diff options
Diffstat (limited to 'drivers/net/phy')
| -rw-r--r-- | drivers/net/phy/Kconfig | 35 | ||||
| -rw-r--r-- | drivers/net/phy/Makefile | 3 | ||||
| -rw-r--r-- | drivers/net/phy/at803x.c | 2 | ||||
| -rw-r--r-- | drivers/net/phy/broadcom.c | 6 | ||||
| -rw-r--r-- | drivers/net/phy/cortina.c | 4 | ||||
| -rw-r--r-- | drivers/net/phy/dp83640_reg.h | 1 | ||||
| -rw-r--r-- | drivers/net/phy/dp83822.c | 344 | ||||
| -rw-r--r-- | drivers/net/phy/dp83848.c | 3 | ||||
| -rw-r--r-- | drivers/net/phy/marvell.c | 8 | ||||
| -rw-r--r-- | drivers/net/phy/marvell10g.c | 5 | ||||
| -rw-r--r-- | drivers/net/phy/mdio-boardinfo.h | 1 | ||||
| -rw-r--r-- | drivers/net/phy/phy.c | 3 | ||||
| -rw-r--r-- | drivers/net/phy/phy_device.c | 2 | ||||
| -rw-r--r-- | drivers/net/phy/phy_led_triggers.c | 63 | ||||
| -rw-r--r-- | drivers/net/phy/phylink.c | 16 | ||||
| -rw-r--r-- | drivers/net/phy/realtek.c | 56 | ||||
| -rw-r--r-- | drivers/net/phy/sfp-bus.c | 11 | ||||
| -rw-r--r-- | drivers/net/phy/sfp.c | 29 | ||||
| -rw-r--r-- | drivers/net/phy/swphy.h | 1 | ||||
| -rw-r--r-- | drivers/net/phy/uPD60620.c | 109 | ||||
| -rw-r--r-- | drivers/net/phy/xilinx_gmii2rgmii.c | 2 | 
21 files changed, 632 insertions, 72 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a9d16a3af514..bdfbabb86ee0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -160,15 +160,6 @@ config MDIO_XGENE  endif -menuconfig PHYLIB -	tristate "PHY Device support and infrastructure" -	depends on NETDEVICES -	select MDIO_DEVICE -	help -	  Ethernet controllers are usually attached to PHY -	  devices.  This option provides infrastructure for -	  managing PHY devices. -  config PHYLINK  	tristate  	depends on NETDEVICES @@ -179,6 +170,15 @@ config PHYLINK  	  configuration links, PHYs, and Serdes links with MAC level  	  autonegotiation modes. +menuconfig PHYLIB +	tristate "PHY Device support and infrastructure" +	depends on NETDEVICES +	select MDIO_DEVICE +	help +	  Ethernet controllers are usually attached to PHY +	  devices.  This option provides infrastructure for +	  managing PHY devices. +  if PHYLIB  config SWPHY @@ -191,11 +191,14 @@ config LED_TRIGGER_PHY  	  Adds support for a set of LED trigger events per-PHY.  Link  	  state change will trigger the events, for consumption by an  	  LED class driver.  There are triggers for each link speed currently -	  supported by the phy, and are of the form: +	  supported by the PHY and also a one common "link" trigger as a +	  logical-or of all the link speed ones. +	  All these triggers are named according to the following pattern:  	      <mii bus id>:<phy>:<speed>  	  Where speed is in the form: -		<Speed in megabits>Mbps or <Speed in gigabits>Gbps +		<Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link +		for any speed known to the PHY.  comment "MII PHY device drivers" @@ -277,6 +280,11 @@ config DAVICOM_PHY  	---help---  	  Currently supports dm9161e and dm9131 +config DP83822_PHY +	tristate "Texas Instruments DP83822 PHY" +	---help--- +	  Supports the DP83822 PHY. +  config DP83848_PHY  	tristate "Texas Instruments DP83848 PHY"  	---help--- @@ -366,6 +374,11 @@ config REALTEK_PHY  	---help---  	  Supports the Realtek 821x PHY. +config RENESAS_PHY +	tristate "Driver for Renesas PHYs" +	---help--- +	  Supports the Renesas PHYs uPD60620 and uPD60620A. +  config ROCKCHIP_PHY          tristate "Driver for Rockchip Ethernet PHYs"          ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 416df92fbf4f..01acbcb2c798 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  # Makefile for Linux PHY drivers and MDIO bus drivers  libphy-y			:= phy.o phy-c45.o phy-core.o phy_device.o @@ -55,6 +56,7 @@ obj-$(CONFIG_CICADA_PHY)	+= cicada.o  obj-$(CONFIG_CORTINA_PHY)	+= cortina.o  obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o  obj-$(CONFIG_DP83640_PHY)	+= dp83640.o +obj-$(CONFIG_DP83822_PHY)	+= dp83822.o  obj-$(CONFIG_DP83848_PHY)	+= dp83848.o  obj-$(CONFIG_DP83867_PHY)	+= dp83867.o  obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o @@ -72,6 +74,7 @@ obj-$(CONFIG_MICROSEMI_PHY)	+= mscc.o  obj-$(CONFIG_NATIONAL_PHY)	+= national.o  obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o  obj-$(CONFIG_REALTEK_PHY)	+= realtek.o +obj-$(CONFIG_RENESAS_PHY)	+= uPD60620.o  obj-$(CONFIG_ROCKCHIP_PHY)	+= rockchip.o  obj-$(CONFIG_SMSC_PHY)		+= smsc.o  obj-$(CONFIG_STE10XP)		+= ste10Xp.o diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index c1e52b9dc58d..5f93e6add563 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -167,7 +167,7 @@ static int at803x_set_wol(struct phy_device *phydev,  		mac = (const u8 *) ndev->dev_addr;  		if (!is_valid_ether_addr(mac)) -			return -EFAULT; +			return -EINVAL;  		for (i = 0; i < 3; i++) {  			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 1e9ad30a35c8..d7ed69deabfb 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -43,6 +43,12 @@ static int bcm54210e_config_init(struct phy_device *phydev)  	val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;  	bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); +	if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { +		val = phy_read(phydev, MII_CTRL1000); +		val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; +		phy_write(phydev, MII_CTRL1000, val); +	} +  	return 0;  } diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index 72f4228a63bb..9442db221834 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -116,3 +116,7 @@ static struct mdio_device_id __maybe_unused cortina_tbl[] = {  };  MODULE_DEVICE_TABLE(mdio, cortina_tbl); + +MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver"); +MODULE_AUTHOR("NXP"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h index e7fe41117003..21aa24c741b9 100644 --- a/drivers/net/phy/dp83640_reg.h +++ b/drivers/net/phy/dp83640_reg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  /* dp83640_reg.h   * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011   */ diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c new file mode 100644 index 000000000000..14335d14e9e4 --- /dev/null +++ b/drivers/net/phy/dp83822.c @@ -0,0 +1,344 @@ +/* + * Driver for the Texas Instruments DP83822 PHY + * + * Copyright (C) 2017 Texas Instruments Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/ethtool.h> +#include <linux/etherdevice.h> +#include <linux/kernel.h> +#include <linux/mii.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy.h> +#include <linux/netdevice.h> + +#define DP83822_PHY_ID	        0x2000a240 +#define DP83822_DEVADDR		0x1f + +#define MII_DP83822_PHYSCR	0x11 +#define MII_DP83822_MISR1	0x12 +#define MII_DP83822_MISR2	0x13 +#define MII_DP83822_RESET_CTRL	0x1f + +#define DP83822_HW_RESET	BIT(15) +#define DP83822_SW_RESET	BIT(14) + +/* PHYSCR Register Fields */ +#define DP83822_PHYSCR_INT_OE		BIT(0) /* Interrupt Output Enable */ +#define DP83822_PHYSCR_INTEN		BIT(1) /* Interrupt Enable */ + +/* MISR1 bits */ +#define DP83822_RX_ERR_HF_INT_EN	BIT(0) +#define DP83822_FALSE_CARRIER_HF_INT_EN	BIT(1) +#define DP83822_ANEG_COMPLETE_INT_EN	BIT(2) +#define DP83822_DUP_MODE_CHANGE_INT_EN	BIT(3) +#define DP83822_SPEED_CHANGED_INT_EN	BIT(4) +#define DP83822_LINK_STAT_INT_EN	BIT(5) +#define DP83822_ENERGY_DET_INT_EN	BIT(6) +#define DP83822_LINK_QUAL_INT_EN	BIT(7) + +/* MISR2 bits */ +#define DP83822_JABBER_DET_INT_EN	BIT(0) +#define DP83822_WOL_PKT_INT_EN		BIT(1) +#define DP83822_SLEEP_MODE_INT_EN	BIT(2) +#define DP83822_MDI_XOVER_INT_EN	BIT(3) +#define DP83822_LB_FIFO_INT_EN		BIT(4) +#define DP83822_PAGE_RX_INT_EN		BIT(5) +#define DP83822_ANEG_ERR_INT_EN		BIT(6) +#define DP83822_EEE_ERROR_CHANGE_INT_EN	BIT(7) + +/* INT_STAT1 bits */ +#define DP83822_WOL_INT_EN	BIT(4) +#define DP83822_WOL_INT_STAT	BIT(12) + +#define MII_DP83822_RXSOP1	0x04a5 +#define	MII_DP83822_RXSOP2	0x04a6 +#define	MII_DP83822_RXSOP3	0x04a7 + +/* WoL Registers */ +#define	MII_DP83822_WOL_CFG	0x04a0 +#define	MII_DP83822_WOL_STAT	0x04a1 +#define	MII_DP83822_WOL_DA1	0x04a2 +#define	MII_DP83822_WOL_DA2	0x04a3 +#define	MII_DP83822_WOL_DA3	0x04a4 + +/* WoL bits */ +#define DP83822_WOL_MAGIC_EN	BIT(0) +#define DP83822_WOL_SECURE_ON	BIT(5) +#define DP83822_WOL_EN		BIT(7) +#define DP83822_WOL_INDICATION_SEL BIT(8) +#define DP83822_WOL_CLR_INDICATION BIT(11) + +static int dp83822_ack_interrupt(struct phy_device *phydev) +{ +	int err; + +	err = phy_read(phydev, MII_DP83822_MISR1); +	if (err < 0) +		return err; + +	err = phy_read(phydev, MII_DP83822_MISR2); +	if (err < 0) +		return err; + +	return 0; +} + +static int dp83822_set_wol(struct phy_device *phydev, +			   struct ethtool_wolinfo *wol) +{ +	struct net_device *ndev = phydev->attached_dev; +	u16 value; +	const u8 *mac; + +	if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { +		mac = (const u8 *)ndev->dev_addr; + +		if (!is_valid_ether_addr(mac)) +			return -EINVAL; + +		/* MAC addresses start with byte 5, but stored in mac[0]. +		 * 822 PHYs store bytes 4|5, 2|3, 0|1 +		 */ +		phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1, +			      (mac[1] << 8) | mac[0]); +		phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2, +			      (mac[3] << 8) | mac[2]); +		phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3, +			      (mac[5] << 8) | mac[4]); + +		value = phy_read_mmd(phydev, DP83822_DEVADDR, +				     MII_DP83822_WOL_CFG); +		if (wol->wolopts & WAKE_MAGIC) +			value |= DP83822_WOL_MAGIC_EN; +		else +			value &= ~DP83822_WOL_MAGIC_EN; + +		if (wol->wolopts & WAKE_MAGICSECURE) { +			phy_write_mmd(phydev, DP83822_DEVADDR, +				      MII_DP83822_RXSOP1, +				      (wol->sopass[1] << 8) | wol->sopass[0]); +			phy_write_mmd(phydev, DP83822_DEVADDR, +				      MII_DP83822_RXSOP2, +				      (wol->sopass[3] << 8) | wol->sopass[2]); +			phy_write_mmd(phydev, DP83822_DEVADDR, +				      MII_DP83822_RXSOP3, +				      (wol->sopass[5] << 8) | wol->sopass[4]); +			value |= DP83822_WOL_SECURE_ON; +		} else { +			value &= ~DP83822_WOL_SECURE_ON; +		} + +		value |= (DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL | +			  DP83822_WOL_CLR_INDICATION); +		phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, +			      value); +	} else { +		value = phy_read_mmd(phydev, DP83822_DEVADDR, +				     MII_DP83822_WOL_CFG); +		value &= ~DP83822_WOL_EN; +		phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, +			      value); +	} + +	return 0; +} + +static void dp83822_get_wol(struct phy_device *phydev, +			    struct ethtool_wolinfo *wol) +{ +	int value; +	u16 sopass_val; + +	wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE); +	wol->wolopts = 0; + +	value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); + +	if (value & DP83822_WOL_MAGIC_EN) +		wol->wolopts |= WAKE_MAGIC; + +	if (value & DP83822_WOL_SECURE_ON) { +		sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, +					  MII_DP83822_RXSOP1); +		wol->sopass[0] = (sopass_val & 0xff); +		wol->sopass[1] = (sopass_val >> 8); + +		sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, +					  MII_DP83822_RXSOP2); +		wol->sopass[2] = (sopass_val & 0xff); +		wol->sopass[3] = (sopass_val >> 8); + +		sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, +					  MII_DP83822_RXSOP3); +		wol->sopass[4] = (sopass_val & 0xff); +		wol->sopass[5] = (sopass_val >> 8); + +		wol->wolopts |= WAKE_MAGICSECURE; +	} + +	/* WoL is not enabled so set wolopts to 0 */ +	if (!(value & DP83822_WOL_EN)) +		wol->wolopts = 0; +} + +static int dp83822_config_intr(struct phy_device *phydev) +{ +	int misr_status; +	int physcr_status; +	int err; + +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +		misr_status = phy_read(phydev, MII_DP83822_MISR1); +		if (misr_status < 0) +			return misr_status; + +		misr_status |= (DP83822_RX_ERR_HF_INT_EN | +				DP83822_FALSE_CARRIER_HF_INT_EN | +				DP83822_ANEG_COMPLETE_INT_EN | +				DP83822_DUP_MODE_CHANGE_INT_EN | +				DP83822_SPEED_CHANGED_INT_EN | +				DP83822_LINK_STAT_INT_EN | +				DP83822_ENERGY_DET_INT_EN | +				DP83822_LINK_QUAL_INT_EN); + +		err = phy_write(phydev, MII_DP83822_MISR1, misr_status); +		if (err < 0) +			return err; + +		misr_status = phy_read(phydev, MII_DP83822_MISR2); +		if (misr_status < 0) +			return misr_status; + +		misr_status |= (DP83822_JABBER_DET_INT_EN | +				DP83822_WOL_PKT_INT_EN | +				DP83822_SLEEP_MODE_INT_EN | +				DP83822_MDI_XOVER_INT_EN | +				DP83822_LB_FIFO_INT_EN | +				DP83822_PAGE_RX_INT_EN | +				DP83822_ANEG_ERR_INT_EN | +				DP83822_EEE_ERROR_CHANGE_INT_EN); + +		err = phy_write(phydev, MII_DP83822_MISR2, misr_status); +		if (err < 0) +			return err; + +		physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); +		if (physcr_status < 0) +			return physcr_status; + +		physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN; + +	} else { +		err = phy_write(phydev, MII_DP83822_MISR1, 0); +		if (err < 0) +			return err; + +		err = phy_write(phydev, MII_DP83822_MISR1, 0); +		if (err < 0) +			return err; + +		physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); +		if (physcr_status < 0) +			return physcr_status; + +		physcr_status &= ~DP83822_PHYSCR_INTEN; +	} + +	return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status); +} + +static int dp83822_config_init(struct phy_device *phydev) +{ +	int err; +	int value; + +	err = genphy_config_init(phydev); +	if (err < 0) +		return err; + +	value = DP83822_WOL_MAGIC_EN | DP83822_WOL_SECURE_ON | DP83822_WOL_EN; + +	return phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, +	      value); +} + +static int dp83822_phy_reset(struct phy_device *phydev) +{ +	int err; + +	err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET); +	if (err < 0) +		return err; + +	dp83822_config_init(phydev); + +	return 0; +} + +static int dp83822_suspend(struct phy_device *phydev) +{ +	int value; + +	value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); + +	if (!(value & DP83822_WOL_EN)) +		genphy_suspend(phydev); + +	return 0; +} + +static int dp83822_resume(struct phy_device *phydev) +{ +	int value; + +	genphy_resume(phydev); + +	value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); + +	phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value | +		      DP83822_WOL_CLR_INDICATION); + +	return 0; +} + +static struct phy_driver dp83822_driver[] = { +	{ +		.phy_id = DP83822_PHY_ID, +		.phy_id_mask = 0xfffffff0, +		.name = "TI DP83822", +		.features = PHY_BASIC_FEATURES, +		.flags = PHY_HAS_INTERRUPT, +		.config_init = dp83822_config_init, +		.soft_reset = dp83822_phy_reset, +		.get_wol = dp83822_get_wol, +		.set_wol = dp83822_set_wol, +		.ack_interrupt = dp83822_ack_interrupt, +		.config_intr = dp83822_config_intr, +		.config_aneg = genphy_config_aneg, +		.read_status = genphy_read_status, +		.suspend = dp83822_suspend, +		.resume = dp83822_resume, +	 }, +}; +module_phy_driver(dp83822_driver); + +static struct mdio_device_id __maybe_unused dp83822_tbl[] = { +	{ DP83822_PHY_ID, 0xfffffff0 }, +	{ }, +}; +MODULE_DEVICE_TABLE(mdio, dp83822_tbl); + +MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver"); +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index 3de4fe4dda77..3966d43c5146 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -20,7 +20,6 @@  #define TI_DP83620_PHY_ID		0x20005ce0  #define NS_DP83848C_PHY_ID		0x20005c90  #define TLK10X_PHY_ID			0x2000a210 -#define TI_DP83822_PHY_ID		0x2000a240  /* Registers */  #define DP83848_MICR			0x11 /* MII Interrupt Control Register */ @@ -80,7 +79,6 @@ static struct mdio_device_id __maybe_unused dp83848_tbl[] = {  	{ NS_DP83848C_PHY_ID, 0xfffffff0 },  	{ TI_DP83620_PHY_ID, 0xfffffff0 },  	{ TLK10X_PHY_ID, 0xfffffff0 }, -	{ TI_DP83822_PHY_ID, 0xfffffff0 },  	{ }  };  MODULE_DEVICE_TABLE(mdio, dp83848_tbl); @@ -110,7 +108,6 @@ static struct phy_driver dp83848_driver[] = {  	DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"),  	DP83848_PHY_DRIVER(TI_DP83620_PHY_ID, "TI DP83620 10/100 Mbps PHY"),  	DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"), -	DP83848_PHY_DRIVER(TI_DP83822_PHY_ID, "TI DP83822 10/100 Mbps PHY"),  };  module_phy_driver(dp83848_driver); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 15cbcdba618a..4d02b27df044 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -681,9 +681,11 @@ static int m88e1116r_config_init(struct phy_device *phydev)  	if (err < 0)  		return err; -	err = m88e1121_config_aneg_rgmii_delays(phydev); -	if (err < 0) -		return err; +	if (phy_interface_is_rgmii(phydev)) { +		err = m88e1121_config_aneg_rgmii_delays(phydev); +		if (err < 0) +			return err; +	}  	err = genphy_soft_reset(phydev);  	if (err < 0) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index aebc08beceba..21b3f36e023a 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -16,6 +16,7 @@   * link takes priority and the other port is completely locked out.   */  #include <linux/phy.h> +#include <linux/marvell_phy.h>  enum {  	MV_PCS_BASE_T		= 0x0000, @@ -338,7 +339,7 @@ static int mv3310_read_status(struct phy_device *phydev)  static struct phy_driver mv3310_drivers[] = {  	{  		.phy_id		= 0x002b09aa, -		.phy_id_mask	= 0xffffffff, +		.phy_id_mask	= MARVELL_PHY_ID_MASK,  		.name		= "mv88x3310",  		.features	= SUPPORTED_10baseT_Full |  				  SUPPORTED_100baseT_Full | @@ -360,7 +361,7 @@ static struct phy_driver mv3310_drivers[] = {  module_phy_driver(mv3310_drivers);  static struct mdio_device_id __maybe_unused mv3310_tbl[] = { -	{ 0x002b09aa, 0xffffffff }, +	{ 0x002b09aa, MARVELL_PHY_ID_MASK },  	{ },  };  MODULE_DEVICE_TABLE(mdio, mv3310_tbl); diff --git a/drivers/net/phy/mdio-boardinfo.h b/drivers/net/phy/mdio-boardinfo.h index 3a7f143904e8..773bb51399be 100644 --- a/drivers/net/phy/mdio-boardinfo.h +++ b/drivers/net/phy/mdio-boardinfo.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  /*   * mdio-boardinfo.h - board info interface internal to the mdio_bus   * component diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e842d2cd1ee7..2b1e67bc1e73 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -373,7 +373,8 @@ void phy_ethtool_ksettings_get(struct phy_device *phydev,  		cmd->base.port = PORT_BNC;  	else  		cmd->base.port = PORT_MII; - +	cmd->base.transceiver = phy_is_internal(phydev) ? +				XCVR_INTERNAL : XCVR_EXTERNAL;  	cmd->base.phy_address = phydev->mdio.addr;  	cmd->base.autoneg = phydev->autoneg;  	cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8cf0c5901f95..67f25ac29025 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -879,7 +879,7 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)  {  	const char *drv_name = phydev->drv ? phydev->drv->name : "unbound";  	char *irq_str; -	char irq_num[4]; +	char irq_num[8];  	switch(phydev->irq) {  	case PHY_POLL: diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c index 94ca42e630bb..39ecad25b201 100644 --- a/drivers/net/phy/phy_led_triggers.c +++ b/drivers/net/phy/phy_led_triggers.c @@ -27,12 +27,21 @@ static struct phy_led_trigger *phy_speed_to_led_trigger(struct phy_device *phy,  	return NULL;  } +static void phy_led_trigger_no_link(struct phy_device *phy) +{ +	if (phy->last_triggered) { +		led_trigger_event(&phy->last_triggered->trigger, LED_OFF); +		led_trigger_event(&phy->led_link_trigger->trigger, LED_OFF); +		phy->last_triggered = NULL; +	} +} +  void phy_led_trigger_change_speed(struct phy_device *phy)  {  	struct phy_led_trigger *plt;  	if (!phy->link) -		goto out_change_speed; +		return phy_led_trigger_no_link(phy);  	if (phy->speed == 0)  		return; @@ -42,25 +51,28 @@ void phy_led_trigger_change_speed(struct phy_device *phy)  		netdev_alert(phy->attached_dev,  			     "No phy led trigger registered for speed(%d)\n",  			     phy->speed); -		goto out_change_speed; +		return phy_led_trigger_no_link(phy);  	}  	if (plt != phy->last_triggered) { +		if (!phy->last_triggered) +			led_trigger_event(&phy->led_link_trigger->trigger, +					  LED_FULL); +  		led_trigger_event(&phy->last_triggered->trigger, LED_OFF);  		led_trigger_event(&plt->trigger, LED_FULL);  		phy->last_triggered = plt;  	} -	return; - -out_change_speed: -	if (phy->last_triggered) { -		led_trigger_event(&phy->last_triggered->trigger, -				  LED_OFF); -		phy->last_triggered = NULL; -	}  }  EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed); +static void phy_led_trigger_format_name(struct phy_device *phy, char *buf, +					size_t size, char *suffix) +{ +	snprintf(buf, size, PHY_ID_FMT ":%s", +		 phy->mdio.bus->id, phy->mdio.addr, suffix); +} +  static int phy_led_trigger_register(struct phy_device *phy,  				    struct phy_led_trigger *plt,  				    unsigned int speed) @@ -77,8 +89,8 @@ static int phy_led_trigger_register(struct phy_device *phy,  		snprintf(name_suffix, sizeof(name_suffix), "%dGbps",  			 DIV_ROUND_CLOSEST(speed, 1000)); -	snprintf(plt->name, sizeof(plt->name), PHY_ID_FMT ":%s", -		 phy->mdio.bus->id, phy->mdio.addr, name_suffix); +	phy_led_trigger_format_name(phy, plt->name, sizeof(plt->name), +				    name_suffix);  	plt->trigger.name = plt->name;  	return led_trigger_register(&plt->trigger); @@ -99,13 +111,30 @@ int phy_led_triggers_register(struct phy_device *phy)  	if (!phy->phy_num_led_triggers)  		return 0; +	phy->led_link_trigger = devm_kzalloc(&phy->mdio.dev, +					     sizeof(*phy->led_link_trigger), +					     GFP_KERNEL); +	if (!phy->led_link_trigger) { +		err = -ENOMEM; +		goto out_clear; +	} + +	phy_led_trigger_format_name(phy, phy->led_link_trigger->name, +				    sizeof(phy->led_link_trigger->name), +				    "link"); +	phy->led_link_trigger->trigger.name = phy->led_link_trigger->name; + +	err = led_trigger_register(&phy->led_link_trigger->trigger); +	if (err) +		goto out_free_link; +  	phy->phy_led_triggers = devm_kzalloc(&phy->mdio.dev,  					    sizeof(struct phy_led_trigger) *  						   phy->phy_num_led_triggers,  					    GFP_KERNEL);  	if (!phy->phy_led_triggers) {  		err = -ENOMEM; -		goto out_clear; +		goto out_unreg_link;  	}  	for (i = 0; i < phy->phy_num_led_triggers; i++) { @@ -123,6 +152,11 @@ out_unreg:  	while (i--)  		phy_led_trigger_unregister(&phy->phy_led_triggers[i]);  	devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); +out_unreg_link: +	phy_led_trigger_unregister(phy->led_link_trigger); +out_free_link: +	devm_kfree(&phy->mdio.dev, phy->led_link_trigger); +	phy->led_link_trigger = NULL;  out_clear:  	phy->phy_num_led_triggers = 0;  	return err; @@ -135,5 +169,8 @@ void phy_led_triggers_unregister(struct phy_device *phy)  	for (i = 0; i < phy->phy_num_led_triggers; i++)  		phy_led_trigger_unregister(&phy->phy_led_triggers[i]); + +	if (phy->led_link_trigger) +		phy_led_trigger_unregister(phy->led_link_trigger);  }  EXPORT_SYMBOL_GPL(phy_led_triggers_unregister); diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index bcb4755bcd95..e3bbc70372d3 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -357,7 +357,7 @@ static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_stat   *    1     1       0     1     TX   */  static void phylink_resolve_flow(struct phylink *pl, -	struct phylink_link_state *state) +				 struct phylink_link_state *state)  {  	int new_pause = 0; @@ -506,7 +506,8 @@ static int phylink_register_sfp(struct phylink *pl, struct device_node *np)  }  struct phylink *phylink_create(struct net_device *ndev, struct device_node *np, -	phy_interface_t iface, const struct phylink_mac_ops *ops) +			       phy_interface_t iface, +			       const struct phylink_mac_ops *ops)  {  	struct phylink *pl;  	int ret; @@ -566,7 +567,8 @@ void phylink_destroy(struct phylink *pl)  }  EXPORT_SYMBOL_GPL(phylink_destroy); -void phylink_phy_change(struct phy_device *phydev, bool up, bool do_carrier) +static void phylink_phy_change(struct phy_device *phydev, bool up, +			       bool do_carrier)  {  	struct phylink *pl = phydev->phylink; @@ -585,7 +587,7 @@ void phylink_phy_change(struct phy_device *phydev, bool up, bool do_carrier)  	phylink_run_resolve(pl);  	netdev_dbg(pl->netdev, "phy link %s %s/%s/%s\n", up ? "up" : "down", -	           phy_modes(phydev->interface), +		   phy_modes(phydev->interface),  		   phy_speed_to_str(phydev->speed),  		   phy_duplex_to_str(phydev->duplex));  } @@ -823,7 +825,7 @@ static void phylink_get_ksettings(const struct phylink_link_state *state,  }  int phylink_ethtool_ksettings_get(struct phylink *pl, -	struct ethtool_link_ksettings *kset) +				  struct ethtool_link_ksettings *kset)  {  	struct phylink_link_state link_state; @@ -870,7 +872,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,  EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);  int phylink_ethtool_ksettings_set(struct phylink *pl, -	const struct ethtool_link_ksettings *kset) +				  const struct ethtool_link_ksettings *kset)  {  	struct ethtool_link_ksettings our_kset;  	struct phylink_link_state config; @@ -1337,8 +1339,6 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)  }  EXPORT_SYMBOL_GPL(phylink_mii_ioctl); - -  static int phylink_sfp_module_insert(void *upstream,  				     const struct sfp_eeprom_id *id)  { diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 9cbe645e3d89..eda0a6e86918 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -22,17 +22,29 @@  #define RTL821x_INER		0x12  #define RTL821x_INER_INIT	0x6400  #define RTL821x_INSR		0x13 +#define RTL821x_PAGE_SELECT	0x1f  #define RTL8211E_INER_LINK_STATUS 0x400  #define RTL8211F_INER_LINK_STATUS 0x0010  #define RTL8211F_INSR		0x1d -#define RTL8211F_PAGE_SELECT	0x1f  #define RTL8211F_TX_DELAY	0x100 +#define RTL8201F_ISR		0x1e +#define RTL8201F_IER		0x13 +  MODULE_DESCRIPTION("Realtek PHY driver");  MODULE_AUTHOR("Johnson Leung");  MODULE_LICENSE("GPL"); +static int rtl8201_ack_interrupt(struct phy_device *phydev) +{ +	int err; + +	err = phy_read(phydev, RTL8201F_ISR); + +	return (err < 0) ? err : 0; +} +  static int rtl821x_ack_interrupt(struct phy_device *phydev)  {  	int err; @@ -46,14 +58,33 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)  {  	int err; -	phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43); +	phy_write(phydev, RTL821x_PAGE_SELECT, 0xa43);  	err = phy_read(phydev, RTL8211F_INSR);  	/* restore to default page 0 */ -	phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); +	phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);  	return (err < 0) ? err : 0;  } +static int rtl8201_config_intr(struct phy_device *phydev) +{ +	int err; + +	/* switch to page 7 */ +	phy_write(phydev, RTL821x_PAGE_SELECT, 0x7); + +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) +		err = phy_write(phydev, RTL8201F_IER, +				BIT(13) | BIT(12) | BIT(11)); +	else +		err = phy_write(phydev, RTL8201F_IER, 0); + +	/* restore to default page 0 */ +	phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); + +	return err; +} +  static int rtl8211b_config_intr(struct phy_device *phydev)  {  	int err; @@ -84,11 +115,13 @@ static int rtl8211f_config_intr(struct phy_device *phydev)  {  	int err; +	phy_write(phydev, RTL821x_PAGE_SELECT, 0xa42);  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)  		err = phy_write(phydev, RTL821x_INER,  				RTL8211F_INER_LINK_STATUS);  	else  		err = phy_write(phydev, RTL821x_INER, 0); +	phy_write(phydev, RTL821x_PAGE_SELECT, 0);  	return err;  } @@ -102,7 +135,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)  	if (ret < 0)  		return ret; -	phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); +	phy_write(phydev, RTL821x_PAGE_SELECT, 0xd08);  	reg = phy_read(phydev, 0x11);  	/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ @@ -114,7 +147,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)  	phy_write(phydev, 0x11, reg);  	/* restore to default page 0 */ -	phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); +	phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);  	return 0;  } @@ -129,6 +162,18 @@ static struct phy_driver realtek_drvs[] = {  		.config_aneg    = &genphy_config_aneg,  		.read_status    = &genphy_read_status,  	}, { +		.phy_id		= 0x001cc816, +		.name		= "RTL8201F 10/100Mbps Ethernet", +		.phy_id_mask	= 0x001fffff, +		.features	= PHY_BASIC_FEATURES, +		.flags		= PHY_HAS_INTERRUPT, +		.config_aneg	= &genphy_config_aneg, +		.read_status	= &genphy_read_status, +		.ack_interrupt	= &rtl8201_ack_interrupt, +		.config_intr	= &rtl8201_config_intr, +		.suspend	= genphy_suspend, +		.resume		= genphy_resume, +	}, {  		.phy_id		= 0x001cc912,  		.name		= "RTL8211B Gigabit Ethernet",  		.phy_id_mask	= 0x001fffff, @@ -181,6 +226,7 @@ static struct phy_driver realtek_drvs[] = {  module_phy_driver(realtek_drvs);  static struct mdio_device_id __maybe_unused realtek_tbl[] = { +	{ 0x001cc816, 0x001fffff },  	{ 0x001cc912, 0x001fffff },  	{ 0x001cc914, 0x001fffff },  	{ 0x001cc915, 0x001fffff }, diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 5cb5384697ea..8a1b1f4c1b7c 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -26,7 +26,6 @@ struct sfp_bus {  	bool started;  }; -  int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,  		   unsigned long *support)  { @@ -208,7 +207,6 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,  }  EXPORT_SYMBOL_GPL(sfp_parse_support); -  static LIST_HEAD(sfp_buses);  static DEFINE_MUTEX(sfp_mutex); @@ -295,7 +293,6 @@ static void sfp_unregister_bus(struct sfp_bus *bus)  	bus->registered = false;  } -  int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo)  {  	if (!bus->registered) @@ -305,7 +302,7 @@ int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo)  EXPORT_SYMBOL_GPL(sfp_get_module_info);  int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, -	u8 *data) +			  u8 *data)  {  	if (!bus->registered)  		return -ENOIOCTLCMD; @@ -330,8 +327,8 @@ void sfp_upstream_stop(struct sfp_bus *bus)  EXPORT_SYMBOL_GPL(sfp_upstream_stop);  struct sfp_bus *sfp_register_upstream(struct device_node *np, -	struct net_device *ndev, void *upstream, -	const struct sfp_upstream_ops *ops) +				      struct net_device *ndev, void *upstream, +				      const struct sfp_upstream_ops *ops)  {  	struct sfp_bus *bus = sfp_bus_get(np);  	int ret = 0; @@ -368,7 +365,6 @@ void sfp_unregister_upstream(struct sfp_bus *bus)  }  EXPORT_SYMBOL_GPL(sfp_unregister_upstream); -  /* Socket driver entry points */  int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)  { @@ -395,7 +391,6 @@ void sfp_remove_phy(struct sfp_bus *bus)  }  EXPORT_SYMBOL_GPL(sfp_remove_phy); -  void sfp_link_up(struct sfp_bus *bus)  {  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index baee371bf767..e381811e5f11 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1,5 +1,5 @@  #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h>  #include <linux/i2c.h>  #include <linux/interrupt.h>  #include <linux/jiffies.h> @@ -88,15 +88,12 @@ static const enum gpiod_flags gpio_flags[] = {  #define T_PROBE_INIT	msecs_to_jiffies(300)  #define T_PROBE_RETRY	msecs_to_jiffies(100) -/* - * SFP modules appear to always have their PHY configured for bus address +/* SFP modules appear to always have their PHY configured for bus address   * 0x56 (which with mdio-i2c, translates to a PHY address of 22).   */  #define SFP_PHY_ADDR	22 -/* - * Give this long for the PHY to reset. - */ +/* Give this long for the PHY to reset. */  #define T_PHY_RESET_MS	50  static DEFINE_MUTEX(sfp_mutex); @@ -150,10 +147,10 @@ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)  		/* If the module is present, drive the signals */  		if (sfp->gpio[GPIO_TX_DISABLE])  			gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE], -						state & SFP_F_TX_DISABLE); +					       state & SFP_F_TX_DISABLE);  		if (state & SFP_F_RATE_SELECT)  			gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT], -						state & SFP_F_RATE_SELECT); +					       state & SFP_F_RATE_SELECT);  	} else {  		/* Otherwise, let them float to the pull-ups */  		if (sfp->gpio[GPIO_TX_DISABLE]) @@ -164,7 +161,7 @@ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)  }  static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr, -	void *buf, size_t len) +			 void *buf, size_t len)  {  	struct i2c_msg msgs[2];  	int ret; @@ -186,7 +183,7 @@ static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr,  }  static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 addr, void *buf, -	size_t len) +			size_t len)  {  	return sfp__i2c_read(sfp->i2c, a2 ? 0x51 : 0x50, addr, buf, len);  } @@ -220,7 +217,6 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)  	return 0;  } -  /* Interface */  static unsigned int sfp_get_state(struct sfp *sfp)  { @@ -295,7 +291,8 @@ static void sfp_sm_next(struct sfp *sfp, unsigned int state,  	sfp_sm_set_timer(sfp, timeout);  } -static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state, unsigned int timeout) +static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state, +			    unsigned int timeout)  {  	sfp->sm_mod_state = state;  	sfp_sm_set_timer(sfp, timeout); @@ -370,7 +367,8 @@ static void sfp_sm_link_check_los(struct sfp *sfp)  static void sfp_sm_fault(struct sfp *sfp, bool warn)  {  	if (sfp->sm_retries && !--sfp->sm_retries) { -		dev_err(sfp->dev, "module persistently indicates fault, disabling\n"); +		dev_err(sfp->dev, +			"module persistently indicates fault, disabling\n");  		sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0);  	} else {  		if (warn) @@ -461,7 +459,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp)  	memcpy(date, sfp->id.ext.datecode, 8);  	date[8] = '\0'; -	dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", vendor, part, rev, sn, date); +	dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", +		 vendor, part, rev, sn, date);  	/* We only support SFP modules, not the legacy GBIC modules. */  	if (sfp->id.base.phys_id != SFP_PHYS_ID_SFP || @@ -651,7 +650,7 @@ static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)  }  static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, -	u8 *data) +			     u8 *data)  {  	unsigned int first, last, len;  	int ret; diff --git a/drivers/net/phy/swphy.h b/drivers/net/phy/swphy.h index 2f09ac324e18..3668ab8c901a 100644 --- a/drivers/net/phy/swphy.h +++ b/drivers/net/phy/swphy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef SWPHY_H  #define SWPHY_H diff --git a/drivers/net/phy/uPD60620.c b/drivers/net/phy/uPD60620.c new file mode 100644 index 000000000000..96b33475ea5e --- /dev/null +++ b/drivers/net/phy/uPD60620.c @@ -0,0 +1,109 @@ +/* + * Driver for the Renesas PHY uPD60620. + * + * Copyright (C) 2015 Softing Industrial Automation GmbH + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/phy.h> + +#define UPD60620_PHY_ID    0xb8242824 + +/* Extended Registers and values */ +/* PHY Special Control/Status    */ +#define PHY_PHYSCR         0x1F      /* PHY.31 */ +#define PHY_PHYSCR_10MB    0x0004    /* PHY speed = 10mb */ +#define PHY_PHYSCR_100MB   0x0008    /* PHY speed = 100mb */ +#define PHY_PHYSCR_DUPLEX  0x0010    /* PHY Duplex */ + +/* PHY Special Modes */ +#define PHY_SPM            0x12      /* PHY.18 */ + +/* Init PHY */ + +static int upd60620_config_init(struct phy_device *phydev) +{ +	/* Enable support for passive HUBs (could be a strap option) */ +	/* PHYMODE: All speeds, HD in parallel detect */ +	return phy_write(phydev, PHY_SPM, 0x0180 | phydev->mdio.addr); +} + +/* Get PHY status from common registers */ + +static int upd60620_read_status(struct phy_device *phydev) +{ +	int phy_state; + +	/* Read negotiated state */ +	phy_state = phy_read(phydev, MII_BMSR); +	if (phy_state < 0) +		return phy_state; + +	phydev->link = 0; +	phydev->lp_advertising = 0; +	phydev->pause = 0; +	phydev->asym_pause = 0; + +	if (phy_state & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) { +		phy_state = phy_read(phydev, PHY_PHYSCR); +		if (phy_state < 0) +			return phy_state; + +		if (phy_state & (PHY_PHYSCR_10MB | PHY_PHYSCR_100MB)) { +			phydev->link = 1; +			phydev->speed = SPEED_10; +			phydev->duplex = DUPLEX_HALF; + +			if (phy_state & PHY_PHYSCR_100MB) +				phydev->speed = SPEED_100; +			if (phy_state & PHY_PHYSCR_DUPLEX) +				phydev->duplex = DUPLEX_FULL; + +			phy_state = phy_read(phydev, MII_LPA); +			if (phy_state < 0) +				return phy_state; + +			phydev->lp_advertising +				= mii_lpa_to_ethtool_lpa_t(phy_state); + +			if (phydev->duplex == DUPLEX_FULL) { +				if (phy_state & LPA_PAUSE_CAP) +					phydev->pause = 1; +				if (phy_state & LPA_PAUSE_ASYM) +					phydev->asym_pause = 1; +			} +		} +	} +	return 0; +} + +MODULE_DESCRIPTION("Renesas uPD60620 PHY driver"); +MODULE_AUTHOR("Bernd Edlinger <bernd.edlinger@hotmail.de>"); +MODULE_LICENSE("GPL"); + +static struct phy_driver upd60620_driver[1] = { { +	.phy_id         = UPD60620_PHY_ID, +	.phy_id_mask    = 0xfffffffe, +	.name           = "Renesas uPD60620", +	.features       = PHY_BASIC_FEATURES, +	.flags          = 0, +	.config_init    = upd60620_config_init, +	.config_aneg    = genphy_config_aneg, +	.read_status    = upd60620_read_status, +} }; + +module_phy_driver(upd60620_driver); + +static struct mdio_device_id __maybe_unused upd60620_tbl[] = { +	{ UPD60620_PHY_ID, 0xfffffffe }, +	{ } +}; + +MODULE_DEVICE_TABLE(mdio, upd60620_tbl); diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c index d15dd3938ba8..2e5150b0b8d5 100644 --- a/drivers/net/phy/xilinx_gmii2rgmii.c +++ b/drivers/net/phy/xilinx_gmii2rgmii.c @@ -44,7 +44,7 @@ static int xgmiitorgmii_read_status(struct phy_device *phydev)  	priv->phy_drv->read_status(phydev);  	val = mdiobus_read(phydev->mdio.bus, priv->addr, XILINX_GMII2RGMII_REG); -	val &= XILINX_GMII2RGMII_SPEED_MASK; +	val &= ~XILINX_GMII2RGMII_SPEED_MASK;  	if (phydev->speed == SPEED_1000)  		val |= BMCR_SPEED1000;  | 

