mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: phy: Add downshift get/set support in Microsemi PHYs driver
Implements the phy tunable function pointers and implement downshift functionality for MSCC PHYs. Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Allan W. Nielsen <allan.nielsen@microsemi.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									65feddd5b9
								
							
						
					
					
						commit
						310d9ad57a
					
				
					 1 changed files with 100 additions and 0 deletions
				
			
		| 
						 | 
					@ -46,8 +46,15 @@ enum rgmii_rx_clock_delay {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSCC_EXT_PAGE_ACCESS		  31
 | 
					#define MSCC_EXT_PAGE_ACCESS		  31
 | 
				
			||||||
#define MSCC_PHY_PAGE_STANDARD		  0x0000 /* Standard registers */
 | 
					#define MSCC_PHY_PAGE_STANDARD		  0x0000 /* Standard registers */
 | 
				
			||||||
 | 
					#define MSCC_PHY_PAGE_EXTENDED		  0x0001 /* Extended registers */
 | 
				
			||||||
#define MSCC_PHY_PAGE_EXTENDED_2	  0x0002 /* Extended reg - page 2 */
 | 
					#define MSCC_PHY_PAGE_EXTENDED_2	  0x0002 /* Extended reg - page 2 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extended Page 1 Registers */
 | 
				
			||||||
 | 
					#define MSCC_PHY_ACTIPHY_CNTL		  20
 | 
				
			||||||
 | 
					#define DOWNSHIFT_CNTL_MASK		  0x001C
 | 
				
			||||||
 | 
					#define DOWNSHIFT_EN			  0x0010
 | 
				
			||||||
 | 
					#define DOWNSHIFT_CNTL_POS		  2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Extended Page 2 Registers */
 | 
					/* Extended Page 2 Registers */
 | 
				
			||||||
#define MSCC_PHY_RGMII_CNTL		  20
 | 
					#define MSCC_PHY_RGMII_CNTL		  20
 | 
				
			||||||
#define RGMII_RX_CLK_DELAY_MASK		  0x0070
 | 
					#define RGMII_RX_CLK_DELAY_MASK		  0x0070
 | 
				
			||||||
| 
						 | 
					@ -75,6 +82,8 @@ enum rgmii_rx_clock_delay {
 | 
				
			||||||
#define MSCC_VDDMAC_2500		  2500
 | 
					#define MSCC_VDDMAC_2500		  2500
 | 
				
			||||||
#define MSCC_VDDMAC_3300		  3300
 | 
					#define MSCC_VDDMAC_3300		  3300
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DOWNSHIFT_COUNT_MAX		  5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct vsc8531_private {
 | 
					struct vsc8531_private {
 | 
				
			||||||
	int rate_magic;
 | 
						int rate_magic;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -101,6 +110,66 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						u16 reg_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&phydev->lock);
 | 
				
			||||||
 | 
						rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
 | 
				
			||||||
 | 
						if (rc != 0)
 | 
				
			||||||
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
 | 
				
			||||||
 | 
						reg_val &= DOWNSHIFT_CNTL_MASK;
 | 
				
			||||||
 | 
						if (!(reg_val & DOWNSHIFT_EN))
 | 
				
			||||||
 | 
							*count = DOWNSHIFT_DEV_DISABLE;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
 | 
				
			||||||
 | 
						rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_unlock:
 | 
				
			||||||
 | 
						mutex_unlock(&phydev->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						u16 reg_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
 | 
				
			||||||
 | 
							/* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
 | 
				
			||||||
 | 
							count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
 | 
				
			||||||
 | 
						} else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
 | 
				
			||||||
 | 
							phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
 | 
				
			||||||
 | 
							return -ERANGE;
 | 
				
			||||||
 | 
						} else if (count) {
 | 
				
			||||||
 | 
							/* Downshift count is either 2,3,4 or 5 */
 | 
				
			||||||
 | 
							count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&phydev->lock);
 | 
				
			||||||
 | 
						rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
 | 
				
			||||||
 | 
						if (rc != 0)
 | 
				
			||||||
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
 | 
				
			||||||
 | 
						reg_val &= ~(DOWNSHIFT_CNTL_MASK);
 | 
				
			||||||
 | 
						reg_val |= count;
 | 
				
			||||||
 | 
						rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val);
 | 
				
			||||||
 | 
						if (rc != 0)
 | 
				
			||||||
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_unlock:
 | 
				
			||||||
 | 
						mutex_unlock(&phydev->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vsc85xx_wol_set(struct phy_device *phydev,
 | 
					static int vsc85xx_wol_set(struct phy_device *phydev,
 | 
				
			||||||
			   struct ethtool_wolinfo *wol)
 | 
								   struct ethtool_wolinfo *wol)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -329,6 +398,29 @@ static int vsc85xx_default_config(struct phy_device *phydev)
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vsc85xx_get_tunable(struct phy_device *phydev,
 | 
				
			||||||
 | 
								       struct ethtool_tunable *tuna, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (tuna->id) {
 | 
				
			||||||
 | 
						case ETHTOOL_PHY_DOWNSHIFT:
 | 
				
			||||||
 | 
							return vsc85xx_downshift_get(phydev, (u8 *)data);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vsc85xx_set_tunable(struct phy_device *phydev,
 | 
				
			||||||
 | 
								       struct ethtool_tunable *tuna,
 | 
				
			||||||
 | 
								       const void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (tuna->id) {
 | 
				
			||||||
 | 
						case ETHTOOL_PHY_DOWNSHIFT:
 | 
				
			||||||
 | 
							return vsc85xx_downshift_set(phydev, *(u8 *)data);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vsc85xx_config_init(struct phy_device *phydev)
 | 
					static int vsc85xx_config_init(struct phy_device *phydev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
| 
						 | 
					@ -418,6 +510,8 @@ static struct phy_driver vsc85xx_driver[] = {
 | 
				
			||||||
	.probe		= &vsc85xx_probe,
 | 
						.probe		= &vsc85xx_probe,
 | 
				
			||||||
	.set_wol	= &vsc85xx_wol_set,
 | 
						.set_wol	= &vsc85xx_wol_set,
 | 
				
			||||||
	.get_wol	= &vsc85xx_wol_get,
 | 
						.get_wol	= &vsc85xx_wol_get,
 | 
				
			||||||
 | 
						.get_tunable	= &vsc85xx_get_tunable,
 | 
				
			||||||
 | 
						.set_tunable	= &vsc85xx_set_tunable,
 | 
				
			||||||
},
 | 
					},
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	.phy_id		= PHY_ID_VSC8531,
 | 
						.phy_id		= PHY_ID_VSC8531,
 | 
				
			||||||
| 
						 | 
					@ -437,6 +531,8 @@ static struct phy_driver vsc85xx_driver[] = {
 | 
				
			||||||
	.probe		= &vsc85xx_probe,
 | 
						.probe		= &vsc85xx_probe,
 | 
				
			||||||
	.set_wol	= &vsc85xx_wol_set,
 | 
						.set_wol	= &vsc85xx_wol_set,
 | 
				
			||||||
	.get_wol	= &vsc85xx_wol_get,
 | 
						.get_wol	= &vsc85xx_wol_get,
 | 
				
			||||||
 | 
						.get_tunable	= &vsc85xx_get_tunable,
 | 
				
			||||||
 | 
						.set_tunable	= &vsc85xx_set_tunable,
 | 
				
			||||||
},
 | 
					},
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	.phy_id		= PHY_ID_VSC8540,
 | 
						.phy_id		= PHY_ID_VSC8540,
 | 
				
			||||||
| 
						 | 
					@ -456,6 +552,8 @@ static struct phy_driver vsc85xx_driver[] = {
 | 
				
			||||||
	.probe		= &vsc85xx_probe,
 | 
						.probe		= &vsc85xx_probe,
 | 
				
			||||||
	.set_wol	= &vsc85xx_wol_set,
 | 
						.set_wol	= &vsc85xx_wol_set,
 | 
				
			||||||
	.get_wol	= &vsc85xx_wol_get,
 | 
						.get_wol	= &vsc85xx_wol_get,
 | 
				
			||||||
 | 
						.get_tunable	= &vsc85xx_get_tunable,
 | 
				
			||||||
 | 
						.set_tunable	= &vsc85xx_set_tunable,
 | 
				
			||||||
},
 | 
					},
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	.phy_id		= PHY_ID_VSC8541,
 | 
						.phy_id		= PHY_ID_VSC8541,
 | 
				
			||||||
| 
						 | 
					@ -475,6 +573,8 @@ static struct phy_driver vsc85xx_driver[] = {
 | 
				
			||||||
	.probe		= &vsc85xx_probe,
 | 
						.probe		= &vsc85xx_probe,
 | 
				
			||||||
	.set_wol	= &vsc85xx_wol_set,
 | 
						.set_wol	= &vsc85xx_wol_set,
 | 
				
			||||||
	.get_wol	= &vsc85xx_wol_get,
 | 
						.get_wol	= &vsc85xx_wol_get,
 | 
				
			||||||
 | 
						.get_tunable	= &vsc85xx_get_tunable,
 | 
				
			||||||
 | 
						.set_tunable	= &vsc85xx_set_tunable,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue