Commit 75a1ccfe authored by Bryan Whitehead's avatar Bryan Whitehead Committed by David S. Miller
Browse files

mscc.c: Add support for additional VSC PHYs



Add support for the following VSC PHYs
	VSC8504, VSC8552, VSC8572
	VSC8562, VSC8564, VSC8575, VSC8582

Updates for v2:
	Checked for NULL on input to container_of
	Changed a large if else series to a switch statement.
	Added a WARN_ON to make sure lowest nibble of mask is 0

Signed-off-by: default avatarBryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 945fe457
Loading
Loading
Loading
Loading
+188 −6
Original line number Diff line number Diff line
@@ -252,13 +252,21 @@ enum rgmii_rx_clock_delay {
#define MSCC_PHY_TR_LSB			  17
#define MSCC_PHY_TR_MSB			  18

/* Microsemi PHY ID's */
/* Microsemi PHY ID's
 *   Code assumes lowest nibble is 0
 */
#define PHY_ID_VSC8504			  0x000704c0
#define PHY_ID_VSC8514			  0x00070670
#define PHY_ID_VSC8530			  0x00070560
#define PHY_ID_VSC8531			  0x00070570
#define PHY_ID_VSC8540			  0x00070760
#define PHY_ID_VSC8541			  0x00070770
#define PHY_ID_VSC8552			  0x000704e0
#define PHY_ID_VSC856X			  0x000707e0
#define PHY_ID_VSC8572			  0x000704d0
#define PHY_ID_VSC8574			  0x000704a0
#define PHY_ID_VSC8575			  0x000707d0
#define PHY_ID_VSC8582			  0x000707b0
#define PHY_ID_VSC8584			  0x000707c0

#define MSCC_VDDMAC_1500		  1500
@@ -1595,6 +1603,9 @@ static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed)
		else
			addr = vsc8531->base_addr + i;

		if (!map[addr])
			continue;

		phy = container_of(map[addr], struct phy_device, mdio);

		if ((phy->phy_id & phydev->drv->phy_id_mask) !=
@@ -1647,14 +1658,29 @@ static int vsc8584_config_init(struct phy_device *phydev)
	 * in this pre-init function.
	 */
	if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
		if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
		    (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
		/* The following switch statement assumes that the lowest
		 * nibble of the phy_id_mask is always 0. This works because
		 * the lowest nibble of the PHY_ID's below are also 0.
		 */
		WARN_ON(phydev->drv->phy_id_mask & 0xf);

		switch (phydev->phy_id & phydev->drv->phy_id_mask) {
		case PHY_ID_VSC8504:
		case PHY_ID_VSC8552:
		case PHY_ID_VSC8572:
		case PHY_ID_VSC8574:
			ret = vsc8574_config_pre_init(phydev);
		else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
			 (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
			break;
		case PHY_ID_VSC856X:
		case PHY_ID_VSC8575:
		case PHY_ID_VSC8582:
		case PHY_ID_VSC8584:
			ret = vsc8584_config_pre_init(phydev);
		else
			break;
		default:
			ret = -EINVAL;
			break;
		};

		if (ret)
			goto err;
@@ -2321,6 +2347,32 @@ static int vsc85xx_probe(struct phy_device *phydev)

/* Microsemi VSC85xx PHYs */
static struct phy_driver vsc85xx_driver[] = {
{
	.phy_id		= PHY_ID_VSC8504,
	.name		= "Microsemi GE VSC8504 SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8574_probe,
	.set_wol	= &vsc85xx_wol_set,
	.get_wol	= &vsc85xx_wol_get,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8514,
	.name		= "Microsemi GE VSC8514 SyncE",
@@ -2444,6 +2496,82 @@ static struct phy_driver vsc85xx_driver[] = {
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8552,
	.name		= "Microsemi GE VSC8552 SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8574_probe,
	.set_wol	= &vsc85xx_wol_set,
	.get_wol	= &vsc85xx_wol_get,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC856X,
	.name		= "Microsemi GE VSC856X SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8584_probe,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8572,
	.name		= "Microsemi GE VSC8572 SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8574_probe,
	.set_wol	= &vsc85xx_wol_set,
	.get_wol	= &vsc85xx_wol_get,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8574,
	.name		= "Microsemi GE VSC8574 SyncE",
@@ -2470,6 +2598,54 @@ static struct phy_driver vsc85xx_driver[] = {
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8575,
	.name		= "Microsemi GE VSC8575 SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8584_probe,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8582,
	.name		= "Microsemi GE VSC8582 SyncE",
	.phy_id_mask	= 0xfffffff0,
	/* PHY_GBIT_FEATURES */
	.soft_reset	= &genphy_soft_reset,
	.config_init    = &vsc8584_config_init,
	.config_aneg    = &vsc85xx_config_aneg,
	.aneg_done	= &genphy_aneg_done,
	.read_status	= &vsc85xx_read_status,
	.ack_interrupt  = &vsc85xx_ack_interrupt,
	.config_intr    = &vsc85xx_config_intr,
	.did_interrupt  = &vsc8584_did_interrupt,
	.suspend	= &genphy_suspend,
	.resume		= &genphy_resume,
	.probe		= &vsc8584_probe,
	.get_tunable	= &vsc85xx_get_tunable,
	.set_tunable	= &vsc85xx_set_tunable,
	.read_page	= &vsc85xx_phy_read_page,
	.write_page	= &vsc85xx_phy_write_page,
	.get_sset_count = &vsc85xx_get_sset_count,
	.get_strings    = &vsc85xx_get_strings,
	.get_stats      = &vsc85xx_get_stats,
},
{
	.phy_id		= PHY_ID_VSC8584,
	.name		= "Microsemi GE VSC8584 SyncE",
@@ -2500,12 +2676,18 @@ static struct phy_driver vsc85xx_driver[] = {
module_phy_driver(vsc85xx_driver);

static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
	{ PHY_ID_VSC8504, 0xfffffff0, },
	{ PHY_ID_VSC8514, 0xfffffff0, },
	{ PHY_ID_VSC8530, 0xfffffff0, },
	{ PHY_ID_VSC8531, 0xfffffff0, },
	{ PHY_ID_VSC8540, 0xfffffff0, },
	{ PHY_ID_VSC8541, 0xfffffff0, },
	{ PHY_ID_VSC8552, 0xfffffff0, },
	{ PHY_ID_VSC856X, 0xfffffff0, },
	{ PHY_ID_VSC8572, 0xfffffff0, },
	{ PHY_ID_VSC8574, 0xfffffff0, },
	{ PHY_ID_VSC8575, 0xfffffff0, },
	{ PHY_ID_VSC8582, 0xfffffff0, },
	{ PHY_ID_VSC8584, 0xfffffff0, },
	{ }
};