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: Bryan Whitehead <Bryan.Whitehead@microchip.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									945fe45759
								
							
						
					
					
						commit
						75a1ccfe6c
					
				| @ -252,13 +252,21 @@ enum rgmii_rx_clock_delay { | |||||||
| #define MSCC_PHY_TR_LSB			  17 | #define MSCC_PHY_TR_LSB			  17 | ||||||
| #define MSCC_PHY_TR_MSB			  18 | #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_VSC8514			  0x00070670 | ||||||
| #define PHY_ID_VSC8530			  0x00070560 | #define PHY_ID_VSC8530			  0x00070560 | ||||||
| #define PHY_ID_VSC8531			  0x00070570 | #define PHY_ID_VSC8531			  0x00070570 | ||||||
| #define PHY_ID_VSC8540			  0x00070760 | #define PHY_ID_VSC8540			  0x00070760 | ||||||
| #define PHY_ID_VSC8541			  0x00070770 | #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_VSC8574			  0x000704a0 | ||||||
|  | #define PHY_ID_VSC8575			  0x000707d0 | ||||||
|  | #define PHY_ID_VSC8582			  0x000707b0 | ||||||
| #define PHY_ID_VSC8584			  0x000707c0 | #define PHY_ID_VSC8584			  0x000707c0 | ||||||
| 
 | 
 | ||||||
| #define MSCC_VDDMAC_1500		  1500 | #define MSCC_VDDMAC_1500		  1500 | ||||||
| @ -1595,6 +1603,9 @@ static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed) | |||||||
| 		else | 		else | ||||||
| 			addr = vsc8531->base_addr + i; | 			addr = vsc8531->base_addr + i; | ||||||
| 
 | 
 | ||||||
|  | 		if (!map[addr]) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		phy = container_of(map[addr], struct phy_device, mdio); | 		phy = container_of(map[addr], struct phy_device, mdio); | ||||||
| 
 | 
 | ||||||
| 		if ((phy->phy_id & phydev->drv->phy_id_mask) != | 		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. | 	 * in this pre-init function. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { | 	if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { | ||||||
| 		if ((phydev->phy_id & phydev->drv->phy_id_mask) == | 		/* The following switch statement assumes that the lowest
 | ||||||
| 		    (PHY_ID_VSC8574 & phydev->drv->phy_id_mask)) | 		 * 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); | 			ret = vsc8574_config_pre_init(phydev); | ||||||
| 		else if ((phydev->phy_id & phydev->drv->phy_id_mask) == | 			break; | ||||||
| 			 (PHY_ID_VSC8584 & phydev->drv->phy_id_mask)) | 		case PHY_ID_VSC856X: | ||||||
|  | 		case PHY_ID_VSC8575: | ||||||
|  | 		case PHY_ID_VSC8582: | ||||||
|  | 		case PHY_ID_VSC8584: | ||||||
| 			ret = vsc8584_config_pre_init(phydev); | 			ret = vsc8584_config_pre_init(phydev); | ||||||
| 		else | 			break; | ||||||
|  | 		default: | ||||||
| 			ret = -EINVAL; | 			ret = -EINVAL; | ||||||
|  | 			break; | ||||||
|  | 		}; | ||||||
| 
 | 
 | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			goto err; | 			goto err; | ||||||
| @ -2321,6 +2347,32 @@ static int vsc85xx_probe(struct phy_device *phydev) | |||||||
| 
 | 
 | ||||||
| /* Microsemi VSC85xx PHYs */ | /* Microsemi VSC85xx PHYs */ | ||||||
| static struct phy_driver vsc85xx_driver[] = { | 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, | 	.phy_id		= PHY_ID_VSC8514, | ||||||
| 	.name		= "Microsemi GE VSC8514 SyncE", | 	.name		= "Microsemi GE VSC8514 SyncE", | ||||||
| @ -2444,6 +2496,82 @@ static struct phy_driver vsc85xx_driver[] = { | |||||||
| 	.get_strings    = &vsc85xx_get_strings, | 	.get_strings    = &vsc85xx_get_strings, | ||||||
| 	.get_stats      = &vsc85xx_get_stats, | 	.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, | 	.phy_id		= PHY_ID_VSC8574, | ||||||
| 	.name		= "Microsemi GE VSC8574 SyncE", | 	.name		= "Microsemi GE VSC8574 SyncE", | ||||||
| @ -2470,6 +2598,54 @@ static struct phy_driver vsc85xx_driver[] = { | |||||||
| 	.get_strings    = &vsc85xx_get_strings, | 	.get_strings    = &vsc85xx_get_strings, | ||||||
| 	.get_stats      = &vsc85xx_get_stats, | 	.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, | 	.phy_id		= PHY_ID_VSC8584, | ||||||
| 	.name		= "Microsemi GE VSC8584 SyncE", | 	.name		= "Microsemi GE VSC8584 SyncE", | ||||||
| @ -2500,12 +2676,18 @@ static struct phy_driver vsc85xx_driver[] = { | |||||||
| module_phy_driver(vsc85xx_driver); | module_phy_driver(vsc85xx_driver); | ||||||
| 
 | 
 | ||||||
| static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { | static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { | ||||||
|  | 	{ PHY_ID_VSC8504, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8514, 0xfffffff0, }, | 	{ PHY_ID_VSC8514, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8530, 0xfffffff0, }, | 	{ PHY_ID_VSC8530, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8531, 0xfffffff0, }, | 	{ PHY_ID_VSC8531, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8540, 0xfffffff0, }, | 	{ PHY_ID_VSC8540, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8541, 0xfffffff0, }, | 	{ PHY_ID_VSC8541, 0xfffffff0, }, | ||||||
|  | 	{ PHY_ID_VSC8552, 0xfffffff0, }, | ||||||
|  | 	{ PHY_ID_VSC856X, 0xfffffff0, }, | ||||||
|  | 	{ PHY_ID_VSC8572, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8574, 0xfffffff0, }, | 	{ PHY_ID_VSC8574, 0xfffffff0, }, | ||||||
|  | 	{ PHY_ID_VSC8575, 0xfffffff0, }, | ||||||
|  | 	{ PHY_ID_VSC8582, 0xfffffff0, }, | ||||||
| 	{ PHY_ID_VSC8584, 0xfffffff0, }, | 	{ PHY_ID_VSC8584, 0xfffffff0, }, | ||||||
| 	{ } | 	{ } | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user