diff options
Diffstat (limited to 'drivers/net/phy')
46 files changed, 1066 insertions, 6194 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 1c5a10b672fc..698bea312adc 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -3,247 +3,6 @@ # PHY Layer Configuration # -menuconfig MDIO_DEVICE - tristate "MDIO bus device drivers" - help - MDIO devices and driver infrastructure code. - -if MDIO_DEVICE - -config MDIO_BUS - tristate - default m if PHYLIB=m - default MDIO_DEVICE - help - This internal symbol is used for link time dependencies and it - reflects whether the mdio_bus/mdio_device code is built as a - loadable module or built-in. - -if MDIO_BUS - -config MDIO_DEVRES - tristate - -config MDIO_ASPEED - tristate "ASPEED MDIO bus controller" - depends on ARCH_ASPEED || COMPILE_TEST - depends on OF_MDIO && HAS_IOMEM - help - This module provides a driver for the independent MDIO bus - controllers found in the ASPEED AST2600 SoC. This is a driver for the - third revision of the ASPEED MDIO register interface - the first two - revisions are the "old" and "new" interfaces found in the AST2400 and - AST2500, embedded in the MAC. For legacy reasons, FTGMAC100 driver - continues to drive the embedded MDIO controller for the AST2400 and - AST2500 SoCs, so say N if AST2600 support is not required. - -config MDIO_BCM_IPROC - tristate "Broadcom iProc MDIO bus controller" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF_MDIO - default ARCH_BCM_IPROC - help - This module provides a driver for the MDIO busses found in the - Broadcom iProc SoC's. - -config MDIO_BCM_UNIMAC - tristate "Broadcom UniMAC MDIO bus controller" - depends on HAS_IOMEM - help - This module provides a driver for the Broadcom UniMAC MDIO busses. - This hardware can be found in the Broadcom GENET Ethernet MAC - controllers as well as some Broadcom Ethernet switches such as the - Starfighter 2 switches. - -config MDIO_BITBANG - tristate "Bitbanged MDIO buses" - help - This module implements the MDIO bus protocol in software, - for use by low level drivers that export the ability to - drive the relevant pins. - - If in doubt, say N. - -config MDIO_BUS_MUX - tristate - depends on OF_MDIO - help - This module provides a driver framework for MDIO bus - multiplexers which connect one of several child MDIO busses - to a parent bus. Switching between child busses is done by - device specific drivers. - -config MDIO_BUS_MUX_BCM_IPROC - tristate "Broadcom iProc based MDIO bus multiplexers" - depends on OF && OF_MDIO && (ARCH_BCM_IPROC || COMPILE_TEST) - select MDIO_BUS_MUX - default ARCH_BCM_IPROC - help - This module provides a driver for MDIO bus multiplexers found in - iProc based Broadcom SoCs. This multiplexer connects one of several - child MDIO bus to a parent bus. Buses could be internal as well as - external and selection logic lies inside the same multiplexer. - -config MDIO_BUS_MUX_GPIO - tristate "GPIO controlled MDIO bus multiplexers" - depends on OF_GPIO && OF_MDIO - select MDIO_BUS_MUX - help - This module provides a driver for MDIO bus multiplexers that - are controlled via GPIO lines. The multiplexer connects one of - several child MDIO busses to a parent bus. Child bus - selection is under the control of GPIO lines. - -config MDIO_BUS_MUX_MESON_G12A - tristate "Amlogic G12a based MDIO bus multiplexer" - depends on ARCH_MESON || COMPILE_TEST - depends on OF_MDIO && HAS_IOMEM && COMMON_CLK - select MDIO_BUS_MUX - default m if ARCH_MESON - help - This module provides a driver for the MDIO multiplexer/glue of - the amlogic g12a SoC. The multiplexers connects either the external - or the internal MDIO bus to the parent bus. - -config MDIO_BUS_MUX_MMIOREG - tristate "MMIO device-controlled MDIO bus multiplexers" - depends on OF_MDIO && HAS_IOMEM - select MDIO_BUS_MUX - help - This module provides a driver for MDIO bus multiplexers that - are controlled via a simple memory-mapped device, like an FPGA. - The multiplexer connects one of several child MDIO busses to a - parent bus. Child bus selection is under the control of one of - the FPGA's registers. - - Currently, only 8/16/32 bits registers are supported. - -config MDIO_BUS_MUX_MULTIPLEXER - tristate "MDIO bus multiplexer using kernel multiplexer subsystem" - depends on OF_MDIO - select MULTIPLEXER - select MDIO_BUS_MUX - help - This module provides a driver for MDIO bus multiplexer - that is controlled via the kernel multiplexer subsystem. The - bus multiplexer connects one of several child MDIO busses to - a parent bus. Child bus selection is under the control of - the kernel multiplexer subsystem. - -config MDIO_CAVIUM - tristate - -config MDIO_GPIO - tristate "GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG - depends on GPIOLIB || COMPILE_TEST - help - Supports GPIO lib-based MDIO busses. - - To compile this driver as a module, choose M here: the module - will be called mdio-gpio. - -config MDIO_HISI_FEMAC - tristate "Hisilicon FEMAC MDIO bus controller" - depends on HAS_IOMEM && OF_MDIO - help - This module provides a driver for the MDIO busses found in the - Hisilicon SoC that have an Fast Ethernet MAC. - -config MDIO_I2C - tristate - depends on I2C - help - Support I2C based PHYs. This provides a MDIO bus bridged - to I2C to allow PHYs connected in I2C mode to be accessed - using the existing infrastructure. - - This is library mode. - -config MDIO_IPQ4019 - tristate "Qualcomm IPQ4019 MDIO interface support" - depends on HAS_IOMEM && OF_MDIO - help - This driver supports the MDIO interface found in Qualcomm - IPQ40xx series Soc-s. - -config MDIO_IPQ8064 - tristate "Qualcomm IPQ8064 MDIO interface support" - depends on HAS_IOMEM && OF_MDIO - depends on MFD_SYSCON - help - This driver supports the MDIO interface found in the network - interface units of the IPQ8064 SoC - -config MDIO_MOXART - tristate "MOXA ART MDIO interface support" - depends on ARCH_MOXART || COMPILE_TEST - help - This driver supports the MDIO interface found in the network - interface units of the MOXA ART SoC - -config MDIO_MSCC_MIIM - tristate "Microsemi MIIM interface support" - depends on HAS_IOMEM - select MDIO_DEVRES - help - This driver supports the MIIM (MDIO) interface found in the network - switches of the Microsemi SoCs; it is recommended to switch on - CONFIG_HIGH_RES_TIMERS - -config MDIO_MVUSB - tristate "Marvell USB to MDIO Adapter" - depends on USB - select MDIO_DEVRES - help - A USB to MDIO converter present on development boards for - Marvell's Link Street family of Ethernet switches. - -config MDIO_OCTEON - tristate "Octeon and some ThunderX SOCs MDIO buses" - depends on (64BIT && OF_MDIO) || COMPILE_TEST - depends on HAS_IOMEM - select MDIO_CAVIUM - help - This module provides a driver for the Octeon and ThunderX MDIO - buses. It is required by the Octeon and ThunderX ethernet device - drivers on some systems. - -config MDIO_SUN4I - tristate "Allwinner sun4i MDIO interface support" - depends on ARCH_SUNXI || COMPILE_TEST - help - This driver supports the MDIO interface found in the network - interface units of the Allwinner SoC that have an EMAC (A10, - A12, A10s, etc.) - -config MDIO_THUNDER - tristate "ThunderX SOCs MDIO buses" - depends on 64BIT - depends on PCI - select MDIO_CAVIUM - select MDIO_DEVRES - help - This driver supports the MDIO interfaces found on Cavium - ThunderX SoCs when the MDIO bus device appears as a PCI - device. - -config MDIO_XGENE - tristate "APM X-Gene SoC MDIO bus controller" - depends on ARCH_XGENE || COMPILE_TEST - help - This module provides a driver for the MDIO busses found in the - APM X-Gene SoC's. - -config MDIO_XPCS - tristate "Synopsys DesignWare XPCS controller" - help - This module provides helper functions for Synopsys DesignWare XPCS - controllers. - -endif -endif - config PHYLINK tristate depends on NETDEVICES @@ -286,7 +45,15 @@ config LED_TRIGGER_PHY for any speed known to the PHY. -comment "MII PHY device drivers" +config FIXED_PHY + tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB + select SWPHY + help + Adds the platform "fixed" MDIO Bus to cover the boards that use + PHYs that are not connected to the real MDIO bus. + + Currently tested with mpc866ads and mpc8349e-mitx. config SFP tristate "SFP cage support" @@ -294,6 +61,19 @@ config SFP depends on HWMON || HWMON=n select MDIO_I2C +comment "MII PHY device drivers" + +config AMD_PHY + tristate "AMD PHYs" + help + Currently supports the am79c874 + +config MESON_GXL_PHY + tristate "Amlogic Meson GXL Internal PHY" + depends on ARCH_MESON || COMPILE_TEST + help + Currently has a driver for the Amlogic Meson GXL Internal PHY + config ADIN_PHY tristate "Analog Devices Industrial Ethernet PHYs" help @@ -303,11 +83,6 @@ config ADIN_PHY - ADIN1300 - Robust,Industrial, Low Latency 10/100/1000 Gigabit Ethernet PHY -config AMD_PHY - tristate "AMD PHYs" - help - Currently supports the am79c874 - config AQUANTIA_PHY tristate "Aquantia PHYs" help @@ -319,6 +94,24 @@ config AX88796B_PHY Currently supports the Asix Electronics PHY found in the X-Surf 100 AX88796B package. +config BROADCOM_PHY + tristate "Broadcom 54XX PHYs" + select BCM_NET_PHYLIB + help + Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, + BCM5481, BCM54810 and BCM5482 PHYs. + +config BCM54140_PHY + tristate "Broadcom BCM54140 PHY" + depends on PHYLIB + depends on HWMON || HWMON=n + select BCM_NET_PHYLIB + help + Support the Broadcom BCM54140 Quad SGMII/QSGMII PHY. + + This driver also supports the hardware monitoring of this PHY and + exposes voltage and temperature sensors. + config BCM63XX_PHY tristate "Broadcom 63xx SOCs internal PHY" depends on BCM63XX || COMPILE_TEST @@ -333,6 +126,12 @@ config BCM7XXX_PHY Currently supports the BCM7366, BCM7439, BCM7445, and 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. +config BCM84881_PHY + tristate "Broadcom BCM84881 PHY" + depends on PHYLIB + help + Support the Broadcom BCM84881 PHY. + config BCM87XX_PHY tristate "Broadcom BCM8706 and BCM8727 PHYs" help @@ -354,30 +153,6 @@ config BCM_CYGNUS_PHY config BCM_NET_PHYLIB tristate -config BROADCOM_PHY - tristate "Broadcom PHYs" - select BCM_NET_PHYLIB - help - Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, - BCM5481, BCM54810 and BCM5482 PHYs. - -config BCM54140_PHY - tristate "Broadcom BCM54140 PHY" - depends on PHYLIB - depends on HWMON || HWMON=n - select BCM_NET_PHYLIB - help - Support the Broadcom BCM54140 Quad SGMII/QSGMII PHY. - - This driver also supports the hardware monitoring of this PHY and - exposes voltage and temperature sensors. - -config BCM84881_PHY - tristate "Broadcom BCM84881 PHY" - depends on PHYLIB - help - Support the Broadcom BCM84881 PHY. - config CICADA_PHY tristate "Cicada PHYs" help @@ -393,48 +168,16 @@ config DAVICOM_PHY help Currently supports dm9161e and dm9131 -config DP83822_PHY - tristate "Texas Instruments DP83822/825/826 PHYs" - help - Supports the DP83822, DP83825I, DP83825CM, DP83825CS, DP83825S, - DP83826C and DP83826NC PHYs. - -config DP83TC811_PHY - tristate "Texas Instruments DP83TC811 PHY" - help - Supports the DP83TC811 PHY. - -config DP83848_PHY - tristate "Texas Instruments DP83848 PHY" - help - Supports the DP83848 PHY. - -config DP83867_PHY - tristate "Texas Instruments DP83867 Gigabit PHY" - help - Currently supports the DP83867 PHY. - -config DP83869_PHY - tristate "Texas Instruments DP83869 Gigabit PHY" - help - Currently supports the DP83869 PHY. This PHY supports copper and - fiber connections. - -config FIXED_PHY - tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" - depends on PHYLIB - select SWPHY - help - Adds the platform "fixed" MDIO Bus to cover the boards that use - PHYs that are not connected to the real MDIO bus. - - Currently tested with mpc866ads and mpc8349e-mitx. - config ICPLUS_PHY tristate "ICPlus PHYs" help Currently supports the IP175C and IP1001 PHYs. +config LXT_PHY + tristate "Intel LXT PHYs" + help + Currently supports the lxt970, lxt971 + config INTEL_XWAY_PHY tristate "Intel XWAY PHYs" help @@ -448,27 +191,16 @@ config LSI_ET1011C_PHY help Supports the LSI ET1011C PHY. -config LXT_PHY - tristate "Intel LXT PHYs" - help - Currently supports the lxt970, lxt971 - config MARVELL_PHY - tristate "Marvell PHYs" + tristate "Marvell Alaska PHYs" help - Currently has a driver for the 88E1011S + Currently has a driver for the 88E1XXX config MARVELL_10G_PHY tristate "Marvell Alaska 10Gbit PHYs" help Support for the Marvell Alaska MV88X3310 and compatible PHYs. -config MESON_GXL_PHY - tristate "Amlogic Meson GXL Internal PHY" - depends on ARCH_MESON || COMPILE_TEST - help - Currently has a driver for the Amlogic Meson GXL Internal PHY - config MICREL_PHY tristate "Micrel PHYs" help @@ -519,12 +251,12 @@ config REALTEK_PHY Supports the Realtek 821x PHY. config RENESAS_PHY - tristate "Driver for Renesas PHYs" + tristate "Renesas PHYs" help Supports the Renesas PHYs uPD60620 and uPD60620A. config ROCKCHIP_PHY - tristate "Driver for Rockchip Ethernet PHYs" + tristate "Rockchip Ethernet PHYs" help Currently supports the integrated Ethernet PHY. @@ -543,6 +275,33 @@ config TERANETICS_PHY help Currently supports the Teranetics TN2020 +config DP83822_PHY + tristate "Texas Instruments DP83822/825/826 PHYs" + help + Supports the DP83822, DP83825I, DP83825CM, DP83825CS, DP83825S, + DP83826C and DP83826NC PHYs. + +config DP83TC811_PHY + tristate "Texas Instruments DP83TC811 PHY" + help + Supports the DP83TC811 PHY. + +config DP83848_PHY + tristate "Texas Instruments DP83848 PHY" + help + Supports the DP83848 PHY. + +config DP83867_PHY + tristate "Texas Instruments DP83867 Gigabit PHY" + help + Currently supports the DP83867 PHY. + +config DP83869_PHY + tristate "Texas Instruments DP83869 Gigabit PHY" + help + Currently supports the DP83869 PHY. This PHY supports copper and + fiber connections. + config VITESSE_PHY tristate "Vitesse PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index d84bab489a53..a13e402074cf 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -# Makefile for Linux PHY drivers and MDIO bus drivers +# Makefile for Linux PHY drivers libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \ linkmode.o @@ -24,31 +24,6 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o obj-$(CONFIG_PHYLINK) += phylink.o obj-$(CONFIG_PHYLIB) += libphy.o -obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o -obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o -obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o -obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o -obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o -obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o -obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o -obj-$(CONFIG_MDIO_BUS_MUX_MESON_G12A) += mdio-mux-meson-g12a.o -obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o -obj-$(CONFIG_MDIO_BUS_MUX_MULTIPLEXER) += mdio-mux-multiplexer.o -obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o -obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o -obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o -obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o -obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o -obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o -obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o -obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o -obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o -obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o -obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o -obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o -obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o -obj-$(CONFIG_MDIO_XPCS) += mdio-xpcs.o - obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o obj-$(CONFIG_SFP) += sfp.o @@ -62,32 +37,32 @@ ifdef CONFIG_HWMON aquantia-objs += aquantia_hwmon.o endif obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o -obj-$(CONFIG_AX88796B_PHY) += ax88796b.o obj-$(CONFIG_AT803X_PHY) += at803x.o +obj-$(CONFIG_AX88796B_PHY) += ax88796b.o +obj-$(CONFIG_BCM54140_PHY) += bcm54140.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o +obj-$(CONFIG_BCM84881_PHY) += bcm84881.o obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o -obj-$(CONFIG_BCM54140_PHY) += bcm54140.o -obj-$(CONFIG_BCM84881_PHY) += bcm84881.o 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_DP83TC811_PHY) += dp83tc811.o obj-$(CONFIG_DP83848_PHY) += dp83848.o obj-$(CONFIG_DP83867_PHY) += dp83867.o obj-$(CONFIG_DP83869_PHY) += dp83869.o +obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o obj-$(CONFIG_FIXED_PHY) += fixed_phy.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_LXT_PHY) += lxt.o -obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o +obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 101651b2de54..ed601a7e46a0 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -343,7 +343,7 @@ static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; } -static struct regulator_ops vddio_regulator_ops = { +static const struct regulator_ops vddio_regulator_ops = { .list_voltage = regulator_list_voltage_table, .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel, .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel, @@ -364,7 +364,7 @@ static const struct regulator_desc vddio_desc = { .owner = THIS_MODULE, }; -static struct regulator_ops vddh_regulator_ops = { +static const struct regulator_ops vddh_regulator_ops = { }; static const struct regulator_desc vddh_desc = { diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 692048d86ab1..15812001b3ff 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -11,6 +11,7 @@ #include "bcm-phy-lib.h" #include <linux/bitops.h> #include <linux/brcmphy.h> +#include <linux/clk.h> #include <linux/mdio.h> /* Broadcom BCM7xxx internal PHY registers */ @@ -39,6 +40,7 @@ struct bcm7xxx_phy_priv { u64 *stats; + struct clk *clk; }; static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) @@ -521,6 +523,7 @@ static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev, static int bcm7xxx_28nm_probe(struct phy_device *phydev) { struct bcm7xxx_phy_priv *priv; + int ret = 0; priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -534,7 +537,30 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) if (!priv->stats) return -ENOMEM; - return 0; + priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + /* Dummy read to a register to workaround an issue upon reset where the + * internal inverter may not allow the first MDIO transaction to pass + * the MDIO management controller and make us return 0xffff for such + * reads. This is needed to ensure that any subsequent reads to the + * PHY will succeed. + */ + phy_read(phydev, MII_BMSR); + + return ret; +} + +static void bcm7xxx_28nm_remove(struct phy_device *phydev) +{ + struct bcm7xxx_phy_priv *priv = phydev->priv; + + clk_disable_unprepare(priv->clk); } #define BCM7XXX_28NM_GPHY(_oui, _name) \ @@ -552,6 +578,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) .get_strings = bcm_phy_get_strings, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \ .probe = bcm7xxx_28nm_probe, \ + .remove = bcm7xxx_28nm_remove, \ } #define BCM7XXX_28NM_EPHY(_oui, _name) \ @@ -567,6 +594,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) .get_strings = bcm_phy_get_strings, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \ .probe = bcm7xxx_28nm_probe, \ + .remove = bcm7xxx_28nm_remove, \ } #define BCM7XXX_40NM_EPHY(_oui, _name) \ @@ -583,6 +611,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) } static struct phy_driver bcm7xxx_driver[] = { + BCM7XXX_28NM_EPHY(PHY_ID_BCM72113, "Broadcom BCM72113"), BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"), BCM7XXX_28NM_EPHY(PHY_ID_BCM7255, "Broadcom BCM7255"), BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"), @@ -603,6 +632,7 @@ static struct phy_driver bcm7xxx_driver[] = { }; static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { + { PHY_ID_BCM72113, 0xfffffff0 }, { PHY_ID_BCM7250, 0xfffffff0, }, { PHY_ID_BCM7255, 0xfffffff0, }, { PHY_ID_BCM7260, 0xfffffff0, }, diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 79e67f2fe00a..f2caccaf4408 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -798,51 +798,32 @@ static int decode_evnt(struct dp83640_private *dp83640, return parsed; } -#define DP83640_PACKET_HASH_OFFSET 20 #define DP83640_PACKET_HASH_LEN 10 static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) { - unsigned int offset = 0; - u8 *msgtype, *data = skb_mac_header(skb); - __be16 *seqid; + struct ptp_header *hdr; + u8 msgtype; + u16 seqid; u16 hash; /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ - if (type & PTP_CLASS_VLAN) - offset += VLAN_HLEN; - - switch (type & PTP_CLASS_PMASK) { - case PTP_CLASS_IPV4: - offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; - break; - case PTP_CLASS_IPV6: - offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; - break; - case PTP_CLASS_L2: - offset += ETH_HLEN; - break; - default: + hdr = ptp_parse_header(skb, type); + if (!hdr) return 0; - } - if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) - return 0; + msgtype = ptp_get_msgtype(hdr, type); - if (unlikely(type & PTP_CLASS_V1)) - msgtype = data + offset + OFF_PTP_CONTROL; - else - msgtype = data + offset; - if (rxts->msgtype != (*msgtype & 0xf)) + if (rxts->msgtype != (msgtype & 0xf)) return 0; - seqid = (__be16 *)(data + offset + OFF_PTP_SEQUENCE_ID); - if (rxts->seqid != ntohs(*seqid)) + seqid = be16_to_cpu(hdr->sequence_id); + if (rxts->seqid != seqid) return 0; hash = ether_crc(DP83640_PACKET_HASH_LEN, - data + offset + DP83640_PACKET_HASH_OFFSET) >> 20; + (unsigned char *)&hdr->source_port_identity) >> 20; if (rxts->hash != hash) return 0; @@ -982,35 +963,16 @@ static void decode_status_frame(struct dp83640_private *dp83640, static int is_sync(struct sk_buff *skb, int type) { - u8 *data = skb->data, *msgtype; - unsigned int offset = 0; - - if (type & PTP_CLASS_VLAN) - offset += VLAN_HLEN; - - switch (type & PTP_CLASS_PMASK) { - case PTP_CLASS_IPV4: - offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; - break; - case PTP_CLASS_IPV6: - offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; - break; - case PTP_CLASS_L2: - offset += ETH_HLEN; - break; - default: - return 0; - } - - if (type & PTP_CLASS_V1) - offset += OFF_PTP_CONTROL; + struct ptp_header *hdr; + u8 msgtype; - if (skb->len < offset + 1) + hdr = ptp_parse_header(skb, type); + if (!hdr) return 0; - msgtype = data + offset; + msgtype = ptp_get_msgtype(hdr, type); - return (*msgtype & 0xf) == 0; + return (msgtype & 0xf) == 0; } static void dp83640_free_clocks(void) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 37643c468e19..c162c9551bd1 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -23,16 +23,31 @@ #define DP83822_DEVADDR 0x1f +#define MII_DP83822_CTRL_2 0x0a +#define MII_DP83822_PHYSTS 0x10 #define MII_DP83822_PHYSCR 0x11 #define MII_DP83822_MISR1 0x12 #define MII_DP83822_MISR2 0x13 +#define MII_DP83822_FCSCR 0x14 #define MII_DP83822_RCSR 0x17 #define MII_DP83822_RESET_CTRL 0x1f #define MII_DP83822_GENCFG 0x465 +#define MII_DP83822_SOR1 0x467 + +/* GENCFG */ +#define DP83822_SIG_DET_LOW BIT(0) + +/* Control Register 2 bits */ +#define DP83822_FX_ENABLE BIT(14) #define DP83822_HW_RESET BIT(15) #define DP83822_SW_RESET BIT(14) +/* PHY STS bits */ +#define DP83822_PHYSTS_DUPLEX BIT(2) +#define DP83822_PHYSTS_10 BIT(1) +#define DP83822_PHYSTS_LINK BIT(0) + /* PHYSCR Register Fields */ #define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */ #define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */ @@ -83,6 +98,27 @@ #define DP83822_RX_CLK_SHIFT BIT(12) #define DP83822_TX_CLK_SHIFT BIT(11) +/* SOR1 mode */ +#define DP83822_STRAP_MODE1 0 +#define DP83822_STRAP_MODE2 BIT(0) +#define DP83822_STRAP_MODE3 BIT(1) +#define DP83822_STRAP_MODE4 GENMASK(1, 0) + +#define DP83822_COL_STRAP_MASK GENMASK(11, 10) +#define DP83822_COL_SHIFT 10 +#define DP83822_RX_ER_STR_MASK GENMASK(9, 8) +#define DP83822_RX_ER_SHIFT 8 + +#define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \ + ADVERTISED_FIBRE | \ + ADVERTISED_Pause | ADVERTISED_Asym_Pause) + +struct dp83822_private { + bool fx_signal_det_low; + int fx_enabled; + u16 fx_sd_enable; +}; + static int dp83822_ack_interrupt(struct phy_device *phydev) { int err; @@ -197,6 +233,7 @@ static void dp83822_get_wol(struct phy_device *phydev, static int dp83822_config_intr(struct phy_device *phydev) { + struct dp83822_private *dp83822 = phydev->priv; int misr_status; int physcr_status; int err; @@ -208,13 +245,16 @@ static int dp83822_config_intr(struct phy_device *phydev) 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); + if (!dp83822->fx_enabled) + misr_status |= DP83822_ANEG_COMPLETE_INT_EN | + DP83822_DUP_MODE_CHANGE_INT_EN | + DP83822_SPEED_CHANGED_INT_EN; + + err = phy_write(phydev, MII_DP83822_MISR1, misr_status); if (err < 0) return err; @@ -224,14 +264,16 @@ static int dp83822_config_intr(struct phy_device *phydev) 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); + if (!dp83822->fx_enabled) + misr_status |= DP83822_MDI_XOVER_INT_EN | + DP83822_ANEG_ERR_INT_EN | + DP83822_WOL_PKT_INT_EN; + err = phy_write(phydev, MII_DP83822_MISR2, misr_status); if (err < 0) return err; @@ -270,13 +312,60 @@ static int dp8382x_disable_wol(struct phy_device *phydev) MII_DP83822_WOL_CFG, value); } +static int dp83822_read_status(struct phy_device *phydev) +{ + struct dp83822_private *dp83822 = phydev->priv; + int status = phy_read(phydev, MII_DP83822_PHYSTS); + int ctrl2; + int ret; + + if (dp83822->fx_enabled) { + if (status & DP83822_PHYSTS_LINK) { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + } else { + ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2); + if (ctrl2 < 0) + return ctrl2; + + if (!(ctrl2 & DP83822_FX_ENABLE)) { + ret = phy_write(phydev, MII_DP83822_CTRL_2, + DP83822_FX_ENABLE | ctrl2); + if (ret < 0) + return ret; + } + } + } + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + if (status < 0) + return status; + + if (status & DP83822_PHYSTS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (status & DP83822_PHYSTS_10) + phydev->speed = SPEED_10; + else + phydev->speed = SPEED_100; + + return 0; +} + static int dp83822_config_init(struct phy_device *phydev) { + struct dp83822_private *dp83822 = phydev->priv; struct device *dev = &phydev->mdio.dev; int rgmii_delay; s32 rx_int_delay; s32 tx_int_delay; int err = 0; + int bmcr; if (phy_interface_is_rgmii(phydev)) { rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0, @@ -302,6 +391,61 @@ static int dp83822_config_init(struct phy_device *phydev) } } + if (dp83822->fx_enabled) { + err = phy_modify(phydev, MII_DP83822_CTRL_2, + DP83822_FX_ENABLE, 1); + if (err < 0) + return err; + + /* Only allow advertising what this PHY supports */ + linkmode_and(phydev->advertising, phydev->advertising, + phydev->supported); + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->advertising); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->advertising); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->advertising); + + /* Auto neg is not supported in fiber mode */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_ANENABLE) { + err = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); + if (err < 0) + return err; + } + phydev->autoneg = AUTONEG_DISABLE; + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->supported); + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->advertising); + + /* Setup fiber advertisement */ + err = phy_modify_changed(phydev, MII_ADVERTISE, + MII_DP83822_FIBER_ADVERTISE, + MII_DP83822_FIBER_ADVERTISE); + + if (err < 0) + return err; + + if (dp83822->fx_signal_det_low) { + err = phy_set_bits_mmd(phydev, DP83822_DEVADDR, + MII_DP83822_GENCFG, + DP83822_SIG_DET_LOW); + if (err) + return err; + } + } return dp8382x_disable_wol(phydev); } @@ -314,13 +458,85 @@ static int dp83822_phy_reset(struct phy_device *phydev) { int err; - err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET); + err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET); if (err < 0) return err; return phydev->drv->config_init(phydev); } +#ifdef CONFIG_OF_MDIO +static int dp83822_of_init(struct phy_device *phydev) +{ + struct dp83822_private *dp83822 = phydev->priv; + struct device *dev = &phydev->mdio.dev; + + /* Signal detection for the PHY is only enabled if the FX_EN and the + * SD_EN pins are strapped. Signal detection can only enabled if FX_EN + * is strapped otherwise signal detection is disabled for the PHY. + */ + if (dp83822->fx_enabled && dp83822->fx_sd_enable) + dp83822->fx_signal_det_low = device_property_present(dev, + "ti,link-loss-low"); + if (!dp83822->fx_enabled) + dp83822->fx_enabled = device_property_present(dev, + "ti,fiber-mode"); + + return 0; +} +#else +static int dp83822_of_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_OF_MDIO */ + +static int dp83822_read_straps(struct phy_device *phydev) +{ + struct dp83822_private *dp83822 = phydev->priv; + int fx_enabled, fx_sd_enable; + int val; + + val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1); + if (val < 0) + return val; + + fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT; + if (fx_enabled == DP83822_STRAP_MODE2 || + fx_enabled == DP83822_STRAP_MODE3) + dp83822->fx_enabled = 1; + + if (dp83822->fx_enabled) { + fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT; + if (fx_sd_enable == DP83822_STRAP_MODE3 || + fx_sd_enable == DP83822_STRAP_MODE4) + dp83822->fx_sd_enable = 1; + } + + return 0; +} + +static int dp83822_probe(struct phy_device *phydev) +{ + struct dp83822_private *dp83822; + int ret; + + dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822), + GFP_KERNEL); + if (!dp83822) + return -ENOMEM; + + phydev->priv = dp83822; + + ret = dp83822_read_straps(phydev); + if (ret) + return ret; + + dp83822_of_init(phydev); + + return 0; +} + static int dp83822_suspend(struct phy_device *phydev) { int value; @@ -352,8 +568,10 @@ static int dp83822_resume(struct phy_device *phydev) PHY_ID_MATCH_MODEL(_id), \ .name = (_name), \ /* PHY_BASIC_FEATURES */ \ + .probe = dp83822_probe, \ .soft_reset = dp83822_phy_reset, \ .config_init = dp83822_config_init, \ + .read_status = dp83822_read_status, \ .get_wol = dp83822_get_wol, \ .set_wol = dp83822_set_wol, \ .ack_interrupt = dp83822_ack_interrupt, \ diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index cd7032628a28..69d3eacc2b96 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * Driver for the Texas Instruments DP83867 PHY +/* Driver for the Texas Instruments DP83867 PHY * * Copyright (C) 2015 Texas Instruments Inc. */ @@ -113,7 +112,6 @@ #define DP83867_RGMII_RX_CLK_DELAY_SHIFT 0 #define DP83867_RGMII_RX_CLK_DELAY_INV (DP83867_RGMII_RX_CLK_DELAY_MAX + 1) - /* IO_MUX_CFG bits */ #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK 0x1f #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 @@ -384,22 +382,22 @@ static int dp83867_set_downshift(struct phy_device *phydev, u8 cnt) DP83867_DOWNSHIFT_EN); switch (cnt) { - case DP83867_DOWNSHIFT_1_COUNT: - count = DP83867_DOWNSHIFT_1_COUNT_VAL; - break; - case DP83867_DOWNSHIFT_2_COUNT: - count = DP83867_DOWNSHIFT_2_COUNT_VAL; - break; - case DP83867_DOWNSHIFT_4_COUNT: - count = DP83867_DOWNSHIFT_4_COUNT_VAL; - break; - case DP83867_DOWNSHIFT_8_COUNT: - count = DP83867_DOWNSHIFT_8_COUNT_VAL; - break; - default: - phydev_err(phydev, - "Downshift count must be 1, 2, 4 or 8\n"); - return -EINVAL; + case DP83867_DOWNSHIFT_1_COUNT: + count = DP83867_DOWNSHIFT_1_COUNT_VAL; + break; + case DP83867_DOWNSHIFT_2_COUNT: + count = DP83867_DOWNSHIFT_2_COUNT_VAL; + break; + case DP83867_DOWNSHIFT_4_COUNT: + count = DP83867_DOWNSHIFT_4_COUNT_VAL; + break; + case DP83867_DOWNSHIFT_8_COUNT: + count = DP83867_DOWNSHIFT_8_COUNT_VAL; + break; + default: + phydev_err(phydev, + "Downshift count must be 1, 2, 4 or 8\n"); + return -EINVAL; } val = DP83867_DOWNSHIFT_EN; @@ -411,7 +409,7 @@ static int dp83867_set_downshift(struct phy_device *phydev, u8 cnt) } static int dp83867_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) + struct ethtool_tunable *tuna, void *data) { switch (tuna->id) { case ETHTOOL_PHY_DOWNSHIFT: @@ -422,7 +420,7 @@ static int dp83867_get_tunable(struct phy_device *phydev, } static int dp83867_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) + struct ethtool_tunable *tuna, const void *data) { switch (tuna->id) { case ETHTOOL_PHY_DOWNSHIFT: @@ -524,11 +522,10 @@ static int dp83867_of_init(struct phy_device *phydev) dp83867->io_impedance = -1; /* leave at default */ dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node, - "ti,dp83867-rxctrl-strap-quirk"); + "ti,dp83867-rxctrl-strap-quirk"); dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node, - "ti,sgmii-ref-clock-output-enable"); - + "ti,sgmii-ref-clock-output-enable"); dp83867->rx_id_delay = DP83867_RGMII_RX_CLK_DELAY_INV; ret = of_property_read_u32(of_node, "ti,rx-internal-delay", diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 6b98d74b5102..cf6dec7b7d8e 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -4,12 +4,14 @@ */ #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/delay.h> +#include <linux/bitfield.h> #include <dt-bindings/net/ti-dp83869.h> @@ -19,6 +21,7 @@ #define MII_DP83869_PHYCTRL 0x10 #define MII_DP83869_MICR 0x12 #define MII_DP83869_ISR 0x13 +#define DP83869_CFG2 0x14 #define DP83869_CTRL 0x1f #define DP83869_CFG4 0x1e @@ -27,6 +30,13 @@ #define DP83869_RGMIICTL 0x0032 #define DP83869_STRAP_STS1 0x006e #define DP83869_RGMIIDCTL 0x0086 +#define DP83869_RXFCFG 0x0134 +#define DP83869_RXFPMD1 0x0136 +#define DP83869_RXFPMD2 0x0137 +#define DP83869_RXFPMD3 0x0138 +#define DP83869_RXFSOP1 0x0139 +#define DP83869_RXFSOP2 0x013A +#define DP83869_RXFSOP3 0x013B #define DP83869_IO_MUX_CFG 0x0170 #define DP83869_OP_MODE 0x01df #define DP83869_FX_CTRL 0x0c00 @@ -52,6 +62,10 @@ BMCR_FULLDPLX | \ BMCR_SPEED1000) +#define MII_DP83869_FIBER_ADVERTISE (ADVERTISED_FIBRE | \ + ADVERTISED_Pause | \ + ADVERTISED_Asym_Pause) + /* This is the same bit mask as the BMCR so re-use the BMCR default */ #define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT @@ -100,6 +114,26 @@ #define DP83869_OP_MODE_MII BIT(5) #define DP83869_SGMII_RGMII_BRIDGE BIT(6) +/* RXFCFG bits*/ +#define DP83869_WOL_MAGIC_EN BIT(0) +#define DP83869_WOL_PATTERN_EN BIT(1) +#define DP83869_WOL_BCAST_EN BIT(2) +#define DP83869_WOL_UCAST_EN BIT(4) +#define DP83869_WOL_SEC_EN BIT(5) +#define DP83869_WOL_ENH_MAC BIT(7) + +/* CFG2 bits */ +#define DP83869_DOWNSHIFT_EN (BIT(8) | BIT(9)) +#define DP83869_DOWNSHIFT_ATTEMPT_MASK (BIT(10) | BIT(11)) +#define DP83869_DOWNSHIFT_1_COUNT_VAL 0 +#define DP83869_DOWNSHIFT_2_COUNT_VAL 1 +#define DP83869_DOWNSHIFT_4_COUNT_VAL 2 +#define DP83869_DOWNSHIFT_8_COUNT_VAL 3 +#define DP83869_DOWNSHIFT_1_COUNT 1 +#define DP83869_DOWNSHIFT_2_COUNT 2 +#define DP83869_DOWNSHIFT_4_COUNT 4 +#define DP83869_DOWNSHIFT_8_COUNT 8 + enum { DP83869_PORT_MIRRORING_KEEP, DP83869_PORT_MIRRORING_EN, @@ -118,6 +152,28 @@ struct dp83869_private { int mode; }; +static int dp83869_read_status(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + int ret; + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + if (phydev->link) { + if (dp83869->mode == DP83869_RGMII_100_BASE) + phydev->speed = SPEED_100; + } else { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + } + } + + return 0; +} + static int dp83869_ack_interrupt(struct phy_device *phydev) { int err = phy_read(phydev, MII_DP83869_ISR); @@ -151,6 +207,256 @@ static int dp83869_config_intr(struct phy_device *phydev) return phy_write(phydev, MII_DP83869_MICR, micr_status); } +static int dp83869_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + int val_rxcfg, val_micr; + u8 *mac; + int ret; + + val_rxcfg = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RXFCFG); + if (val_rxcfg < 0) + return val_rxcfg; + + val_micr = phy_read(phydev, MII_DP83869_MICR); + if (val_micr < 0) + return val_micr; + + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_UCAST | + WAKE_BCAST)) { + val_rxcfg |= DP83869_WOL_ENH_MAC; + val_micr |= MII_DP83869_MICR_WOL_INT_EN; + + if (wol->wolopts & WAKE_MAGIC || + wol->wolopts & WAKE_MAGICSECURE) { + mac = (u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFPMD1, + mac[1] << 8 | mac[0]); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFPMD2, + mac[3] << 8 | mac[2]); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFPMD3, + mac[5] << 8 | mac[4]); + if (ret) + return ret; + + val_rxcfg |= DP83869_WOL_MAGIC_EN; + } else { + val_rxcfg &= ~DP83869_WOL_MAGIC_EN; + } + + if (wol->wolopts & WAKE_MAGICSECURE) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP1, + (wol->sopass[1] << 8) | wol->sopass[0]); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP2, + (wol->sopass[3] << 8) | wol->sopass[2]); + if (ret) + return ret; + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP3, + (wol->sopass[5] << 8) | wol->sopass[4]); + if (ret) + return ret; + + val_rxcfg |= DP83869_WOL_SEC_EN; + } else { + val_rxcfg &= ~DP83869_WOL_SEC_EN; + } + + if (wol->wolopts & WAKE_UCAST) + val_rxcfg |= DP83869_WOL_UCAST_EN; + else + val_rxcfg &= ~DP83869_WOL_UCAST_EN; + + if (wol->wolopts & WAKE_BCAST) + val_rxcfg |= DP83869_WOL_BCAST_EN; + else + val_rxcfg &= ~DP83869_WOL_BCAST_EN; + } else { + val_rxcfg &= ~DP83869_WOL_ENH_MAC; + val_micr &= ~MII_DP83869_MICR_WOL_INT_EN; + } + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RXFCFG, val_rxcfg); + if (ret) + return ret; + + return phy_write(phydev, MII_DP83869_MICR, val_micr); +} + +static void dp83869_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int value, sopass_val; + + wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC | + WAKE_MAGICSECURE); + wol->wolopts = 0; + + value = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RXFCFG); + if (value < 0) { + phydev_err(phydev, "Failed to read RX CFG\n"); + return; + } + + if (value & DP83869_WOL_UCAST_EN) + wol->wolopts |= WAKE_UCAST; + + if (value & DP83869_WOL_BCAST_EN) + wol->wolopts |= WAKE_BCAST; + + if (value & DP83869_WOL_MAGIC_EN) + wol->wolopts |= WAKE_MAGIC; + + if (value & DP83869_WOL_SEC_EN) { + sopass_val = phy_read_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP1); + if (sopass_val < 0) { + phydev_err(phydev, "Failed to read RX SOP 1\n"); + return; + } + + wol->sopass[0] = (sopass_val & 0xff); + wol->sopass[1] = (sopass_val >> 8); + + sopass_val = phy_read_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP2); + if (sopass_val < 0) { + phydev_err(phydev, "Failed to read RX SOP 2\n"); + return; + } + + wol->sopass[2] = (sopass_val & 0xff); + wol->sopass[3] = (sopass_val >> 8); + + sopass_val = phy_read_mmd(phydev, DP83869_DEVADDR, + DP83869_RXFSOP3); + if (sopass_val < 0) { + phydev_err(phydev, "Failed to read RX SOP 3\n"); + return; + } + + wol->sopass[4] = (sopass_val & 0xff); + wol->sopass[5] = (sopass_val >> 8); + + wol->wolopts |= WAKE_MAGICSECURE; + } + + if (!(value & DP83869_WOL_ENH_MAC)) + wol->wolopts = 0; +} + +static int dp83869_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable, count; + + val = phy_read(phydev, DP83869_CFG2); + if (val < 0) + return val; + + enable = FIELD_GET(DP83869_DOWNSHIFT_EN, val); + cnt = FIELD_GET(DP83869_DOWNSHIFT_ATTEMPT_MASK, val); + + switch (cnt) { + case DP83869_DOWNSHIFT_1_COUNT_VAL: + count = DP83869_DOWNSHIFT_1_COUNT; + break; + case DP83869_DOWNSHIFT_2_COUNT_VAL: + count = DP83869_DOWNSHIFT_2_COUNT; + break; + case DP83869_DOWNSHIFT_4_COUNT_VAL: + count = DP83869_DOWNSHIFT_4_COUNT; + break; + case DP83869_DOWNSHIFT_8_COUNT_VAL: + count = DP83869_DOWNSHIFT_8_COUNT; + break; + default: + return -EINVAL; + } + + *data = enable ? count : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int dp83869_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int val, count; + + if (cnt > DP83869_DOWNSHIFT_8_COUNT) + return -EINVAL; + + if (!cnt) + return phy_clear_bits(phydev, DP83869_CFG2, + DP83869_DOWNSHIFT_EN); + + switch (cnt) { + case DP83869_DOWNSHIFT_1_COUNT: + count = DP83869_DOWNSHIFT_1_COUNT_VAL; + break; + case DP83869_DOWNSHIFT_2_COUNT: + count = DP83869_DOWNSHIFT_2_COUNT_VAL; + break; + case DP83869_DOWNSHIFT_4_COUNT: + count = DP83869_DOWNSHIFT_4_COUNT_VAL; + break; + case DP83869_DOWNSHIFT_8_COUNT: + count = DP83869_DOWNSHIFT_8_COUNT_VAL; + break; + default: + phydev_err(phydev, + "Downshift count must be 1, 2, 4 or 8\n"); + return -EINVAL; + } + + val = DP83869_DOWNSHIFT_EN; + val |= FIELD_PREP(DP83869_DOWNSHIFT_ATTEMPT_MASK, count); + + return phy_modify(phydev, DP83869_CFG2, + DP83869_DOWNSHIFT_EN | DP83869_DOWNSHIFT_ATTEMPT_MASK, + val); +} + +static int dp83869_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return dp83869_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int dp83869_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return dp83869_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + static int dp83869_config_port_mirroring(struct phy_device *phydev) { struct dp83869_private *dp83869 = phydev->priv; @@ -295,6 +601,51 @@ static int dp83869_configure_rgmii(struct phy_device *phydev, return ret; } +static int dp83869_configure_fiber(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int bmcr; + int ret; + + /* Only allow advertising what this PHY supports */ + linkmode_and(phydev->advertising, phydev->advertising, + phydev->supported); + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_set_bit(ADVERTISED_FIBRE, phydev->advertising); + + if (dp83869->mode == DP83869_RGMII_1000_BASE) { + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported); + } else { + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + phydev->supported); + + /* Auto neg is not supported in 100base FX mode */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + phydev->autoneg = AUTONEG_DISABLE; + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising); + + if (bmcr & BMCR_ANENABLE) { + ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); + if (ret < 0) + return ret; + } + } + + /* Update advertising from supported */ + linkmode_or(phydev->advertising, phydev->advertising, + phydev->supported); + + return 0; +} + static int dp83869_configure_mode(struct phy_device *phydev, struct dp83869_private *dp83869) { @@ -384,6 +735,7 @@ static int dp83869_configure_mode(struct phy_device *phydev, break; case DP83869_RGMII_1000_BASE: case DP83869_RGMII_100_BASE: + ret = dp83869_configure_fiber(phydev, dp83869); break; default: return -EINVAL; @@ -397,6 +749,12 @@ static int dp83869_config_init(struct phy_device *phydev) struct dp83869_private *dp83869 = phydev->priv; int ret, val; + /* Force speed optimization for the PHY even if it strapped */ + ret = phy_modify(phydev, DP83869_CFG2, DP83869_DOWNSHIFT_EN, + DP83869_DOWNSHIFT_EN); + if (ret) + return ret; + ret = dp83869_configure_mode(phydev, dp83869); if (ret) return ret; @@ -494,6 +852,13 @@ static struct phy_driver dp83869_driver[] = { /* IRQ related */ .ack_interrupt = dp83869_ack_interrupt, .config_intr = dp83869_config_intr, + .read_status = dp83869_read_status, + + .get_tunable = dp83869_get_tunable, + .set_tunable = dp83869_set_tunable, + + .get_wol = dp83869_get_wol, + .set_wol = dp83869_set_wol, .suspend = genphy_suspend, .resume = genphy_resume, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index bb86ac0bd092..5aec673a0120 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1598,21 +1598,15 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { - int oldpage, ret = 0; + int ret; wol->supported = WAKE_MAGIC; wol->wolopts = 0; - oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); - if (oldpage < 0) - goto error; - - ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); - if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) + ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE, + MII_88E1318S_PHY_WOL_CTRL); + if (ret >= 0 && ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - -error: - phy_restore_page(phydev, oldpage, ret); } static int m88e1318_set_wol(struct phy_device *phydev, diff --git a/drivers/net/phy/mdio-aspeed.c b/drivers/net/phy/mdio-aspeed.c deleted file mode 100644 index cad820568f75..000000000000 --- a/drivers/net/phy/mdio-aspeed.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (C) 2019 IBM Corp. */ - -#include <linux/bitfield.h> -#include <linux/delay.h> -#include <linux/iopoll.h> -#include <linux/mdio.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> - -#define DRV_NAME "mdio-aspeed" - -#define ASPEED_MDIO_CTRL 0x0 -#define ASPEED_MDIO_CTRL_FIRE BIT(31) -#define ASPEED_MDIO_CTRL_ST BIT(28) -#define ASPEED_MDIO_CTRL_ST_C45 0 -#define ASPEED_MDIO_CTRL_ST_C22 1 -#define ASPEED_MDIO_CTRL_OP GENMASK(27, 26) -#define MDIO_C22_OP_WRITE 0b01 -#define MDIO_C22_OP_READ 0b10 -#define ASPEED_MDIO_CTRL_PHYAD GENMASK(25, 21) -#define ASPEED_MDIO_CTRL_REGAD GENMASK(20, 16) -#define ASPEED_MDIO_CTRL_MIIWDATA GENMASK(15, 0) - -#define ASPEED_MDIO_DATA 0x4 -#define ASPEED_MDIO_DATA_MDC_THRES GENMASK(31, 24) -#define ASPEED_MDIO_DATA_MDIO_EDGE BIT(23) -#define ASPEED_MDIO_DATA_MDIO_LATCH GENMASK(22, 20) -#define ASPEED_MDIO_DATA_IDLE BIT(16) -#define ASPEED_MDIO_DATA_MIIRDATA GENMASK(15, 0) - -#define ASPEED_MDIO_INTERVAL_US 100 -#define ASPEED_MDIO_TIMEOUT_US (ASPEED_MDIO_INTERVAL_US * 10) - -struct aspeed_mdio { - void __iomem *base; -}; - -static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum) -{ - struct aspeed_mdio *ctx = bus->priv; - u32 ctrl; - u32 data; - int rc; - - dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d\n", __func__, addr, - regnum); - - /* Just clause 22 for the moment */ - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - ctrl = ASPEED_MDIO_CTRL_FIRE - | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22) - | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ) - | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr) - | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum); - - iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); - - rc = readl_poll_timeout(ctx->base + ASPEED_MDIO_DATA, data, - data & ASPEED_MDIO_DATA_IDLE, - ASPEED_MDIO_INTERVAL_US, - ASPEED_MDIO_TIMEOUT_US); - if (rc < 0) - return rc; - - return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data); -} - -static int aspeed_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) -{ - struct aspeed_mdio *ctx = bus->priv; - u32 ctrl; - - dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d, val: 0x%x\n", - __func__, addr, regnum, val); - - /* Just clause 22 for the moment */ - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - ctrl = ASPEED_MDIO_CTRL_FIRE - | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22) - | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE) - | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr) - | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum) - | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val); - - iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); - - return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl, - !(ctrl & ASPEED_MDIO_CTRL_FIRE), - ASPEED_MDIO_INTERVAL_US, - ASPEED_MDIO_TIMEOUT_US); -} - -static int aspeed_mdio_probe(struct platform_device *pdev) -{ - struct aspeed_mdio *ctx; - struct mii_bus *bus; - int rc; - - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctx)); - if (!bus) - return -ENOMEM; - - ctx = bus->priv; - ctx->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ctx->base)) - return PTR_ERR(ctx->base); - - bus->name = DRV_NAME; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id); - bus->parent = &pdev->dev; - bus->read = aspeed_mdio_read; - bus->write = aspeed_mdio_write; - - rc = of_mdiobus_register(bus, pdev->dev.of_node); - if (rc) { - dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); - return rc; - } - - platform_set_drvdata(pdev, bus); - - return 0; -} - -static int aspeed_mdio_remove(struct platform_device *pdev) -{ - mdiobus_unregister(platform_get_drvdata(pdev)); - - return 0; -} - -static const struct of_device_id aspeed_mdio_of_match[] = { - { .compatible = "aspeed,ast2600-mdio", }, - { }, -}; - -static struct platform_driver aspeed_mdio_driver = { - .driver = { - .name = DRV_NAME, - .of_match_table = aspeed_mdio_of_match, - }, - .probe = aspeed_mdio_probe, - .remove = aspeed_mdio_remove, -}; - -module_platform_driver(aspeed_mdio_driver); - -MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-bcm-iproc.c b/drivers/net/phy/mdio-bcm-iproc.c deleted file mode 100644 index 77fc970cdfde..000000000000 --- a/drivers/net/phy/mdio-bcm-iproc.c +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2015 Broadcom Corporation - */ - -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/sched.h> - -#define IPROC_GPHY_MDCDIV 0x1a - -#define MII_CTRL_OFFSET 0x000 - -#define MII_CTRL_DIV_SHIFT 0 -#define MII_CTRL_PRE_SHIFT 7 -#define MII_CTRL_BUSY_SHIFT 8 - -#define MII_DATA_OFFSET 0x004 -#define MII_DATA_MASK 0xffff -#define MII_DATA_TA_SHIFT 16 -#define MII_DATA_TA_VAL 2 -#define MII_DATA_RA_SHIFT 18 -#define MII_DATA_PA_SHIFT 23 -#define MII_DATA_OP_SHIFT 28 -#define MII_DATA_OP_WRITE 1 -#define MII_DATA_OP_READ 2 -#define MII_DATA_SB_SHIFT 30 - -struct iproc_mdio_priv { - struct mii_bus *mii_bus; - void __iomem *base; -}; - -static inline int iproc_mdio_wait_for_idle(void __iomem *base) -{ - u32 val; - unsigned int timeout = 1000; /* loop for 1s */ - - do { - val = readl(base + MII_CTRL_OFFSET); - if ((val & BIT(MII_CTRL_BUSY_SHIFT)) == 0) - return 0; - - usleep_range(1000, 2000); - } while (timeout--); - - return -ETIMEDOUT; -} - -static inline void iproc_mdio_config_clk(void __iomem *base) -{ - u32 val; - - val = (IPROC_GPHY_MDCDIV << MII_CTRL_DIV_SHIFT) | - BIT(MII_CTRL_PRE_SHIFT); - writel(val, base + MII_CTRL_OFFSET); -} - -static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct iproc_mdio_priv *priv = bus->priv; - u32 cmd; - int rc; - - rc = iproc_mdio_wait_for_idle(priv->base); - if (rc) - return rc; - - /* Prepare the read operation */ - cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | - (reg << MII_DATA_RA_SHIFT) | - (phy_id << MII_DATA_PA_SHIFT) | - BIT(MII_DATA_SB_SHIFT) | - (MII_DATA_OP_READ << MII_DATA_OP_SHIFT); - - writel(cmd, priv->base + MII_DATA_OFFSET); - - rc = iproc_mdio_wait_for_idle(priv->base); - if (rc) - return rc; - - cmd = readl(priv->base + MII_DATA_OFFSET) & MII_DATA_MASK; - - return cmd; -} - -static int iproc_mdio_write(struct mii_bus *bus, int phy_id, - int reg, u16 val) -{ - struct iproc_mdio_priv *priv = bus->priv; - u32 cmd; - int rc; - - rc = iproc_mdio_wait_for_idle(priv->base); - if (rc) - return rc; - - /* Prepare the write operation */ - cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | - (reg << MII_DATA_RA_SHIFT) | - (phy_id << MII_DATA_PA_SHIFT) | - BIT(MII_DATA_SB_SHIFT) | - (MII_DATA_OP_WRITE << MII_DATA_OP_SHIFT) | - ((u32)(val) & MII_DATA_MASK); - - writel(cmd, priv->base + MII_DATA_OFFSET); - - rc = iproc_mdio_wait_for_idle(priv->base); - if (rc) - return rc; - - return 0; -} - -static int iproc_mdio_probe(struct platform_device *pdev) -{ - struct iproc_mdio_priv *priv; - struct mii_bus *bus; - int rc; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) { - dev_err(&pdev->dev, "failed to ioremap register\n"); - return PTR_ERR(priv->base); - } - - priv->mii_bus = mdiobus_alloc(); - if (!priv->mii_bus) { - dev_err(&pdev->dev, "MDIO bus alloc failed\n"); - return -ENOMEM; - } - - bus = priv->mii_bus; - bus->priv = priv; - bus->name = "iProc MDIO bus"; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); - bus->parent = &pdev->dev; - bus->read = iproc_mdio_read; - bus->write = iproc_mdio_write; - - iproc_mdio_config_clk(priv->base); - - rc = of_mdiobus_register(bus, pdev->dev.of_node); - if (rc) { - dev_err(&pdev->dev, "MDIO bus registration failed\n"); - goto err_iproc_mdio; - } - - platform_set_drvdata(pdev, priv); - - dev_info(&pdev->dev, "Broadcom iProc MDIO bus registered\n"); - - return 0; - -err_iproc_mdio: - mdiobus_free(bus); - return rc; -} - -static int iproc_mdio_remove(struct platform_device *pdev) -{ - struct iproc_mdio_priv *priv = platform_get_drvdata(pdev); - - mdiobus_unregister(priv->mii_bus); - mdiobus_free(priv->mii_bus); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int iproc_mdio_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct iproc_mdio_priv *priv = platform_get_drvdata(pdev); - - /* restore the mii clock configuration */ - iproc_mdio_config_clk(priv->base); - - return 0; -} - -static const struct dev_pm_ops iproc_mdio_pm_ops = { - .resume = iproc_mdio_resume -}; -#endif /* CONFIG_PM_SLEEP */ - -static const struct of_device_id iproc_mdio_of_match[] = { - { .compatible = "brcm,iproc-mdio", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, iproc_mdio_of_match); - -static struct platform_driver iproc_mdio_driver = { - .driver = { - .name = "iproc-mdio", - .of_match_table = iproc_mdio_of_match, -#ifdef CONFIG_PM_SLEEP - .pm = &iproc_mdio_pm_ops, -#endif - }, - .probe = iproc_mdio_probe, - .remove = iproc_mdio_remove, -}; - -module_platform_driver(iproc_mdio_driver); - -MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom iProc MDIO bus controller"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:iproc-mdio"); diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c deleted file mode 100644 index fbd36891ee64..000000000000 --- a/drivers/net/phy/mdio-bcm-unimac.c +++ /dev/null @@ -1,363 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Broadcom UniMAC MDIO bus controller driver - * - * Copyright (C) 2014-2017 Broadcom - */ - -#include <linux/kernel.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/clk.h> - -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/of_mdio.h> - -#include <linux/platform_data/mdio-bcm-unimac.h> - -#define MDIO_CMD 0x00 -#define MDIO_START_BUSY (1 << 29) -#define MDIO_READ_FAIL (1 << 28) -#define MDIO_RD (2 << 26) -#define MDIO_WR (1 << 26) -#define MDIO_PMD_SHIFT 21 -#define MDIO_PMD_MASK 0x1F -#define MDIO_REG_SHIFT 16 -#define MDIO_REG_MASK 0x1F - -#define MDIO_CFG 0x04 -#define MDIO_C22 (1 << 0) -#define MDIO_C45 0 -#define MDIO_CLK_DIV_SHIFT 4 -#define MDIO_CLK_DIV_MASK 0x3F -#define MDIO_SUPP_PREAMBLE (1 << 12) - -struct unimac_mdio_priv { - struct mii_bus *mii_bus; - void __iomem *base; - int (*wait_func) (void *wait_func_data); - void *wait_func_data; - struct clk *clk; - u32 clk_freq; -}; - -static inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset) -{ - /* MIPS chips strapped for BE will automagically configure the - * peripheral registers for CPU-native byte order. - */ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) - return __raw_readl(priv->base + offset); - else - return readl_relaxed(priv->base + offset); -} - -static inline void unimac_mdio_writel(struct unimac_mdio_priv *priv, u32 val, - u32 offset) -{ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) - __raw_writel(val, priv->base + offset); - else - writel_relaxed(val, priv->base + offset); -} - -static inline void unimac_mdio_start(struct unimac_mdio_priv *priv) -{ - u32 reg; - - reg = unimac_mdio_readl(priv, MDIO_CMD); - reg |= MDIO_START_BUSY; - unimac_mdio_writel(priv, reg, MDIO_CMD); -} - -static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv) -{ - return unimac_mdio_readl(priv, MDIO_CMD) & MDIO_START_BUSY; -} - -static int unimac_mdio_poll(void *wait_func_data) -{ - struct unimac_mdio_priv *priv = wait_func_data; - unsigned int timeout = 1000; - - do { - if (!unimac_mdio_busy(priv)) - return 0; - - usleep_range(1000, 2000); - } while (--timeout); - - return -ETIMEDOUT; -} - -static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct unimac_mdio_priv *priv = bus->priv; - int ret; - u32 cmd; - - /* Prepare the read operation */ - cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); - unimac_mdio_writel(priv, cmd, MDIO_CMD); - - /* Start MDIO transaction */ - unimac_mdio_start(priv); - - ret = priv->wait_func(priv->wait_func_data); - if (ret) - return ret; - - cmd = unimac_mdio_readl(priv, MDIO_CMD); - - /* Some broken devices are known not to release the line during - * turn-around, e.g: Broadcom BCM53125 external switches, so check for - * that condition here and ignore the MDIO controller read failure - * indication. - */ - if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL)) - return -EIO; - - return cmd & 0xffff; -} - -static int unimac_mdio_write(struct mii_bus *bus, int phy_id, - int reg, u16 val) -{ - struct unimac_mdio_priv *priv = bus->priv; - u32 cmd; - - /* Prepare the write operation */ - cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | - (reg << MDIO_REG_SHIFT) | (0xffff & val); - unimac_mdio_writel(priv, cmd, MDIO_CMD); - - unimac_mdio_start(priv); - - return priv->wait_func(priv->wait_func_data); -} - -/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with - * their internal MDIO management controller making them fail to successfully - * be read from or written to for the first transaction. We insert a dummy - * BMSR read here to make sure that phy_get_device() and get_phy_id() can - * correctly read the PHY MII_PHYSID1/2 registers and successfully register a - * PHY device for this peripheral. - * - * Once the PHY driver is registered, we can workaround subsequent reads from - * there (e.g: during system-wide power management). - * - * bus->reset is invoked before mdiobus_scan during mdiobus_register and is - * therefore the right location to stick that workaround. Since we do not want - * to read from non-existing PHYs, we either use bus->phy_mask or do a manual - * Device Tree scan to limit the search area. - */ -static int unimac_mdio_reset(struct mii_bus *bus) -{ - struct device_node *np = bus->dev.of_node; - struct device_node *child; - u32 read_mask = 0; - int addr; - - if (!np) { - read_mask = ~bus->phy_mask; - } else { - for_each_available_child_of_node(np, child) { - addr = of_mdio_parse_addr(&bus->dev, child); - if (addr < 0) - continue; - - read_mask |= 1 << addr; - } - } - - for (addr = 0; addr < PHY_MAX_ADDR; addr++) { - if (read_mask & 1 << addr) { - dev_dbg(&bus->dev, "Workaround for PHY @ %d\n", addr); - mdiobus_read(bus, addr, MII_BMSR); - } - } - - return 0; -} - -static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) -{ - unsigned long rate; - u32 reg, div; - - /* Keep the hardware default values */ - if (!priv->clk_freq) - return; - - if (!priv->clk) - rate = 250000000; - else - rate = clk_get_rate(priv->clk); - - div = (rate / (2 * priv->clk_freq)) - 1; - if (div & ~MDIO_CLK_DIV_MASK) { - pr_warn("Incorrect MDIO clock frequency, ignoring\n"); - return; - } - - /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by - * 2 x (MDIO_CLK_DIV + 1) - */ - reg = unimac_mdio_readl(priv, MDIO_CFG); - reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT); - reg |= div << MDIO_CLK_DIV_SHIFT; - unimac_mdio_writel(priv, reg, MDIO_CFG); -} - -static int unimac_mdio_probe(struct platform_device *pdev) -{ - struct unimac_mdio_pdata *pdata = pdev->dev.platform_data; - struct unimac_mdio_priv *priv; - struct device_node *np; - struct mii_bus *bus; - struct resource *r; - int ret; - - np = pdev->dev.of_node; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -EINVAL; - - /* Just ioremap, as this MDIO block is usually integrated into an - * Ethernet MAC controller register range - */ - priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (!priv->base) { - dev_err(&pdev->dev, "failed to remap register\n"); - return -ENOMEM; - } - - priv->clk = devm_clk_get_optional(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) - priv->clk_freq = 0; - - unimac_mdio_clk_set(priv); - - priv->mii_bus = mdiobus_alloc(); - if (!priv->mii_bus) { - ret = -ENOMEM; - goto out_clk_disable; - } - - bus = priv->mii_bus; - bus->priv = priv; - if (pdata) { - bus->name = pdata->bus_name; - priv->wait_func = pdata->wait_func; - priv->wait_func_data = pdata->wait_func_data; - bus->phy_mask = ~pdata->phy_mask; - } else { - bus->name = "unimac MII bus"; - priv->wait_func_data = priv; - priv->wait_func = unimac_mdio_poll; - } - bus->parent = &pdev->dev; - bus->read = unimac_mdio_read; - bus->write = unimac_mdio_write; - bus->reset = unimac_mdio_reset; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); - - ret = of_mdiobus_register(bus, np); - if (ret) { - dev_err(&pdev->dev, "MDIO bus registration failed\n"); - goto out_mdio_free; - } - - platform_set_drvdata(pdev, priv); - - dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus\n"); - - return 0; - -out_mdio_free: - mdiobus_free(bus); -out_clk_disable: - clk_disable_unprepare(priv->clk); - return ret; -} - -static int unimac_mdio_remove(struct platform_device *pdev) -{ - struct unimac_mdio_priv *priv = platform_get_drvdata(pdev); - - mdiobus_unregister(priv->mii_bus); - mdiobus_free(priv->mii_bus); - clk_disable_unprepare(priv->clk); - - return 0; -} - -static int __maybe_unused unimac_mdio_suspend(struct device *d) -{ - struct unimac_mdio_priv *priv = dev_get_drvdata(d); - - clk_disable_unprepare(priv->clk); - - return 0; -} - -static int __maybe_unused unimac_mdio_resume(struct device *d) -{ - struct unimac_mdio_priv *priv = dev_get_drvdata(d); - int ret; - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - unimac_mdio_clk_set(priv); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops, - unimac_mdio_suspend, unimac_mdio_resume); - -static const struct of_device_id unimac_mdio_ids[] = { - { .compatible = "brcm,genet-mdio-v5", }, - { .compatible = "brcm,genet-mdio-v4", }, - { .compatible = "brcm,genet-mdio-v3", }, - { .compatible = "brcm,genet-mdio-v2", }, - { .compatible = "brcm,genet-mdio-v1", }, - { .compatible = "brcm,unimac-mdio", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, unimac_mdio_ids); - -static struct platform_driver unimac_mdio_driver = { - .driver = { - .name = UNIMAC_MDIO_DRV_NAME, - .of_match_table = unimac_mdio_ids, - .pm = &unimac_mdio_pm_ops, - }, - .probe = unimac_mdio_probe, - .remove = unimac_mdio_remove, -}; -module_platform_driver(unimac_mdio_driver); - -MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" UNIMAC_MDIO_DRV_NAME); diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c deleted file mode 100644 index 5136275c8e73..000000000000 --- a/drivers/net/phy/mdio-bitbang.c +++ /dev/null @@ -1,232 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Bitbanged MDIO support. - * - * Author: Scott Wood <scottwood@freescale.com> - * Copyright (c) 2007 Freescale Semiconductor - * - * Based on CPM2 MDIO code which is: - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou <panto@intracom.gr> - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug <vbordug@ru.mvista.com> - */ - -#include <linux/module.h> -#include <linux/mdio-bitbang.h> -#include <linux/types.h> -#include <linux/delay.h> - -#define MDIO_READ 2 -#define MDIO_WRITE 1 - -#define MDIO_C45 (1<<15) -#define MDIO_C45_ADDR (MDIO_C45 | 0) -#define MDIO_C45_READ (MDIO_C45 | 3) -#define MDIO_C45_WRITE (MDIO_C45 | 1) - -#define MDIO_SETUP_TIME 10 -#define MDIO_HOLD_TIME 10 - -/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY - * is done twice per period. - */ -#define MDIO_DELAY 250 - -/* The PHY may take up to 300 ns to produce data, plus some margin - * for error. - */ -#define MDIO_READ_DELAY 350 - -/* MDIO must already be configured as output. */ -static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) -{ - const struct mdiobb_ops *ops = ctrl->ops; - - ops->set_mdio_data(ctrl, val); - ndelay(MDIO_DELAY); - ops->set_mdc(ctrl, 1); - ndelay(MDIO_DELAY); - ops->set_mdc(ctrl, 0); -} - -/* MDIO must already be configured as input. */ -static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) -{ - const struct mdiobb_ops *ops = ctrl->ops; - - ndelay(MDIO_DELAY); - ops->set_mdc(ctrl, 1); - ndelay(MDIO_READ_DELAY); - ops->set_mdc(ctrl, 0); - - return ops->get_mdio_data(ctrl); -} - -/* MDIO must already be configured as output. */ -static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) -{ - int i; - - for (i = bits - 1; i >= 0; i--) - mdiobb_send_bit(ctrl, (val >> i) & 1); -} - -/* MDIO must already be configured as input. */ -static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) -{ - int i; - u16 ret = 0; - - for (i = bits - 1; i >= 0; i--) { - ret <<= 1; - ret |= mdiobb_get_bit(ctrl); - } - - return ret; -} - -/* Utility to send the preamble, address, and - * register (common to read and write). - */ -static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) -{ - const struct mdiobb_ops *ops = ctrl->ops; - int i; - - ops->set_mdio_dir(ctrl, 1); - - /* - * Send a 32 bit preamble ('1's) with an extra '1' bit for good - * measure. The IEEE spec says this is a PHY optional - * requirement. The AMD 79C874 requires one after power up and - * one after a MII communications error. This means that we are - * doing more preambles than we need, but it is safer and will be - * much more robust. - */ - - for (i = 0; i < 32; i++) - mdiobb_send_bit(ctrl, 1); - - /* send the start bit (01) and the read opcode (10) or write (01). - Clause 45 operation uses 00 for the start and 11, 10 for - read/write */ - mdiobb_send_bit(ctrl, 0); - if (op & MDIO_C45) - mdiobb_send_bit(ctrl, 0); - else - mdiobb_send_bit(ctrl, 1); - mdiobb_send_bit(ctrl, (op >> 1) & 1); - mdiobb_send_bit(ctrl, (op >> 0) & 1); - - mdiobb_send_num(ctrl, phy, 5); - mdiobb_send_num(ctrl, reg, 5); -} - -/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the - lower 16 bits of the 21 bit address. This transfer is done identically to a - MDIO_WRITE except for a different code. To enable clause 45 mode or - MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices - can exist on the same bus. Normal devices should ignore the MDIO_ADDR - phase. */ -static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) -{ - unsigned int dev_addr = (addr >> 16) & 0x1F; - unsigned int reg = addr & 0xFFFF; - mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); - - /* send the turnaround (10) */ - mdiobb_send_bit(ctrl, 1); - mdiobb_send_bit(ctrl, 0); - - mdiobb_send_num(ctrl, reg, 16); - - ctrl->ops->set_mdio_dir(ctrl, 0); - mdiobb_get_bit(ctrl); - - return dev_addr; -} - -static int mdiobb_read(struct mii_bus *bus, int phy, int reg) -{ - struct mdiobb_ctrl *ctrl = bus->priv; - int ret, i; - - if (reg & MII_ADDR_C45) { - reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); - } else - mdiobb_cmd(ctrl, MDIO_READ, phy, reg); - - ctrl->ops->set_mdio_dir(ctrl, 0); - - /* check the turnaround bit: the PHY should be driving it to zero, if this - * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that - */ - if (mdiobb_get_bit(ctrl) != 0 && - !(bus->phy_ignore_ta_mask & (1 << phy))) { - /* PHY didn't drive TA low -- flush any bits it - * may be trying to send. - */ - for (i = 0; i < 32; i++) - mdiobb_get_bit(ctrl); - - return 0xffff; - } - - ret = mdiobb_get_num(ctrl, 16); - mdiobb_get_bit(ctrl); - return ret; -} - -static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) -{ - struct mdiobb_ctrl *ctrl = bus->priv; - - if (reg & MII_ADDR_C45) { - reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); - } else - mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); - - /* send the turnaround (10) */ - mdiobb_send_bit(ctrl, 1); - mdiobb_send_bit(ctrl, 0); - - mdiobb_send_num(ctrl, val, 16); - - ctrl->ops->set_mdio_dir(ctrl, 0); - mdiobb_get_bit(ctrl); - return 0; -} - -struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) -{ - struct mii_bus *bus; - - bus = mdiobus_alloc(); - if (!bus) - return NULL; - - __module_get(ctrl->ops->owner); - - bus->read = mdiobb_read; - bus->write = mdiobb_write; - bus->priv = ctrl; - - return bus; -} -EXPORT_SYMBOL(alloc_mdio_bitbang); - -void free_mdio_bitbang(struct mii_bus *bus) -{ - struct mdiobb_ctrl *ctrl = bus->priv; - - module_put(ctrl->ops->owner); - mdiobus_free(bus); -} -EXPORT_SYMBOL(free_mdio_bitbang); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-cavium.c b/drivers/net/phy/mdio-cavium.c deleted file mode 100644 index 1afd6fc1a351..000000000000 --- a/drivers/net/phy/mdio-cavium.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2009-2016 Cavium, Inc. - */ - -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/io.h> - -#include "mdio-cavium.h" - -static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p, - enum cavium_mdiobus_mode m) -{ - union cvmx_smix_clk smi_clk; - - if (m == p->mode) - return; - - smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK); - smi_clk.s.mode = (m == C45) ? 1 : 0; - smi_clk.s.preamble = 1; - oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK); - p->mode = m; -} - -static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, - int phy_id, int regnum) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - cavium_mdiobus_set_mode(p, C45); - - smi_wr.u64 = 0; - smi_wr.s.dat = regnum & 0xffff; - oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); - - regnum = (regnum >> 16) & 0x1f; - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = regnum; - oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); - - do { - /* Wait 1000 clocks so we don't saturate the RSL bus - * doing reads. - */ - __delay(1000); - smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); - } while (smi_wr.s.pending && --timeout); - - if (timeout <= 0) - return -EIO; - return 0; -} - -int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) -{ - struct cavium_mdiobus *p = bus->priv; - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_rd_dat smi_rd; - unsigned int op = 1; /* MDIO_CLAUSE_22_READ */ - int timeout = 1000; - - if (regnum & MII_ADDR_C45) { - int r = cavium_mdiobus_c45_addr(p, phy_id, regnum); - - if (r < 0) - return r; - - regnum = (regnum >> 16) & 0x1f; - op = 3; /* MDIO_CLAUSE_45_READ */ - } else { - cavium_mdiobus_set_mode(p, C22); - } - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = op; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = regnum; - oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); - - do { - /* Wait 1000 clocks so we don't saturate the RSL bus - * doing reads. - */ - __delay(1000); - smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); - } while (smi_rd.s.pending && --timeout); - - if (smi_rd.s.val) - return smi_rd.s.dat; - else - return -EIO; -} -EXPORT_SYMBOL(cavium_mdiobus_read); - -int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val) -{ - struct cavium_mdiobus *p = bus->priv; - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */ - int timeout = 1000; - - if (regnum & MII_ADDR_C45) { - int r = cavium_mdiobus_c45_addr(p, phy_id, regnum); - - if (r < 0) - return r; - - regnum = (regnum >> 16) & 0x1f; - op = 1; /* MDIO_CLAUSE_45_WRITE */ - } else { - cavium_mdiobus_set_mode(p, C22); - } - - smi_wr.u64 = 0; - smi_wr.s.dat = val; - oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = op; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = regnum; - oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); - - do { - /* Wait 1000 clocks so we don't saturate the RSL bus - * doing reads. - */ - __delay(1000); - smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); - } while (smi_wr.s.pending && --timeout); - - if (timeout <= 0) - return -EIO; - - return 0; -} -EXPORT_SYMBOL(cavium_mdiobus_write); - -MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers"); -MODULE_AUTHOR("David Daney"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-cavium.h b/drivers/net/phy/mdio-cavium.h deleted file mode 100644 index a2245d436f5d..000000000000 --- a/drivers/net/phy/mdio-cavium.h +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2009-2016 Cavium, Inc. - */ - -enum cavium_mdiobus_mode { - UNINIT = 0, - C22, - C45 -}; - -#define SMI_CMD 0x0 -#define SMI_WR_DAT 0x8 -#define SMI_RD_DAT 0x10 -#define SMI_CLK 0x18 -#define SMI_EN 0x20 - -#ifdef __BIG_ENDIAN_BITFIELD -#define OCT_MDIO_BITFIELD_FIELD(field, more) \ - field; \ - more - -#else -#define OCT_MDIO_BITFIELD_FIELD(field, more) \ - more \ - field; - -#endif - -union cvmx_smix_clk { - u64 u64; - struct cvmx_smix_clk_s { - OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39, - OCT_MDIO_BITFIELD_FIELD(u64 mode:1, - OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3, - OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5, - OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1, - OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1, - OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1, - OCT_MDIO_BITFIELD_FIELD(u64 preamble:1, - OCT_MDIO_BITFIELD_FIELD(u64 sample:4, - OCT_MDIO_BITFIELD_FIELD(u64 phase:8, - ;)))))))))) - } s; -}; - -union cvmx_smix_cmd { - u64 u64; - struct cvmx_smix_cmd_s { - OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, - OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2, - OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3, - OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5, - OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3, - OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5, - ;)))))) - } s; -}; - -union cvmx_smix_en { - u64 u64; - struct cvmx_smix_en_s { - OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63, - OCT_MDIO_BITFIELD_FIELD(u64 en:1, - ;)) - } s; -}; - -union cvmx_smix_rd_dat { - u64 u64; - struct cvmx_smix_rd_dat_s { - OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, - OCT_MDIO_BITFIELD_FIELD(u64 pending:1, - OCT_MDIO_BITFIELD_FIELD(u64 val:1, - OCT_MDIO_BITFIELD_FIELD(u64 dat:16, - ;)))) - } s; -}; - -union cvmx_smix_wr_dat { - u64 u64; - struct cvmx_smix_wr_dat_s { - OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, - OCT_MDIO_BITFIELD_FIELD(u64 pending:1, - OCT_MDIO_BITFIELD_FIELD(u64 val:1, - OCT_MDIO_BITFIELD_FIELD(u64 dat:16, - ;)))) - } s; -}; - -struct cavium_mdiobus { - struct mii_bus *mii_bus; - void __iomem *register_base; - enum cavium_mdiobus_mode mode; -}; - -#ifdef CONFIG_CAVIUM_OCTEON_SOC - -#include <asm/octeon/octeon.h> - -static inline void oct_mdio_writeq(u64 val, void __iomem *addr) -{ - cvmx_write_csr((u64 __force)addr, val); -} - -static inline u64 oct_mdio_readq(void __iomem *addr) -{ - return cvmx_read_csr((u64 __force)addr); -} -#else -#include <linux/io-64-nonatomic-lo-hi.h> - -#define oct_mdio_writeq(val, addr) writeq(val, addr) -#define oct_mdio_readq(addr) readq(addr) -#endif - -int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum); -int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val); diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c deleted file mode 100644 index 1b00235d7dc5..000000000000 --- a/drivers/net/phy/mdio-gpio.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPIO based MDIO bitbang driver. - * Supports OpenFirmware. - * - * Copyright (c) 2008 CSE Semaphore Belgium. - * by Laurent Pinchart <laurentp@cse-semaphore.com> - * - * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * Based on earlier work by - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou <panto@intracom.gr> - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug <vbordug@ru.mvista.com> - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/platform_data/mdio-gpio.h> -#include <linux/mdio-bitbang.h> -#include <linux/mdio-gpio.h> -#include <linux/gpio/consumer.h> -#include <linux/of_mdio.h> - -struct mdio_gpio_info { - struct mdiobb_ctrl ctrl; - struct gpio_desc *mdc, *mdio, *mdo; -}; - -static int mdio_gpio_get_data(struct device *dev, - struct mdio_gpio_info *bitbang) -{ - bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC, - GPIOD_OUT_LOW); - if (IS_ERR(bitbang->mdc)) - return PTR_ERR(bitbang->mdc); - - bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO, - GPIOD_IN); - if (IS_ERR(bitbang->mdio)) - return PTR_ERR(bitbang->mdio); - - bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO, - GPIOD_OUT_LOW); - return PTR_ERR_OR_ZERO(bitbang->mdo); -} - -static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - if (bitbang->mdo) { - /* Separate output pin. Always set its value to high - * when changing direction. If direction is input, - * assume the pin serves as pull-up. If direction is - * output, the default value is high. - */ - gpiod_set_value_cansleep(bitbang->mdo, 1); - return; - } - - if (dir) - gpiod_direction_output(bitbang->mdio, 1); - else - gpiod_direction_input(bitbang->mdio); -} - -static int mdio_get(struct mdiobb_ctrl *ctrl) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - return gpiod_get_value_cansleep(bitbang->mdio); -} - -static void mdio_set(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - if (bitbang->mdo) - gpiod_set_value_cansleep(bitbang->mdo, what); - else - gpiod_set_value_cansleep(bitbang->mdio, what); -} - -static void mdc_set(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - gpiod_set_value_cansleep(bitbang->mdc, what); -} - -static const struct mdiobb_ops mdio_gpio_ops = { - .owner = THIS_MODULE, - .set_mdc = mdc_set, - .set_mdio_dir = mdio_dir, - .set_mdio_data = mdio_set, - .get_mdio_data = mdio_get, -}; - -static struct mii_bus *mdio_gpio_bus_init(struct device *dev, - struct mdio_gpio_info *bitbang, - int bus_id) -{ - struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev); - struct mii_bus *new_bus; - - bitbang->ctrl.ops = &mdio_gpio_ops; - - new_bus = alloc_mdio_bitbang(&bitbang->ctrl); - if (!new_bus) - return NULL; - - new_bus->name = "GPIO Bitbanged MDIO"; - new_bus->parent = dev; - - if (bus_id != -1) - snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); - else - strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); - - if (pdata) { - new_bus->phy_mask = pdata->phy_mask; - new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; - } - - dev_set_drvdata(dev, new_bus); - - return new_bus; -} - -static void mdio_gpio_bus_deinit(struct device *dev) -{ - struct mii_bus *bus = dev_get_drvdata(dev); - - free_mdio_bitbang(bus); -} - -static void mdio_gpio_bus_destroy(struct device *dev) -{ - struct mii_bus *bus = dev_get_drvdata(dev); - - mdiobus_unregister(bus); - mdio_gpio_bus_deinit(dev); -} - -static int mdio_gpio_probe(struct platform_device *pdev) -{ - struct mdio_gpio_info *bitbang; - struct mii_bus *new_bus; - int ret, bus_id; - - bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL); - if (!bitbang) - return -ENOMEM; - - ret = mdio_gpio_get_data(&pdev->dev, bitbang); - if (ret) - return ret; - - if (pdev->dev.of_node) { - bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); - if (bus_id < 0) { - dev_warn(&pdev->dev, "failed to get alias id\n"); - bus_id = 0; - } - } else { - bus_id = pdev->id; - } - - new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id); - if (!new_bus) - return -ENODEV; - - ret = of_mdiobus_register(new_bus, pdev->dev.of_node); - if (ret) - mdio_gpio_bus_deinit(&pdev->dev); - - return ret; -} - -static int mdio_gpio_remove(struct platform_device *pdev) -{ - mdio_gpio_bus_destroy(&pdev->dev); - - return 0; -} - -static const struct of_device_id mdio_gpio_of_match[] = { - { .compatible = "virtual,mdio-gpio", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); - -static struct platform_driver mdio_gpio_driver = { - .probe = mdio_gpio_probe, - .remove = mdio_gpio_remove, - .driver = { - .name = "mdio-gpio", - .of_match_table = mdio_gpio_of_match, - }, -}; - -module_platform_driver(mdio_gpio_driver); - -MODULE_ALIAS("platform:mdio-gpio"); -MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); diff --git a/drivers/net/phy/mdio-hisi-femac.c b/drivers/net/phy/mdio-hisi-femac.c deleted file mode 100644 index f231c2fbb1de..000000000000 --- a/drivers/net/phy/mdio-hisi-femac.c +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Hisilicon Fast Ethernet MDIO Bus Driver - * - * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. - */ - -#include <linux/clk.h> -#include <linux/iopoll.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/platform_device.h> - -#define MDIO_RWCTRL 0x00 -#define MDIO_RO_DATA 0x04 -#define MDIO_WRITE BIT(13) -#define MDIO_RW_FINISH BIT(15) -#define BIT_PHY_ADDR_OFFSET 8 -#define BIT_WR_DATA_OFFSET 16 - -struct hisi_femac_mdio_data { - struct clk *clk; - void __iomem *membase; -}; - -static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) -{ - u32 val; - - return readl_poll_timeout(data->membase + MDIO_RWCTRL, - val, val & MDIO_RW_FINISH, 20, 10000); -} - -static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct hisi_femac_mdio_data *data = bus->priv; - int ret; - - ret = hisi_femac_mdio_wait_ready(data); - if (ret) - return ret; - - writel((mii_id << BIT_PHY_ADDR_OFFSET) | regnum, - data->membase + MDIO_RWCTRL); - - ret = hisi_femac_mdio_wait_ready(data); - if (ret) - return ret; - - return readl(data->membase + MDIO_RO_DATA) & 0xFFFF; -} - -static int hisi_femac_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 value) -{ - struct hisi_femac_mdio_data *data = bus->priv; - int ret; - - ret = hisi_femac_mdio_wait_ready(data); - if (ret) - return ret; - - writel(MDIO_WRITE | (value << BIT_WR_DATA_OFFSET) | - (mii_id << BIT_PHY_ADDR_OFFSET) | regnum, - data->membase + MDIO_RWCTRL); - - return hisi_femac_mdio_wait_ready(data); -} - -static int hisi_femac_mdio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct mii_bus *bus; - struct hisi_femac_mdio_data *data; - int ret; - - bus = mdiobus_alloc_size(sizeof(*data)); - if (!bus) - return -ENOMEM; - - bus->name = "hisi_femac_mii_bus"; - bus->read = &hisi_femac_mdio_read; - bus->write = &hisi_femac_mdio_write; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); - bus->parent = &pdev->dev; - - data = bus->priv; - data->membase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->membase)) { - ret = PTR_ERR(data->membase); - goto err_out_free_mdiobus; - } - - data->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(data->clk)) { - ret = PTR_ERR(data->clk); - goto err_out_free_mdiobus; - } - - ret = clk_prepare_enable(data->clk); - if (ret) - goto err_out_free_mdiobus; - - ret = of_mdiobus_register(bus, np); - if (ret) - goto err_out_disable_clk; - - platform_set_drvdata(pdev, bus); - - return 0; - -err_out_disable_clk: - clk_disable_unprepare(data->clk); -err_out_free_mdiobus: - mdiobus_free(bus); - return ret; -} - -static int hisi_femac_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - struct hisi_femac_mdio_data *data = bus->priv; - - mdiobus_unregister(bus); - clk_disable_unprepare(data->clk); - mdiobus_free(bus); - - return 0; -} - -static const struct of_device_id hisi_femac_mdio_dt_ids[] = { - { .compatible = "hisilicon,hisi-femac-mdio" }, - { } -}; -MODULE_DEVICE_TABLE(of, hisi_femac_mdio_dt_ids); - -static struct platform_driver hisi_femac_mdio_driver = { - .probe = hisi_femac_mdio_probe, - .remove = hisi_femac_mdio_remove, - .driver = { - .name = "hisi-femac-mdio", - .of_match_table = hisi_femac_mdio_dt_ids, - }, -}; - -module_platform_driver(hisi_femac_mdio_driver); - -MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC MDIO interface driver"); -MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-i2c.c b/drivers/net/phy/mdio-i2c.c deleted file mode 100644 index 0746e2cc39ae..000000000000 --- a/drivers/net/phy/mdio-i2c.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * MDIO I2C bridge - * - * Copyright (C) 2015-2016 Russell King - * - * Network PHYs can appear on I2C buses when they are part of SFP module. - * This driver exposes these PHYs to the networking PHY code, allowing - * our PHY drivers access to these PHYs, and so allowing configuration - * of their settings. - */ -#include <linux/i2c.h> -#include <linux/phy.h> - -#include "mdio-i2c.h" - -/* - * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is - * specified to be present in SFP modules. These correspond with PHY - * addresses 16 and 17. Disallow access to these "phy" addresses. - */ -static bool i2c_mii_valid_phy_id(int phy_id) -{ - return phy_id != 0x10 && phy_id != 0x11; -} - -static unsigned int i2c_mii_phy_addr(int phy_id) -{ - return phy_id + 0x40; -} - -static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct i2c_adapter *i2c = bus->priv; - struct i2c_msg msgs[2]; - u8 addr[3], data[2], *p; - int bus_addr, ret; - - if (!i2c_mii_valid_phy_id(phy_id)) - return 0xffff; - - p = addr; - if (reg & MII_ADDR_C45) { - *p++ = 0x20 | ((reg >> 16) & 31); - *p++ = reg >> 8; - } - *p++ = reg; - - bus_addr = i2c_mii_phy_addr(phy_id); - msgs[0].addr = bus_addr; - msgs[0].flags = 0; - msgs[0].len = p - addr; - msgs[0].buf = addr; - msgs[1].addr = bus_addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(data); - msgs[1].buf = data; - - ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return 0xffff; - - return data[0] << 8 | data[1]; -} - -static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) -{ - struct i2c_adapter *i2c = bus->priv; - struct i2c_msg msg; - int ret; - u8 data[5], *p; - - if (!i2c_mii_valid_phy_id(phy_id)) - return 0; - - p = data; - if (reg & MII_ADDR_C45) { - *p++ = (reg >> 16) & 31; - *p++ = reg >> 8; - } - *p++ = reg; - *p++ = val >> 8; - *p++ = val; - - msg.addr = i2c_mii_phy_addr(phy_id); - msg.flags = 0; - msg.len = p - data; - msg.buf = data; - - ret = i2c_transfer(i2c, &msg, 1); - - return ret < 0 ? ret : 0; -} - -struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) -{ - struct mii_bus *mii; - - if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) - return ERR_PTR(-EINVAL); - - mii = mdiobus_alloc(); - if (!mii) - return ERR_PTR(-ENOMEM); - - snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent)); - mii->parent = parent; - mii->read = i2c_mii_read; - mii->write = i2c_mii_write; - mii->priv = i2c; - - return mii; -} -EXPORT_SYMBOL_GPL(mdio_i2c_alloc); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("MDIO I2C bridge library"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-i2c.h b/drivers/net/phy/mdio-i2c.h deleted file mode 100644 index b1d27f7cd23f..000000000000 --- a/drivers/net/phy/mdio-i2c.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * MDIO I2C bridge - * - * Copyright (C) 2015 Russell King - */ -#ifndef MDIO_I2C_H -#define MDIO_I2C_H - -struct device; -struct i2c_adapter; -struct mii_bus; - -struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); - -#endif diff --git a/drivers/net/phy/mdio-ipq4019.c b/drivers/net/phy/mdio-ipq4019.c deleted file mode 100644 index 1ce81ff2f41d..000000000000 --- a/drivers/net/phy/mdio-ipq4019.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2020 Sartura Ltd. */ - -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> - -#define MDIO_ADDR_REG 0x44 -#define MDIO_DATA_WRITE_REG 0x48 -#define MDIO_DATA_READ_REG 0x4c -#define MDIO_CMD_REG 0x50 -#define MDIO_CMD_ACCESS_BUSY BIT(16) -#define MDIO_CMD_ACCESS_START BIT(8) -#define MDIO_CMD_ACCESS_CODE_READ 0 -#define MDIO_CMD_ACCESS_CODE_WRITE 1 - -#define ipq4019_MDIO_TIMEOUT 10000 -#define ipq4019_MDIO_SLEEP 10 - -struct ipq4019_mdio_data { - void __iomem *membase; -}; - -static int ipq4019_mdio_wait_busy(struct mii_bus *bus) -{ - struct ipq4019_mdio_data *priv = bus->priv; - unsigned int busy; - - return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy, - (busy & MDIO_CMD_ACCESS_BUSY) == 0, - ipq4019_MDIO_SLEEP, ipq4019_MDIO_TIMEOUT); -} - -static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct ipq4019_mdio_data *priv = bus->priv; - unsigned int cmd; - - /* Reject clause 45 */ - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - if (ipq4019_mdio_wait_busy(bus)) - return -ETIMEDOUT; - - /* issue the phy address and reg */ - writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG); - - cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ; - - /* issue read command */ - writel(cmd, priv->membase + MDIO_CMD_REG); - - /* Wait read complete */ - if (ipq4019_mdio_wait_busy(bus)) - return -ETIMEDOUT; - - /* Read and return data */ - return readl(priv->membase + MDIO_DATA_READ_REG); -} - -static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 value) -{ - struct ipq4019_mdio_data *priv = bus->priv; - unsigned int cmd; - - /* Reject clause 45 */ - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - if (ipq4019_mdio_wait_busy(bus)) - return -ETIMEDOUT; - - /* issue the phy address and reg */ - writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG); - - /* issue write data */ - writel(value, priv->membase + MDIO_DATA_WRITE_REG); - - cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE; - /* issue write command */ - writel(cmd, priv->membase + MDIO_CMD_REG); - - /* Wait write complete */ - if (ipq4019_mdio_wait_busy(bus)) - return -ETIMEDOUT; - - return 0; -} - -static int ipq4019_mdio_probe(struct platform_device *pdev) -{ - struct ipq4019_mdio_data *priv; - struct mii_bus *bus; - int ret; - - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); - if (!bus) - return -ENOMEM; - - priv = bus->priv; - - priv->membase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->membase)) - return PTR_ERR(priv->membase); - - bus->name = "ipq4019_mdio"; - bus->read = ipq4019_mdio_read; - bus->write = ipq4019_mdio_write; - bus->parent = &pdev->dev; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id); - - ret = of_mdiobus_register(bus, pdev->dev.of_node); - if (ret) { - dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); - return ret; - } - - platform_set_drvdata(pdev, bus); - - return 0; -} - -static int ipq4019_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - - mdiobus_unregister(bus); - - return 0; -} - -static const struct of_device_id ipq4019_mdio_dt_ids[] = { - { .compatible = "qcom,ipq4019-mdio" }, - { } -}; -MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids); - -static struct platform_driver ipq4019_mdio_driver = { - .probe = ipq4019_mdio_probe, - .remove = ipq4019_mdio_remove, - .driver = { - .name = "ipq4019-mdio", - .of_match_table = ipq4019_mdio_dt_ids, - }, -}; - -module_platform_driver(ipq4019_mdio_driver); - -MODULE_DESCRIPTION("ipq4019 MDIO interface driver"); -MODULE_AUTHOR("Qualcomm Atheros"); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/mdio-ipq8064.c b/drivers/net/phy/mdio-ipq8064.c deleted file mode 100644 index 1bd18857e1c5..000000000000 --- a/drivers/net/phy/mdio-ipq8064.c +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Qualcomm IPQ8064 MDIO interface driver - * - * Copyright (C) 2019 Christian Lamparter <chunkeey@gmail.com> - * Copyright (C) 2020 Ansuel Smith <ansuelsmth@gmail.com> - */ - -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/regmap.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/mfd/syscon.h> - -/* MII address register definitions */ -#define MII_ADDR_REG_ADDR 0x10 -#define MII_BUSY BIT(0) -#define MII_WRITE BIT(1) -#define MII_CLKRANGE_60_100M (0 << 2) -#define MII_CLKRANGE_100_150M (1 << 2) -#define MII_CLKRANGE_20_35M (2 << 2) -#define MII_CLKRANGE_35_60M (3 << 2) -#define MII_CLKRANGE_150_250M (4 << 2) -#define MII_CLKRANGE_250_300M (5 << 2) -#define MII_CLKRANGE_MASK GENMASK(4, 2) -#define MII_REG_SHIFT 6 -#define MII_REG_MASK GENMASK(10, 6) -#define MII_ADDR_SHIFT 11 -#define MII_ADDR_MASK GENMASK(15, 11) - -#define MII_DATA_REG_ADDR 0x14 - -#define MII_MDIO_DELAY_USEC (1000) -#define MII_MDIO_RETRY_MSEC (10) - -struct ipq8064_mdio { - struct regmap *base; /* NSS_GMAC0_BASE */ -}; - -static int -ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv) -{ - u32 busy; - - return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy, - !(busy & MII_BUSY), MII_MDIO_DELAY_USEC, - MII_MDIO_RETRY_MSEC * USEC_PER_MSEC); -} - -static int -ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset) -{ - u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M; - struct ipq8064_mdio *priv = bus->priv; - u32 ret_val; - int err; - - /* Reject clause 45 */ - if (reg_offset & MII_ADDR_C45) - return -EOPNOTSUPP; - - miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | - ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); - - regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); - usleep_range(8, 10); - - err = ipq8064_mdio_wait_busy(priv); - if (err) - return err; - - regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val); - return (int)ret_val; -} - -static int -ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data) -{ - u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M; - struct ipq8064_mdio *priv = bus->priv; - - /* Reject clause 45 */ - if (reg_offset & MII_ADDR_C45) - return -EOPNOTSUPP; - - regmap_write(priv->base, MII_DATA_REG_ADDR, data); - - miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | - ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); - - regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); - usleep_range(8, 10); - - return ipq8064_mdio_wait_busy(priv); -} - -static int -ipq8064_mdio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct ipq8064_mdio *priv; - struct mii_bus *bus; - int ret; - - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); - if (!bus) - return -ENOMEM; - - bus->name = "ipq8064_mdio_bus"; - bus->read = ipq8064_mdio_read; - bus->write = ipq8064_mdio_write; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); - bus->parent = &pdev->dev; - - priv = bus->priv; - priv->base = device_node_to_regmap(np); - if (IS_ERR(priv->base)) { - if (priv->base == ERR_PTR(-EPROBE_DEFER)) - return -EPROBE_DEFER; - - dev_err(&pdev->dev, "error getting device regmap, error=%pe\n", - priv->base); - return PTR_ERR(priv->base); - } - - ret = of_mdiobus_register(bus, np); - if (ret) - return ret; - - platform_set_drvdata(pdev, bus); - return 0; -} - -static int -ipq8064_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - - mdiobus_unregister(bus); - - return 0; -} - -static const struct of_device_id ipq8064_mdio_dt_ids[] = { - { .compatible = "qcom,ipq8064-mdio" }, - { } -}; -MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); - -static struct platform_driver ipq8064_mdio_driver = { - .probe = ipq8064_mdio_probe, - .remove = ipq8064_mdio_remove, - .driver = { - .name = "ipq8064-mdio", - .of_match_table = ipq8064_mdio_dt_ids, - }, -}; - -module_platform_driver(ipq8064_mdio_driver); - -MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver"); -MODULE_AUTHOR("Christian Lamparter <chunkeey@gmail.com>"); -MODULE_AUTHOR("Ansuel Smith <ansuelsmth@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-moxart.c b/drivers/net/phy/mdio-moxart.c deleted file mode 100644 index b72c6d185175..000000000000 --- a/drivers/net/phy/mdio-moxart.c +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* MOXA ART Ethernet (RTL8201CP) MDIO interface driver - * - * Copyright (C) 2013 Jonas Jensen <jonas.jensen@gmail.com> - */ - -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> - -#define REG_PHY_CTRL 0 -#define REG_PHY_WRITE_DATA 4 - -/* REG_PHY_CTRL */ -#define MIIWR BIT(27) /* init write sequence (auto cleared)*/ -#define MIIRD BIT(26) -#define REGAD_MASK 0x3e00000 -#define PHYAD_MASK 0x1f0000 -#define MIIRDATA_MASK 0xffff - -/* REG_PHY_WRITE_DATA */ -#define MIIWDATA_MASK 0xffff - -struct moxart_mdio_data { - void __iomem *base; -}; - -static int moxart_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct moxart_mdio_data *data = bus->priv; - u32 ctrl = 0; - unsigned int count = 5; - - dev_dbg(&bus->dev, "%s\n", __func__); - - ctrl |= MIIRD | ((mii_id << 16) & PHYAD_MASK) | - ((regnum << 21) & REGAD_MASK); - - writel(ctrl, data->base + REG_PHY_CTRL); - - do { - ctrl = readl(data->base + REG_PHY_CTRL); - - if (!(ctrl & MIIRD)) - return ctrl & MIIRDATA_MASK; - - mdelay(10); - count--; - } while (count > 0); - - dev_dbg(&bus->dev, "%s timed out\n", __func__); - - return -ETIMEDOUT; -} - -static int moxart_mdio_write(struct mii_bus *bus, int mii_id, - int regnum, u16 value) -{ - struct moxart_mdio_data *data = bus->priv; - u32 ctrl = 0; - unsigned int count = 5; - - dev_dbg(&bus->dev, "%s\n", __func__); - - ctrl |= MIIWR | ((mii_id << 16) & PHYAD_MASK) | - ((regnum << 21) & REGAD_MASK); - - value &= MIIWDATA_MASK; - - writel(value, data->base + REG_PHY_WRITE_DATA); - writel(ctrl, data->base + REG_PHY_CTRL); - - do { - ctrl = readl(data->base + REG_PHY_CTRL); - - if (!(ctrl & MIIWR)) - return 0; - - mdelay(10); - count--; - } while (count > 0); - - dev_dbg(&bus->dev, "%s timed out\n", __func__); - - return -ETIMEDOUT; -} - -static int moxart_mdio_reset(struct mii_bus *bus) -{ - int data, i; - - for (i = 0; i < PHY_MAX_ADDR; i++) { - data = moxart_mdio_read(bus, i, MII_BMCR); - if (data < 0) - continue; - - data |= BMCR_RESET; - if (moxart_mdio_write(bus, i, MII_BMCR, data) < 0) - continue; - } - - return 0; -} - -static int moxart_mdio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct mii_bus *bus; - struct moxart_mdio_data *data; - int ret, i; - - bus = mdiobus_alloc_size(sizeof(*data)); - if (!bus) - return -ENOMEM; - - bus->name = "MOXA ART Ethernet MII"; - bus->read = &moxart_mdio_read; - bus->write = &moxart_mdio_write; - bus->reset = &moxart_mdio_reset; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id); - bus->parent = &pdev->dev; - - /* Setting PHY_IGNORE_INTERRUPT here even if it has no effect, - * of_mdiobus_register() sets these PHY_POLL. - * Ideally, the interrupt from MAC controller could be used to - * detect link state changes, not polling, i.e. if there was - * a way phy_driver could set PHY_HAS_INTERRUPT but have that - * interrupt handled in ethernet drivercode. - */ - for (i = 0; i < PHY_MAX_ADDR; i++) - bus->irq[i] = PHY_IGNORE_INTERRUPT; - - data = bus->priv; - data->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->base)) { - ret = PTR_ERR(data->base); - goto err_out_free_mdiobus; - } - - ret = of_mdiobus_register(bus, np); - if (ret < 0) - goto err_out_free_mdiobus; - - platform_set_drvdata(pdev, bus); - - return 0; - -err_out_free_mdiobus: - mdiobus_free(bus); - return ret; -} - -static int moxart_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - - mdiobus_unregister(bus); - mdiobus_free(bus); - - return 0; -} - -static const struct of_device_id moxart_mdio_dt_ids[] = { - { .compatible = "moxa,moxart-mdio" }, - { } -}; -MODULE_DEVICE_TABLE(of, moxart_mdio_dt_ids); - -static struct platform_driver moxart_mdio_driver = { - .probe = moxart_mdio_probe, - .remove = moxart_mdio_remove, - .driver = { - .name = "moxart-mdio", - .of_match_table = moxart_mdio_dt_ids, - }, -}; - -module_platform_driver(moxart_mdio_driver); - -MODULE_DESCRIPTION("MOXA ART MDIO interface driver"); -MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mscc-miim.c b/drivers/net/phy/mdio-mscc-miim.c deleted file mode 100644 index 11f583fd4611..000000000000 --- a/drivers/net/phy/mdio-mscc-miim.c +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MIT) -/* - * Driver for the MDIO interface of Microsemi network switches. - * - * Author: Alexandre Belloni <alexandre.belloni@bootlin.com> - * Copyright (c) 2017 Microsemi Corporation - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/bitops.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/of_mdio.h> - -#define MSCC_MIIM_REG_STATUS 0x0 -#define MSCC_MIIM_STATUS_STAT_PENDING BIT(2) -#define MSCC_MIIM_STATUS_STAT_BUSY BIT(3) -#define MSCC_MIIM_REG_CMD 0x8 -#define MSCC_MIIM_CMD_OPR_WRITE BIT(1) -#define MSCC_MIIM_CMD_OPR_READ BIT(2) -#define MSCC_MIIM_CMD_WRDATA_SHIFT 4 -#define MSCC_MIIM_CMD_REGAD_SHIFT 20 -#define MSCC_MIIM_CMD_PHYAD_SHIFT 25 -#define MSCC_MIIM_CMD_VLD BIT(31) -#define MSCC_MIIM_REG_DATA 0xC -#define MSCC_MIIM_DATA_ERROR (BIT(16) | BIT(17)) - -#define MSCC_PHY_REG_PHY_CFG 0x0 -#define PHY_CFG_PHY_ENA (BIT(0) | BIT(1) | BIT(2) | BIT(3)) -#define PHY_CFG_PHY_COMMON_RESET BIT(4) -#define PHY_CFG_PHY_RESET (BIT(5) | BIT(6) | BIT(7) | BIT(8)) -#define MSCC_PHY_REG_PHY_STATUS 0x4 - -struct mscc_miim_dev { - void __iomem *regs; - void __iomem *phy_regs; -}; - -/* When high resolution timers aren't built-in: we can't use usleep_range() as - * we would sleep way too long. Use udelay() instead. - */ -#define mscc_readl_poll_timeout(addr, val, cond, delay_us, timeout_us) \ -({ \ - if (!IS_ENABLED(CONFIG_HIGH_RES_TIMERS)) \ - readl_poll_timeout_atomic(addr, val, cond, delay_us, \ - timeout_us); \ - readl_poll_timeout(addr, val, cond, delay_us, timeout_us); \ -}) - -static int mscc_miim_wait_ready(struct mii_bus *bus) -{ - struct mscc_miim_dev *miim = bus->priv; - u32 val; - - return mscc_readl_poll_timeout(miim->regs + MSCC_MIIM_REG_STATUS, val, - !(val & MSCC_MIIM_STATUS_STAT_BUSY), 50, - 10000); -} - -static int mscc_miim_wait_pending(struct mii_bus *bus) -{ - struct mscc_miim_dev *miim = bus->priv; - u32 val; - - return mscc_readl_poll_timeout(miim->regs + MSCC_MIIM_REG_STATUS, val, - !(val & MSCC_MIIM_STATUS_STAT_PENDING), - 50, 10000); -} - -static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct mscc_miim_dev *miim = bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_pending(bus); - if (ret) - goto out; - - writel(MSCC_MIIM_CMD_VLD | (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) | - (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) | MSCC_MIIM_CMD_OPR_READ, - miim->regs + MSCC_MIIM_REG_CMD); - - ret = mscc_miim_wait_ready(bus); - if (ret) - goto out; - - val = readl(miim->regs + MSCC_MIIM_REG_DATA); - if (val & MSCC_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; -out: - return ret; -} - -static int mscc_miim_write(struct mii_bus *bus, int mii_id, - int regnum, u16 value) -{ - struct mscc_miim_dev *miim = bus->priv; - int ret; - - ret = mscc_miim_wait_pending(bus); - if (ret < 0) - goto out; - - writel(MSCC_MIIM_CMD_VLD | (mii_id << MSCC_MIIM_CMD_PHYAD_SHIFT) | - (regnum << MSCC_MIIM_CMD_REGAD_SHIFT) | - (value << MSCC_MIIM_CMD_WRDATA_SHIFT) | - MSCC_MIIM_CMD_OPR_WRITE, - miim->regs + MSCC_MIIM_REG_CMD); - -out: - return ret; -} - -static int mscc_miim_reset(struct mii_bus *bus) -{ - struct mscc_miim_dev *miim = bus->priv; - - if (miim->phy_regs) { - writel(0, miim->phy_regs + MSCC_PHY_REG_PHY_CFG); - writel(0x1ff, miim->phy_regs + MSCC_PHY_REG_PHY_CFG); - mdelay(500); - } - - return 0; -} - -static int mscc_miim_probe(struct platform_device *pdev) -{ - struct resource *res; - struct mii_bus *bus; - struct mscc_miim_dev *dev; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*dev)); - if (!bus) - return -ENOMEM; - - bus->name = "mscc_miim"; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - bus->reset = mscc_miim_reset; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); - bus->parent = &pdev->dev; - - dev = bus->priv; - dev->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->regs)) { - dev_err(&pdev->dev, "Unable to map MIIM registers\n"); - return PTR_ERR(dev->regs); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) { - dev->phy_regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->phy_regs)) { - dev_err(&pdev->dev, "Unable to map internal phy registers\n"); - return PTR_ERR(dev->phy_regs); - } - } - - ret = of_mdiobus_register(bus, pdev->dev.of_node); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); - return ret; - } - - platform_set_drvdata(pdev, bus); - - return 0; -} - -static int mscc_miim_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - - mdiobus_unregister(bus); - - return 0; -} - -static const struct of_device_id mscc_miim_match[] = { - { .compatible = "mscc,ocelot-miim" }, - { } -}; -MODULE_DEVICE_TABLE(of, mscc_miim_match); - -static struct platform_driver mscc_miim_driver = { - .probe = mscc_miim_probe, - .remove = mscc_miim_remove, - .driver = { - .name = "mscc-miim", - .of_match_table = mscc_miim_match, - }, -}; - -module_platform_driver(mscc_miim_driver); - -MODULE_DESCRIPTION("Microsemi MIIM driver"); -MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>"); -MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c deleted file mode 100644 index 42fb5f166136..000000000000 --- a/drivers/net/phy/mdio-mux-bcm-iproc.c +++ /dev/null @@ -1,323 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright 2016 Broadcom - */ -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/device.h> -#include <linux/of_mdio.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/mdio-mux.h> -#include <linux/delay.h> -#include <linux/iopoll.h> - -#define MDIO_RATE_ADJ_EXT_OFFSET 0x000 -#define MDIO_RATE_ADJ_INT_OFFSET 0x004 -#define MDIO_RATE_ADJ_DIVIDENT_SHIFT 16 - -#define MDIO_SCAN_CTRL_OFFSET 0x008 -#define MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR 28 - -#define MDIO_PARAM_OFFSET 0x23c -#define MDIO_PARAM_MIIM_CYCLE 29 -#define MDIO_PARAM_INTERNAL_SEL 25 -#define MDIO_PARAM_BUS_ID 22 -#define MDIO_PARAM_C45_SEL 21 -#define MDIO_PARAM_PHY_ID 16 -#define MDIO_PARAM_PHY_DATA 0 - -#define MDIO_READ_OFFSET 0x240 -#define MDIO_READ_DATA_MASK 0xffff -#define MDIO_ADDR_OFFSET 0x244 - -#define MDIO_CTRL_OFFSET 0x248 -#define MDIO_CTRL_WRITE_OP 0x1 -#define MDIO_CTRL_READ_OP 0x2 - -#define MDIO_STAT_OFFSET 0x24c -#define MDIO_STAT_DONE 1 - -#define BUS_MAX_ADDR 32 -#define EXT_BUS_START_ADDR 16 - -#define MDIO_REG_ADDR_SPACE_SIZE 0x250 - -#define MDIO_OPERATING_FREQUENCY 11000000 -#define MDIO_RATE_ADJ_DIVIDENT 1 - -struct iproc_mdiomux_desc { - void *mux_handle; - void __iomem *base; - struct device *dev; - struct mii_bus *mii_bus; - struct clk *core_clk; -}; - -static void mdio_mux_iproc_config(struct iproc_mdiomux_desc *md) -{ - u32 divisor; - u32 val; - - /* Disable external mdio master access */ - val = readl(md->base + MDIO_SCAN_CTRL_OFFSET); - val |= BIT(MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR); - writel(val, md->base + MDIO_SCAN_CTRL_OFFSET); - - if (md->core_clk) { - /* use rate adjust regs to derrive the mdio's operating - * frequency from the specified core clock - */ - divisor = clk_get_rate(md->core_clk) / MDIO_OPERATING_FREQUENCY; - divisor = divisor / (MDIO_RATE_ADJ_DIVIDENT + 1); - val = divisor; - val |= MDIO_RATE_ADJ_DIVIDENT << MDIO_RATE_ADJ_DIVIDENT_SHIFT; - writel(val, md->base + MDIO_RATE_ADJ_EXT_OFFSET); - writel(val, md->base + MDIO_RATE_ADJ_INT_OFFSET); - } -} - -static int iproc_mdio_wait_for_idle(void __iomem *base, bool result) -{ - u32 val; - - return readl_poll_timeout(base + MDIO_STAT_OFFSET, val, - (val & MDIO_STAT_DONE) == result, - 2000, 1000000); -} - -/* start_miim_ops- Program and start MDIO transaction over mdio bus. - * @base: Base address - * @phyid: phyid of the selected bus. - * @reg: register offset to be read/written. - * @val :0 if read op else value to be written in @reg; - * @op: Operation that need to be carried out. - * MDIO_CTRL_READ_OP: Read transaction. - * MDIO_CTRL_WRITE_OP: Write transaction. - * - * Return value: Successful Read operation returns read reg values and write - * operation returns 0. Failure operation returns negative error code. - */ -static int start_miim_ops(void __iomem *base, - u16 phyid, u32 reg, u16 val, u32 op) -{ - u32 param; - int ret; - - writel(0, base + MDIO_CTRL_OFFSET); - ret = iproc_mdio_wait_for_idle(base, 0); - if (ret) - goto err; - - param = readl(base + MDIO_PARAM_OFFSET); - param |= phyid << MDIO_PARAM_PHY_ID; - param |= val << MDIO_PARAM_PHY_DATA; - if (reg & MII_ADDR_C45) - param |= BIT(MDIO_PARAM_C45_SEL); - - writel(param, base + MDIO_PARAM_OFFSET); - - writel(reg, base + MDIO_ADDR_OFFSET); - - writel(op, base + MDIO_CTRL_OFFSET); - - ret = iproc_mdio_wait_for_idle(base, 1); - if (ret) - goto err; - - if (op == MDIO_CTRL_READ_OP) - ret = readl(base + MDIO_READ_OFFSET) & MDIO_READ_DATA_MASK; -err: - return ret; -} - -static int iproc_mdiomux_read(struct mii_bus *bus, int phyid, int reg) -{ - struct iproc_mdiomux_desc *md = bus->priv; - int ret; - - ret = start_miim_ops(md->base, phyid, reg, 0, MDIO_CTRL_READ_OP); - if (ret < 0) - dev_err(&bus->dev, "mdiomux read operation failed!!!"); - - return ret; -} - -static int iproc_mdiomux_write(struct mii_bus *bus, - int phyid, int reg, u16 val) -{ - struct iproc_mdiomux_desc *md = bus->priv; - int ret; - - /* Write val at reg offset */ - ret = start_miim_ops(md->base, phyid, reg, val, MDIO_CTRL_WRITE_OP); - if (ret < 0) - dev_err(&bus->dev, "mdiomux write operation failed!!!"); - - return ret; -} - -static int mdio_mux_iproc_switch_fn(int current_child, int desired_child, - void *data) -{ - struct iproc_mdiomux_desc *md = data; - u32 param, bus_id; - bool bus_dir; - - /* select bus and its properties */ - bus_dir = (desired_child < EXT_BUS_START_ADDR); - bus_id = bus_dir ? desired_child : (desired_child - EXT_BUS_START_ADDR); - - param = (bus_dir ? 1 : 0) << MDIO_PARAM_INTERNAL_SEL; - param |= (bus_id << MDIO_PARAM_BUS_ID); - - writel(param, md->base + MDIO_PARAM_OFFSET); - return 0; -} - -static int mdio_mux_iproc_probe(struct platform_device *pdev) -{ - struct iproc_mdiomux_desc *md; - struct mii_bus *bus; - struct resource *res; - int rc; - - md = devm_kzalloc(&pdev->dev, sizeof(*md), GFP_KERNEL); - if (!md) - return -ENOMEM; - md->dev = &pdev->dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res->start & 0xfff) { - /* For backward compatibility in case the - * base address is specified with an offset. - */ - dev_info(&pdev->dev, "fix base address in dt-blob\n"); - res->start &= ~0xfff; - res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1; - } - md->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(md->base)) { - dev_err(&pdev->dev, "failed to ioremap register\n"); - return PTR_ERR(md->base); - } - - md->mii_bus = devm_mdiobus_alloc(&pdev->dev); - if (!md->mii_bus) { - dev_err(&pdev->dev, "mdiomux bus alloc failed\n"); - return -ENOMEM; - } - - md->core_clk = devm_clk_get(&pdev->dev, NULL); - if (md->core_clk == ERR_PTR(-ENOENT) || - md->core_clk == ERR_PTR(-EINVAL)) - md->core_clk = NULL; - else if (IS_ERR(md->core_clk)) - return PTR_ERR(md->core_clk); - - rc = clk_prepare_enable(md->core_clk); - if (rc) { - dev_err(&pdev->dev, "failed to enable core clk\n"); - return rc; - } - - bus = md->mii_bus; - bus->priv = md; - bus->name = "iProc MDIO mux bus"; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); - bus->parent = &pdev->dev; - bus->read = iproc_mdiomux_read; - bus->write = iproc_mdiomux_write; - - bus->phy_mask = ~0; - bus->dev.of_node = pdev->dev.of_node; - rc = mdiobus_register(bus); - if (rc) { - dev_err(&pdev->dev, "mdiomux registration failed\n"); - goto out_clk; - } - - platform_set_drvdata(pdev, md); - - rc = mdio_mux_init(md->dev, md->dev->of_node, mdio_mux_iproc_switch_fn, - &md->mux_handle, md, md->mii_bus); - if (rc) { - dev_info(md->dev, "mdiomux initialization failed\n"); - goto out_register; - } - - mdio_mux_iproc_config(md); - - dev_info(md->dev, "iProc mdiomux registered\n"); - return 0; - -out_register: - mdiobus_unregister(bus); -out_clk: - clk_disable_unprepare(md->core_clk); - return rc; -} - -static int mdio_mux_iproc_remove(struct platform_device *pdev) -{ - struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev); - - mdio_mux_uninit(md->mux_handle); - mdiobus_unregister(md->mii_bus); - clk_disable_unprepare(md->core_clk); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int mdio_mux_iproc_suspend(struct device *dev) -{ - struct iproc_mdiomux_desc *md = dev_get_drvdata(dev); - - clk_disable_unprepare(md->core_clk); - - return 0; -} - -static int mdio_mux_iproc_resume(struct device *dev) -{ - struct iproc_mdiomux_desc *md = dev_get_drvdata(dev); - int rc; - - rc = clk_prepare_enable(md->core_clk); - if (rc) { - dev_err(md->dev, "failed to enable core clk\n"); - return rc; - } - mdio_mux_iproc_config(md); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(mdio_mux_iproc_pm_ops, - mdio_mux_iproc_suspend, mdio_mux_iproc_resume); - -static const struct of_device_id mdio_mux_iproc_match[] = { - { - .compatible = "brcm,mdio-mux-iproc", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mdio_mux_iproc_match); - -static struct platform_driver mdiomux_iproc_driver = { - .driver = { - .name = "mdio-mux-iproc", - .of_match_table = mdio_mux_iproc_match, - .pm = &mdio_mux_iproc_pm_ops, - }, - .probe = mdio_mux_iproc_probe, - .remove = mdio_mux_iproc_remove, -}; - -module_platform_driver(mdiomux_iproc_driver); - -MODULE_DESCRIPTION("iProc MDIO Mux Bus Driver"); -MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c deleted file mode 100644 index 10a758fdc9e6..000000000000 --- a/drivers/net/phy/mdio-mux-gpio.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011, 2012 Cavium, Inc. - */ - -#include <linux/platform_device.h> -#include <linux/device.h> -#include <linux/of_mdio.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/mdio-mux.h> -#include <linux/gpio/consumer.h> - -#define DRV_VERSION "1.1" -#define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver" - -struct mdio_mux_gpio_state { - struct gpio_descs *gpios; - void *mux_handle; -}; - -static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, - void *data) -{ - struct mdio_mux_gpio_state *s = data; - DECLARE_BITMAP(values, BITS_PER_TYPE(desired_child)); - - if (current_child == desired_child) - return 0; - - values[0] = desired_child; - - gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc, - s->gpios->info, values); - - return 0; -} - -static int mdio_mux_gpio_probe(struct platform_device *pdev) -{ - struct mdio_mux_gpio_state *s; - struct gpio_descs *gpios; - int r; - - gpios = devm_gpiod_get_array(&pdev->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(gpios)) - return PTR_ERR(gpios); - - s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - s->gpios = gpios; - - r = mdio_mux_init(&pdev->dev, pdev->dev.of_node, - mdio_mux_gpio_switch_fn, &s->mux_handle, s, NULL); - - if (r != 0) - return r; - - pdev->dev.platform_data = s; - return 0; -} - -static int mdio_mux_gpio_remove(struct platform_device *pdev) -{ - struct mdio_mux_gpio_state *s = dev_get_platdata(&pdev->dev); - mdio_mux_uninit(s->mux_handle); - return 0; -} - -static const struct of_device_id mdio_mux_gpio_match[] = { - { - .compatible = "mdio-mux-gpio", - }, - { - /* Legacy compatible property. */ - .compatible = "cavium,mdio-mux-sn74cbtlv3253", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mdio_mux_gpio_match); - -static struct platform_driver mdio_mux_gpio_driver = { - .driver = { - .name = "mdio-mux-gpio", - .of_match_table = mdio_mux_gpio_match, - }, - .probe = mdio_mux_gpio_probe, - .remove = mdio_mux_gpio_remove, -}; - -module_platform_driver(mdio_mux_gpio_driver); - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR("David Daney"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c deleted file mode 100644 index bf86c9c7a288..000000000000 --- a/drivers/net/phy/mdio-mux-meson-g12a.c +++ /dev/null @@ -1,380 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2019 Baylibre, SAS. - * Author: Jerome Brunet <jbrunet@baylibre.com> - */ - -#include <linux/bitfield.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/device.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/mdio-mux.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/platform_device.h> - -#define ETH_PLL_STS 0x40 -#define ETH_PLL_CTL0 0x44 -#define PLL_CTL0_LOCK_DIG BIT(30) -#define PLL_CTL0_RST BIT(29) -#define PLL_CTL0_EN BIT(28) -#define PLL_CTL0_SEL BIT(23) -#define PLL_CTL0_N GENMASK(14, 10) -#define PLL_CTL0_M GENMASK(8, 0) -#define PLL_LOCK_TIMEOUT 1000000 -#define PLL_MUX_NUM_PARENT 2 -#define ETH_PLL_CTL1 0x48 -#define ETH_PLL_CTL2 0x4c -#define ETH_PLL_CTL3 0x50 -#define ETH_PLL_CTL4 0x54 -#define ETH_PLL_CTL5 0x58 -#define ETH_PLL_CTL6 0x5c -#define ETH_PLL_CTL7 0x60 - -#define ETH_PHY_CNTL0 0x80 -#define EPHY_G12A_ID 0x33010180 -#define ETH_PHY_CNTL1 0x84 -#define PHY_CNTL1_ST_MODE GENMASK(2, 0) -#define PHY_CNTL1_ST_PHYADD GENMASK(7, 3) -#define EPHY_DFLT_ADD 8 -#define PHY_CNTL1_MII_MODE GENMASK(15, 14) -#define EPHY_MODE_RMII 0x1 -#define PHY_CNTL1_CLK_EN BIT(16) -#define PHY_CNTL1_CLKFREQ BIT(17) -#define PHY_CNTL1_PHY_ENB BIT(18) -#define ETH_PHY_CNTL2 0x88 -#define PHY_CNTL2_USE_INTERNAL BIT(5) -#define PHY_CNTL2_SMI_SRC_MAC BIT(6) -#define PHY_CNTL2_RX_CLK_EPHY BIT(9) - -#define MESON_G12A_MDIO_EXTERNAL_ID 0 -#define MESON_G12A_MDIO_INTERNAL_ID 1 - -struct g12a_mdio_mux { - bool pll_is_enabled; - void __iomem *regs; - void *mux_handle; - struct clk *pclk; - struct clk *pll; -}; - -struct g12a_ephy_pll { - void __iomem *base; - struct clk_hw hw; -}; - -#define g12a_ephy_pll_to_dev(_hw) \ - container_of(_hw, struct g12a_ephy_pll, hw) - -static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); - u32 val, m, n; - - val = readl(pll->base + ETH_PLL_CTL0); - m = FIELD_GET(PLL_CTL0_M, val); - n = FIELD_GET(PLL_CTL0_N, val); - - return parent_rate * m / n; -} - -static int g12a_ephy_pll_enable(struct clk_hw *hw) -{ - struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); - u32 val = readl(pll->base + ETH_PLL_CTL0); - - /* Apply both enable an reset */ - val |= PLL_CTL0_RST | PLL_CTL0_EN; - writel(val, pll->base + ETH_PLL_CTL0); - - /* Clear the reset to let PLL lock */ - val &= ~PLL_CTL0_RST; - writel(val, pll->base + ETH_PLL_CTL0); - - /* Poll on the digital lock instead of the usual analog lock - * This is done because bit 31 is unreliable on some SoC. Bit - * 31 may indicate that the PLL is not lock eventhough the clock - * is actually running - */ - return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val, - val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT); -} - -static void g12a_ephy_pll_disable(struct clk_hw *hw) -{ - struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); - u32 val; - - val = readl(pll->base + ETH_PLL_CTL0); - val &= ~PLL_CTL0_EN; - val |= PLL_CTL0_RST; - writel(val, pll->base + ETH_PLL_CTL0); -} - -static int g12a_ephy_pll_is_enabled(struct clk_hw *hw) -{ - struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); - unsigned int val; - - val = readl(pll->base + ETH_PLL_CTL0); - - return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0; -} - -static int g12a_ephy_pll_init(struct clk_hw *hw) -{ - struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); - - /* Apply PLL HW settings */ - writel(0x29c0040a, pll->base + ETH_PLL_CTL0); - writel(0x927e0000, pll->base + ETH_PLL_CTL1); - writel(0xac5f49e5, pll->base + ETH_PLL_CTL2); - writel(0x00000000, pll->base + ETH_PLL_CTL3); - writel(0x00000000, pll->base + ETH_PLL_CTL4); - writel(0x20200000, pll->base + ETH_PLL_CTL5); - writel(0x0000c002, pll->base + ETH_PLL_CTL6); - writel(0x00000023, pll->base + ETH_PLL_CTL7); - - return 0; -} - -static const struct clk_ops g12a_ephy_pll_ops = { - .recalc_rate = g12a_ephy_pll_recalc_rate, - .is_enabled = g12a_ephy_pll_is_enabled, - .enable = g12a_ephy_pll_enable, - .disable = g12a_ephy_pll_disable, - .init = g12a_ephy_pll_init, -}; - -static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) -{ - int ret; - - /* Enable the phy clock */ - if (!priv->pll_is_enabled) { - ret = clk_prepare_enable(priv->pll); - if (ret) - return ret; - } - - priv->pll_is_enabled = true; - - /* Initialize ephy control */ - writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0); - writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | - FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | - FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | - PHY_CNTL1_CLK_EN | - PHY_CNTL1_CLKFREQ | - PHY_CNTL1_PHY_ENB, - priv->regs + ETH_PHY_CNTL1); - writel(PHY_CNTL2_USE_INTERNAL | - PHY_CNTL2_SMI_SRC_MAC | - PHY_CNTL2_RX_CLK_EPHY, - priv->regs + ETH_PHY_CNTL2); - - return 0; -} - -static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv) -{ - /* Reset the mdio bus mux */ - writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2); - - /* Disable the phy clock if enabled */ - if (priv->pll_is_enabled) { - clk_disable_unprepare(priv->pll); - priv->pll_is_enabled = false; - } - - return 0; -} - -static int g12a_mdio_switch_fn(int current_child, int desired_child, - void *data) -{ - struct g12a_mdio_mux *priv = dev_get_drvdata(data); - - if (current_child == desired_child) - return 0; - - switch (desired_child) { - case MESON_G12A_MDIO_EXTERNAL_ID: - return g12a_enable_external_mdio(priv); - case MESON_G12A_MDIO_INTERNAL_ID: - return g12a_enable_internal_mdio(priv); - default: - return -EINVAL; - } -} - -static const struct of_device_id g12a_mdio_mux_match[] = { - { .compatible = "amlogic,g12a-mdio-mux", }, - {}, -}; -MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match); - -static int g12a_ephy_glue_clk_register(struct device *dev) -{ - struct g12a_mdio_mux *priv = dev_get_drvdata(dev); - const char *parent_names[PLL_MUX_NUM_PARENT]; - struct clk_init_data init; - struct g12a_ephy_pll *pll; - struct clk_mux *mux; - struct clk *clk; - char *name; - int i; - - /* get the mux parents */ - for (i = 0; i < PLL_MUX_NUM_PARENT; i++) { - char in_name[8]; - - snprintf(in_name, sizeof(in_name), "clkin%d", i); - clk = devm_clk_get(dev, in_name); - if (IS_ERR(clk)) { - if (PTR_ERR(clk) != -EPROBE_DEFER) - dev_err(dev, "Missing clock %s\n", in_name); - return PTR_ERR(clk); - } - - parent_names[i] = __clk_get_name(clk); - } - - /* create the input mux */ - mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); - if (!mux) - return -ENOMEM; - - name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev)); - if (!name) - return -ENOMEM; - - init.name = name; - init.ops = &clk_mux_ro_ops; - init.flags = 0; - init.parent_names = parent_names; - init.num_parents = PLL_MUX_NUM_PARENT; - - mux->reg = priv->regs + ETH_PLL_CTL0; - mux->shift = __ffs(PLL_CTL0_SEL); - mux->mask = PLL_CTL0_SEL >> mux->shift; - mux->hw.init = &init; - - clk = devm_clk_register(dev, &mux->hw); - kfree(name); - if (IS_ERR(clk)) { - dev_err(dev, "failed to register input mux\n"); - return PTR_ERR(clk); - } - - /* create the pll */ - pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); - if (!pll) - return -ENOMEM; - - name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev)); - if (!name) - return -ENOMEM; - - init.name = name; - init.ops = &g12a_ephy_pll_ops; - init.flags = 0; - parent_names[0] = __clk_get_name(clk); - init.parent_names = parent_names; - init.num_parents = 1; - - pll->base = priv->regs; - pll->hw.init = &init; - - clk = devm_clk_register(dev, &pll->hw); - kfree(name); - if (IS_ERR(clk)) { - dev_err(dev, "failed to register input mux\n"); - return PTR_ERR(clk); - } - - priv->pll = clk; - - return 0; -} - -static int g12a_mdio_mux_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct g12a_mdio_mux *priv; - int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - platform_set_drvdata(pdev, priv); - - priv->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->regs)) - return PTR_ERR(priv->regs); - - priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - ret = PTR_ERR(priv->pclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get peripheral clock\n"); - return ret; - } - - /* Make sure the device registers are clocked */ - ret = clk_prepare_enable(priv->pclk); - if (ret) { - dev_err(dev, "failed to enable peripheral clock"); - return ret; - } - - /* Register PLL in CCF */ - ret = g12a_ephy_glue_clk_register(dev); - if (ret) - goto err; - - ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn, - &priv->mux_handle, dev, NULL); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "mdio multiplexer init failed: %d", ret); - goto err; - } - - return 0; - -err: - clk_disable_unprepare(priv->pclk); - return ret; -} - -static int g12a_mdio_mux_remove(struct platform_device *pdev) -{ - struct g12a_mdio_mux *priv = platform_get_drvdata(pdev); - - mdio_mux_uninit(priv->mux_handle); - - if (priv->pll_is_enabled) - clk_disable_unprepare(priv->pll); - - clk_disable_unprepare(priv->pclk); - - return 0; -} - -static struct platform_driver g12a_mdio_mux_driver = { - .probe = g12a_mdio_mux_probe, - .remove = g12a_mdio_mux_remove, - .driver = { - .name = "g12a-mdio_mux", - .of_match_table = g12a_mdio_mux_match, - }, -}; -module_platform_driver(g12a_mdio_mux_driver); - -MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver"); -MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mux-mmioreg.c b/drivers/net/phy/mdio-mux-mmioreg.c deleted file mode 100644 index d1a8780e24d8..000000000000 --- a/drivers/net/phy/mdio-mux-mmioreg.c +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Simple memory-mapped device MDIO MUX driver - * - * Author: Timur Tabi <timur@freescale.com> - * - * Copyright 2012 Freescale Semiconductor, Inc. - */ - -#include <linux/platform_device.h> -#include <linux/device.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/module.h> -#include <linux/phy.h> -#include <linux/mdio-mux.h> - -struct mdio_mux_mmioreg_state { - void *mux_handle; - phys_addr_t phys; - unsigned int iosize; - unsigned int mask; -}; - -/* - * MDIO multiplexing switch function - * - * This function is called by the mdio-mux layer when it thinks the mdio bus - * multiplexer needs to switch. - * - * 'current_child' is the current value of the mux register (masked via - * s->mask). - * - * 'desired_child' is the value of the 'reg' property of the target child MDIO - * node. - * - * The first time this function is called, current_child == -1. - * - * If current_child == desired_child, then the mux is already set to the - * correct bus. - */ -static int mdio_mux_mmioreg_switch_fn(int current_child, int desired_child, - void *data) -{ - struct mdio_mux_mmioreg_state *s = data; - - if (current_child ^ desired_child) { - void __iomem *p = ioremap(s->phys, s->iosize); - if (!p) - return -ENOMEM; - - switch (s->iosize) { - case sizeof(uint8_t): { - uint8_t x, y; - - x = ioread8(p); - y = (x & ~s->mask) | desired_child; - if (x != y) { - iowrite8((x & ~s->mask) | desired_child, p); - pr_debug("%s: %02x -> %02x\n", __func__, x, y); - } - - break; - } - case sizeof(uint16_t): { - uint16_t x, y; - - x = ioread16(p); - y = (x & ~s->mask) | desired_child; - if (x != y) { - iowrite16((x & ~s->mask) | desired_child, p); - pr_debug("%s: %04x -> %04x\n", __func__, x, y); - } - - break; - } - case sizeof(uint32_t): { - uint32_t x, y; - - x = ioread32(p); - y = (x & ~s->mask) | desired_child; - if (x != y) { - iowrite32((x & ~s->mask) | desired_child, p); - pr_debug("%s: %08x -> %08x\n", __func__, x, y); - } - - break; - } - } - - iounmap(p); - } - - return 0; -} - -static int mdio_mux_mmioreg_probe(struct platform_device *pdev) -{ - struct device_node *np2, *np = pdev->dev.of_node; - struct mdio_mux_mmioreg_state *s; - struct resource res; - const __be32 *iprop; - int len, ret; - - dev_dbg(&pdev->dev, "probing node %pOF\n", np); - - s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - ret = of_address_to_resource(np, 0, &res); - if (ret) { - dev_err(&pdev->dev, "could not obtain memory map for node %pOF\n", - np); - return ret; - } - s->phys = res.start; - - s->iosize = resource_size(&res); - if (s->iosize != sizeof(uint8_t) && - s->iosize != sizeof(uint16_t) && - s->iosize != sizeof(uint32_t)) { - dev_err(&pdev->dev, "only 8/16/32-bit registers are supported\n"); - return -EINVAL; - } - - iprop = of_get_property(np, "mux-mask", &len); - if (!iprop || len != sizeof(uint32_t)) { - dev_err(&pdev->dev, "missing or invalid mux-mask property\n"); - return -ENODEV; - } - if (be32_to_cpup(iprop) >= BIT(s->iosize * 8)) { - dev_err(&pdev->dev, "only 8/16/32-bit registers are supported\n"); - return -EINVAL; - } - s->mask = be32_to_cpup(iprop); - - /* - * Verify that the 'reg' property of each child MDIO bus does not - * set any bits outside of the 'mask'. - */ - for_each_available_child_of_node(np, np2) { - iprop = of_get_property(np2, "reg", &len); - if (!iprop || len != sizeof(uint32_t)) { - dev_err(&pdev->dev, "mdio-mux child node %pOF is " - "missing a 'reg' property\n", np2); - of_node_put(np2); - return -ENODEV; - } - if (be32_to_cpup(iprop) & ~s->mask) { - dev_err(&pdev->dev, "mdio-mux child node %pOF has " - "a 'reg' value with unmasked bits\n", - np2); - of_node_put(np2); - return -ENODEV; - } - } - - ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node, - mdio_mux_mmioreg_switch_fn, - &s->mux_handle, s, NULL); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to register mdio-mux bus %pOF\n", np); - return ret; - } - - pdev->dev.platform_data = s; - - return 0; -} - -static int mdio_mux_mmioreg_remove(struct platform_device *pdev) -{ - struct mdio_mux_mmioreg_state *s = dev_get_platdata(&pdev->dev); - - mdio_mux_uninit(s->mux_handle); - - return 0; -} - -static const struct of_device_id mdio_mux_mmioreg_match[] = { - { - .compatible = "mdio-mux-mmioreg", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mdio_mux_mmioreg_match); - -static struct platform_driver mdio_mux_mmioreg_driver = { - .driver = { - .name = "mdio-mux-mmioreg", - .of_match_table = mdio_mux_mmioreg_match, - }, - .probe = mdio_mux_mmioreg_probe, - .remove = mdio_mux_mmioreg_remove, -}; - -module_platform_driver(mdio_mux_mmioreg_driver); - -MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); -MODULE_DESCRIPTION("Memory-mapped device MDIO MUX driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mux-multiplexer.c b/drivers/net/phy/mdio-mux-multiplexer.c deleted file mode 100644 index d6564381aa3e..000000000000 --- a/drivers/net/phy/mdio-mux-multiplexer.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* MDIO bus multiplexer using kernel multiplexer subsystem - * - * Copyright 2019 NXP - */ - -#include <linux/platform_device.h> -#include <linux/mdio-mux.h> -#include <linux/module.h> -#include <linux/mux/consumer.h> - -struct mdio_mux_multiplexer_state { - struct mux_control *muxc; - bool do_deselect; - void *mux_handle; -}; - -/** - * mdio_mux_multiplexer_switch_fn - This function is called by the mdio-mux - * layer when it thinks the mdio bus - * multiplexer needs to switch. - * @current_child: current value of the mux register. - * @desired_child: value of the 'reg' property of the target child MDIO node. - * @data: Private data used by this switch_fn passed to mdio_mux_init function - * via mdio_mux_init(.., .., .., .., data, ..). - * - * The first time this function is called, current_child == -1. - * If current_child == desired_child, then the mux is already set to the - * correct bus. - */ -static int mdio_mux_multiplexer_switch_fn(int current_child, int desired_child, - void *data) -{ - struct platform_device *pdev; - struct mdio_mux_multiplexer_state *s; - int ret = 0; - - pdev = (struct platform_device *)data; - s = platform_get_drvdata(pdev); - - if (!(current_child ^ desired_child)) - return 0; - - if (s->do_deselect) - ret = mux_control_deselect(s->muxc); - if (ret) { - dev_err(&pdev->dev, "mux_control_deselect failed in %s: %d\n", - __func__, ret); - return ret; - } - - ret = mux_control_select(s->muxc, desired_child); - if (!ret) { - dev_dbg(&pdev->dev, "%s %d -> %d\n", __func__, current_child, - desired_child); - s->do_deselect = true; - } else { - s->do_deselect = false; - } - - return ret; -} - -static int mdio_mux_multiplexer_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mdio_mux_multiplexer_state *s; - int ret = 0; - - s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - s->muxc = devm_mux_control_get(dev, NULL); - if (IS_ERR(s->muxc)) { - ret = PTR_ERR(s->muxc); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get mux: %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, s); - - ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node, - mdio_mux_multiplexer_switch_fn, &s->mux_handle, - pdev, NULL); - - return ret; -} - -static int mdio_mux_multiplexer_remove(struct platform_device *pdev) -{ - struct mdio_mux_multiplexer_state *s = platform_get_drvdata(pdev); - - mdio_mux_uninit(s->mux_handle); - - if (s->do_deselect) - mux_control_deselect(s->muxc); - - return 0; -} - -static const struct of_device_id mdio_mux_multiplexer_match[] = { - { .compatible = "mdio-mux-multiplexer", }, - {}, -}; -MODULE_DEVICE_TABLE(of, mdio_mux_multiplexer_match); - -static struct platform_driver mdio_mux_multiplexer_driver = { - .driver = { - .name = "mdio-mux-multiplexer", - .of_match_table = mdio_mux_multiplexer_match, - }, - .probe = mdio_mux_multiplexer_probe, - .remove = mdio_mux_multiplexer_remove, -}; - -module_platform_driver(mdio_mux_multiplexer_driver); - -MODULE_DESCRIPTION("MDIO bus multiplexer using kernel multiplexer subsystem"); -MODULE_AUTHOR("Pankaj Bansal <pankaj.bansal@nxp.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c deleted file mode 100644 index 6a1d3540210b..000000000000 --- a/drivers/net/phy/mdio-mux.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011, 2012 Cavium, Inc. - */ - -#include <linux/platform_device.h> -#include <linux/mdio-mux.h> -#include <linux/of_mdio.h> -#include <linux/device.h> -#include <linux/module.h> -#include <linux/phy.h> - -#define DRV_DESCRIPTION "MDIO bus multiplexer driver" - -struct mdio_mux_child_bus; - -struct mdio_mux_parent_bus { - struct mii_bus *mii_bus; - int current_child; - int parent_id; - void *switch_data; - int (*switch_fn)(int current_child, int desired_child, void *data); - - /* List of our children linked through their next fields. */ - struct mdio_mux_child_bus *children; -}; - -struct mdio_mux_child_bus { - struct mii_bus *mii_bus; - struct mdio_mux_parent_bus *parent; - struct mdio_mux_child_bus *next; - int bus_number; -}; - -/* - * The parent bus' lock is used to order access to the switch_fn. - */ -static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum) -{ - struct mdio_mux_child_bus *cb = bus->priv; - struct mdio_mux_parent_bus *pb = cb->parent; - int r; - - mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); - r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); - if (r) - goto out; - - pb->current_child = cb->bus_number; - - r = pb->mii_bus->read(pb->mii_bus, phy_id, regnum); -out: - mutex_unlock(&pb->mii_bus->mdio_lock); - - return r; -} - -/* - * The parent bus' lock is used to order access to the switch_fn. - */ -static int mdio_mux_write(struct mii_bus *bus, int phy_id, - int regnum, u16 val) -{ - struct mdio_mux_child_bus *cb = bus->priv; - struct mdio_mux_parent_bus *pb = cb->parent; - - int r; - - mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); - r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); - if (r) - goto out; - - pb->current_child = cb->bus_number; - - r = pb->mii_bus->write(pb->mii_bus, phy_id, regnum, val); -out: - mutex_unlock(&pb->mii_bus->mdio_lock); - - return r; -} - -static int parent_count; - -int mdio_mux_init(struct device *dev, - struct device_node *mux_node, - int (*switch_fn)(int cur, int desired, void *data), - void **mux_handle, - void *data, - struct mii_bus *mux_bus) -{ - struct device_node *parent_bus_node; - struct device_node *child_bus_node; - int r, ret_val; - struct mii_bus *parent_bus; - struct mdio_mux_parent_bus *pb; - struct mdio_mux_child_bus *cb; - - if (!mux_node) - return -ENODEV; - - if (!mux_bus) { - parent_bus_node = of_parse_phandle(mux_node, - "mdio-parent-bus", 0); - - if (!parent_bus_node) - return -ENODEV; - - parent_bus = of_mdio_find_bus(parent_bus_node); - if (!parent_bus) { - ret_val = -EPROBE_DEFER; - goto err_parent_bus; - } - } else { - parent_bus_node = NULL; - parent_bus = mux_bus; - get_device(&parent_bus->dev); - } - - pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL); - if (!pb) { - ret_val = -ENOMEM; - goto err_pb_kz; - } - - pb->switch_data = data; - pb->switch_fn = switch_fn; - pb->current_child = -1; - pb->parent_id = parent_count++; - pb->mii_bus = parent_bus; - - ret_val = -ENODEV; - for_each_available_child_of_node(mux_node, child_bus_node) { - int v; - - r = of_property_read_u32(child_bus_node, "reg", &v); - if (r) { - dev_err(dev, - "Error: Failed to find reg for child %pOF\n", - child_bus_node); - continue; - } - - cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); - if (!cb) { - ret_val = -ENOMEM; - continue; - } - cb->bus_number = v; - cb->parent = pb; - - cb->mii_bus = mdiobus_alloc(); - if (!cb->mii_bus) { - ret_val = -ENOMEM; - devm_kfree(dev, cb); - continue; - } - cb->mii_bus->priv = cb; - - cb->mii_bus->name = "mdio_mux"; - snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x", - pb->parent_id, v); - cb->mii_bus->parent = dev; - cb->mii_bus->read = mdio_mux_read; - cb->mii_bus->write = mdio_mux_write; - r = of_mdiobus_register(cb->mii_bus, child_bus_node); - if (r) { - dev_err(dev, - "Error: Failed to register MDIO bus for child %pOF\n", - child_bus_node); - mdiobus_free(cb->mii_bus); - devm_kfree(dev, cb); - } else { - cb->next = pb->children; - pb->children = cb; - } - } - if (pb->children) { - *mux_handle = pb; - return 0; - } - - dev_err(dev, "Error: No acceptable child buses found\n"); - devm_kfree(dev, pb); -err_pb_kz: - put_device(&parent_bus->dev); -err_parent_bus: - of_node_put(parent_bus_node); - return ret_val; -} -EXPORT_SYMBOL_GPL(mdio_mux_init); - -void mdio_mux_uninit(void *mux_handle) -{ - struct mdio_mux_parent_bus *pb = mux_handle; - struct mdio_mux_child_bus *cb = pb->children; - - while (cb) { - mdiobus_unregister(cb->mii_bus); - mdiobus_free(cb->mii_bus); - cb = cb->next; - } - - put_device(&pb->mii_bus->dev); -} -EXPORT_SYMBOL_GPL(mdio_mux_uninit); - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR("David Daney"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-mvusb.c b/drivers/net/phy/mdio-mvusb.c deleted file mode 100644 index d5eabddfdf51..000000000000 --- a/drivers/net/phy/mdio-mvusb.c +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/usb.h> - -#define USB_MARVELL_VID 0x1286 - -static const struct usb_device_id mvusb_mdio_table[] = { - { USB_DEVICE(USB_MARVELL_VID, 0x1fa4) }, - - {} -}; -MODULE_DEVICE_TABLE(usb, mvusb_mdio_table); - -enum { - MVUSB_CMD_PREAMBLE0, - MVUSB_CMD_PREAMBLE1, - MVUSB_CMD_ADDR, - MVUSB_CMD_VAL, -}; - -struct mvusb_mdio { - struct usb_device *udev; - struct mii_bus *mdio; - - __le16 buf[4]; -}; - -static int mvusb_mdio_read(struct mii_bus *mdio, int dev, int reg) -{ - struct mvusb_mdio *mvusb = mdio->priv; - int err, alen; - - if (dev & MII_ADDR_C45) - return -EOPNOTSUPP; - - mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0xa400 | (dev << 5) | reg); - - err = usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2), - mvusb->buf, 6, &alen, 100); - if (err) - return err; - - err = usb_bulk_msg(mvusb->udev, usb_rcvbulkpipe(mvusb->udev, 6), - &mvusb->buf[MVUSB_CMD_VAL], 2, &alen, 100); - if (err) - return err; - - return le16_to_cpu(mvusb->buf[MVUSB_CMD_VAL]); -} - -static int mvusb_mdio_write(struct mii_bus *mdio, int dev, int reg, u16 val) -{ - struct mvusb_mdio *mvusb = mdio->priv; - int alen; - - if (dev & MII_ADDR_C45) - return -EOPNOTSUPP; - - mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0x8000 | (dev << 5) | reg); - mvusb->buf[MVUSB_CMD_VAL] = cpu_to_le16(val); - - return usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2), - mvusb->buf, 8, &alen, 100); -} - -static int mvusb_mdio_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct device *dev = &interface->dev; - struct mvusb_mdio *mvusb; - struct mii_bus *mdio; - - mdio = devm_mdiobus_alloc_size(dev, sizeof(*mvusb)); - if (!mdio) - return -ENOMEM; - - mvusb = mdio->priv; - mvusb->mdio = mdio; - mvusb->udev = usb_get_dev(interface_to_usbdev(interface)); - - /* Reversed from USB PCAPs, no idea what these mean. */ - mvusb->buf[MVUSB_CMD_PREAMBLE0] = cpu_to_le16(0xe800); - mvusb->buf[MVUSB_CMD_PREAMBLE1] = cpu_to_le16(0x0001); - - snprintf(mdio->id, MII_BUS_ID_SIZE, "mvusb-%s", dev_name(dev)); - mdio->name = mdio->id; - mdio->parent = dev; - mdio->read = mvusb_mdio_read; - mdio->write = mvusb_mdio_write; - - usb_set_intfdata(interface, mvusb); - return of_mdiobus_register(mdio, dev->of_node); -} - -static void mvusb_mdio_disconnect(struct usb_interface *interface) -{ - struct mvusb_mdio *mvusb = usb_get_intfdata(interface); - struct usb_device *udev = mvusb->udev; - - mdiobus_unregister(mvusb->mdio); - usb_set_intfdata(interface, NULL); - usb_put_dev(udev); -} - -static struct usb_driver mvusb_mdio_driver = { - .name = "mvusb_mdio", - .id_table = mvusb_mdio_table, - .probe = mvusb_mdio_probe, - .disconnect = mvusb_mdio_disconnect, -}; - -module_usb_driver(mvusb_mdio_driver); - -MODULE_AUTHOR("Tobias Waldekranz <tobias@waldekranz.com>"); -MODULE_DESCRIPTION("Marvell USB MDIO Adapter"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c deleted file mode 100644 index d1e1009d51af..000000000000 --- a/drivers/net/phy/mdio-octeon.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2009-2015 Cavium, Inc. - */ - -#include <linux/platform_device.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/module.h> -#include <linux/gfp.h> -#include <linux/phy.h> -#include <linux/io.h> - -#include "mdio-cavium.h" - -static int octeon_mdiobus_probe(struct platform_device *pdev) -{ - struct cavium_mdiobus *bus; - struct mii_bus *mii_bus; - struct resource *res_mem; - resource_size_t mdio_phys; - resource_size_t regsize; - union cvmx_smix_en smi_en; - int err = -ENOENT; - - mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus)); - if (!mii_bus) - return -ENOMEM; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "found no memory resource\n"); - return -ENXIO; - } - - bus = mii_bus->priv; - bus->mii_bus = mii_bus; - mdio_phys = res_mem->start; - regsize = resource_size(res_mem); - - if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize, - res_mem->name)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - return -ENXIO; - } - - bus->register_base = devm_ioremap(&pdev->dev, mdio_phys, regsize); - if (!bus->register_base) { - dev_err(&pdev->dev, "dev_ioremap failed\n"); - return -ENOMEM; - } - - smi_en.u64 = 0; - smi_en.s.en = 1; - oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); - - bus->mii_bus->name = KBUILD_MODNAME; - snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%px", bus->register_base); - bus->mii_bus->parent = &pdev->dev; - - bus->mii_bus->read = cavium_mdiobus_read; - bus->mii_bus->write = cavium_mdiobus_write; - - platform_set_drvdata(pdev, bus); - - err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); - if (err) - goto fail_register; - - dev_info(&pdev->dev, "Probed\n"); - - return 0; -fail_register: - mdiobus_free(bus->mii_bus); - smi_en.u64 = 0; - oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); - return err; -} - -static int octeon_mdiobus_remove(struct platform_device *pdev) -{ - struct cavium_mdiobus *bus; - union cvmx_smix_en smi_en; - - bus = platform_get_drvdata(pdev); - - mdiobus_unregister(bus->mii_bus); - mdiobus_free(bus->mii_bus); - smi_en.u64 = 0; - oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); - return 0; -} - -static const struct of_device_id octeon_mdiobus_match[] = { - { - .compatible = "cavium,octeon-3860-mdio", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); - -static struct platform_driver octeon_mdiobus_driver = { - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = octeon_mdiobus_match, - }, - .probe = octeon_mdiobus_probe, - .remove = octeon_mdiobus_remove, -}; - -module_platform_driver(octeon_mdiobus_driver); - -MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver"); -MODULE_AUTHOR("David Daney"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c deleted file mode 100644 index f798de3276dc..000000000000 --- a/drivers/net/phy/mdio-sun4i.c +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Allwinner EMAC MDIO interface driver - * - * Copyright 2012-2013 Stefan Roese <sr@denx.de> - * Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com> - * - * Based on the Linux driver provided by Allwinner: - * Copyright (C) 1997 Sten Wang - */ - -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> - -#define EMAC_MAC_MCMD_REG (0x00) -#define EMAC_MAC_MADR_REG (0x04) -#define EMAC_MAC_MWTD_REG (0x08) -#define EMAC_MAC_MRDD_REG (0x0c) -#define EMAC_MAC_MIND_REG (0x10) -#define EMAC_MAC_SSRR_REG (0x14) - -#define MDIO_TIMEOUT (msecs_to_jiffies(100)) - -struct sun4i_mdio_data { - void __iomem *membase; - struct regulator *regulator; -}; - -static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct sun4i_mdio_data *data = bus->priv; - unsigned long timeout_jiffies; - int value; - - /* issue the phy address and reg */ - writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); - /* pull up the phy io line */ - writel(0x1, data->membase + EMAC_MAC_MCMD_REG); - - /* Wait read complete */ - timeout_jiffies = jiffies + MDIO_TIMEOUT; - while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_is_before_jiffies(timeout_jiffies)) - return -ETIMEDOUT; - msleep(1); - } - - /* push down the phy io line */ - writel(0x0, data->membase + EMAC_MAC_MCMD_REG); - /* and read data */ - value = readl(data->membase + EMAC_MAC_MRDD_REG); - - return value; -} - -static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 value) -{ - struct sun4i_mdio_data *data = bus->priv; - unsigned long timeout_jiffies; - - /* issue the phy address and reg */ - writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); - /* pull up the phy io line */ - writel(0x1, data->membase + EMAC_MAC_MCMD_REG); - - /* Wait read complete */ - timeout_jiffies = jiffies + MDIO_TIMEOUT; - while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_is_before_jiffies(timeout_jiffies)) - return -ETIMEDOUT; - msleep(1); - } - - /* push down the phy io line */ - writel(0x0, data->membase + EMAC_MAC_MCMD_REG); - /* and write data */ - writel(value, data->membase + EMAC_MAC_MWTD_REG); - - return 0; -} - -static int sun4i_mdio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct mii_bus *bus; - struct sun4i_mdio_data *data; - int ret; - - bus = mdiobus_alloc_size(sizeof(*data)); - if (!bus) - return -ENOMEM; - - bus->name = "sun4i_mii_bus"; - bus->read = &sun4i_mdio_read; - bus->write = &sun4i_mdio_write; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); - bus->parent = &pdev->dev; - - data = bus->priv; - data->membase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->membase)) { - ret = PTR_ERR(data->membase); - goto err_out_free_mdiobus; - } - - data->regulator = devm_regulator_get(&pdev->dev, "phy"); - if (IS_ERR(data->regulator)) { - if (PTR_ERR(data->regulator) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_out_free_mdiobus; - } - - dev_info(&pdev->dev, "no regulator found\n"); - data->regulator = NULL; - } else { - ret = regulator_enable(data->regulator); - if (ret) - goto err_out_free_mdiobus; - } - - ret = of_mdiobus_register(bus, np); - if (ret < 0) - goto err_out_disable_regulator; - - platform_set_drvdata(pdev, bus); - - return 0; - -err_out_disable_regulator: - if (data->regulator) - regulator_disable(data->regulator); -err_out_free_mdiobus: - mdiobus_free(bus); - return ret; -} - -static int sun4i_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - struct sun4i_mdio_data *data = bus->priv; - - mdiobus_unregister(bus); - if (data->regulator) - regulator_disable(data->regulator); - mdiobus_free(bus); - - return 0; -} - -static const struct of_device_id sun4i_mdio_dt_ids[] = { - { .compatible = "allwinner,sun4i-a10-mdio" }, - - /* Deprecated */ - { .compatible = "allwinner,sun4i-mdio" }, - { } -}; -MODULE_DEVICE_TABLE(of, sun4i_mdio_dt_ids); - -static struct platform_driver sun4i_mdio_driver = { - .probe = sun4i_mdio_probe, - .remove = sun4i_mdio_remove, - .driver = { - .name = "sun4i-mdio", - .of_match_table = sun4i_mdio_dt_ids, - }, -}; - -module_platform_driver(sun4i_mdio_driver); - -MODULE_DESCRIPTION("Allwinner EMAC MDIO interface driver"); -MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-thunder.c b/drivers/net/phy/mdio-thunder.c deleted file mode 100644 index 3d7eda99d34e..000000000000 --- a/drivers/net/phy/mdio-thunder.c +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2009-2016 Cavium, Inc. - */ - -#include <linux/of_address.h> -#include <linux/of_mdio.h> -#include <linux/module.h> -#include <linux/gfp.h> -#include <linux/phy.h> -#include <linux/io.h> -#include <linux/acpi.h> -#include <linux/pci.h> - -#include "mdio-cavium.h" - -struct thunder_mdiobus_nexus { - void __iomem *bar0; - struct cavium_mdiobus *buses[4]; -}; - -static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct device_node *node; - struct fwnode_handle *fwn; - struct thunder_mdiobus_nexus *nexus; - int err; - int i; - - nexus = devm_kzalloc(&pdev->dev, sizeof(*nexus), GFP_KERNEL); - if (!nexus) - return -ENOMEM; - - pci_set_drvdata(pdev, nexus); - - err = pcim_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Failed to enable PCI device\n"); - pci_set_drvdata(pdev, NULL); - return err; - } - - err = pci_request_regions(pdev, KBUILD_MODNAME); - if (err) { - dev_err(&pdev->dev, "pci_request_regions failed\n"); - goto err_disable_device; - } - - nexus->bar0 = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); - if (!nexus->bar0) { - err = -ENOMEM; - goto err_release_regions; - } - - i = 0; - device_for_each_child_node(&pdev->dev, fwn) { - struct resource r; - struct mii_bus *mii_bus; - struct cavium_mdiobus *bus; - union cvmx_smix_en smi_en; - - /* If it is not an OF node we cannot handle it yet, so - * exit the loop. - */ - node = to_of_node(fwn); - if (!node) - break; - - err = of_address_to_resource(node, 0, &r); - if (err) { - dev_err(&pdev->dev, - "Couldn't translate address for \"%pOFn\"\n", - node); - break; - } - - mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus)); - if (!mii_bus) - break; - bus = mii_bus->priv; - bus->mii_bus = mii_bus; - - nexus->buses[i] = bus; - i++; - - bus->register_base = nexus->bar0 + - r.start - pci_resource_start(pdev, 0); - - smi_en.u64 = 0; - smi_en.s.en = 1; - oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); - bus->mii_bus->name = KBUILD_MODNAME; - snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start); - bus->mii_bus->parent = &pdev->dev; - bus->mii_bus->read = cavium_mdiobus_read; - bus->mii_bus->write = cavium_mdiobus_write; - - err = of_mdiobus_register(bus->mii_bus, node); - if (err) - dev_err(&pdev->dev, "of_mdiobus_register failed\n"); - - dev_info(&pdev->dev, "Added bus at %llx\n", r.start); - if (i >= ARRAY_SIZE(nexus->buses)) - break; - } - return 0; - -err_release_regions: - pci_release_regions(pdev); - -err_disable_device: - pci_set_drvdata(pdev, NULL); - return err; -} - -static void thunder_mdiobus_pci_remove(struct pci_dev *pdev) -{ - int i; - struct thunder_mdiobus_nexus *nexus = pci_get_drvdata(pdev); - - for (i = 0; i < ARRAY_SIZE(nexus->buses); i++) { - struct cavium_mdiobus *bus = nexus->buses[i]; - - if (!bus) - continue; - - mdiobus_unregister(bus->mii_bus); - mdiobus_free(bus->mii_bus); - oct_mdio_writeq(0, bus->register_base + SMI_EN); - } - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); -} - -static const struct pci_device_id thunder_mdiobus_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa02b) }, - { 0, } /* End of table. */ -}; -MODULE_DEVICE_TABLE(pci, thunder_mdiobus_id_table); - -static struct pci_driver thunder_mdiobus_driver = { - .name = KBUILD_MODNAME, - .id_table = thunder_mdiobus_id_table, - .probe = thunder_mdiobus_pci_probe, - .remove = thunder_mdiobus_pci_remove, -}; - -module_pci_driver(thunder_mdiobus_driver); - -MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c deleted file mode 100644 index 34990eaa3298..000000000000 --- a/drivers/net/phy/mdio-xgene.c +++ /dev/null @@ -1,466 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Applied Micro X-Gene SoC MDIO Driver - * - * Copyright (c) 2016, Applied Micro Circuits Corporation - * Author: Iyappan Subramanian <isubramanian@apm.com> - */ - -#include <linux/acpi.h> -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/efi.h> -#include <linux/if_vlan.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/of_net.h> -#include <linux/of_mdio.h> -#include <linux/prefetch.h> -#include <linux/phy.h> -#include <net/ip.h> -#include "mdio-xgene.h" - -static bool xgene_mdio_status; - -u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr) -{ - void __iomem *addr, *rd, *cmd, *cmd_done; - u32 done, rd_data = BUSY_MASK; - u8 wait = 10; - - addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; - rd = pdata->mac_csr_addr + MAC_READ_REG_OFFSET; - cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; - - spin_lock(&pdata->mac_lock); - iowrite32(rd_addr, addr); - iowrite32(XGENE_ENET_RD_CMD, cmd); - - while (!(done = ioread32(cmd_done)) && wait--) - udelay(1); - - if (done) - rd_data = ioread32(rd); - - iowrite32(0, cmd); - spin_unlock(&pdata->mac_lock); - - return rd_data; -} -EXPORT_SYMBOL(xgene_mdio_rd_mac); - -void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data) -{ - void __iomem *addr, *wr, *cmd, *cmd_done; - u8 wait = 10; - u32 done; - - addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; - wr = pdata->mac_csr_addr + MAC_WRITE_REG_OFFSET; - cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; - - spin_lock(&pdata->mac_lock); - iowrite32(wr_addr, addr); - iowrite32(data, wr); - iowrite32(XGENE_ENET_WR_CMD, cmd); - - while (!(done = ioread32(cmd_done)) && wait--) - udelay(1); - - if (!done) - pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); - - iowrite32(0, cmd); - spin_unlock(&pdata->mac_lock); -} -EXPORT_SYMBOL(xgene_mdio_wr_mac); - -int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) -{ - struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; - u32 data, done; - u8 wait = 10; - - data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, data); - xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); - do { - usleep_range(5, 10); - done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); - } while ((done & BUSY_MASK) && wait--); - - if (done & BUSY_MASK) { - dev_err(&bus->dev, "MII_MGMT read failed\n"); - return -EBUSY; - } - - data = xgene_mdio_rd_mac(pdata, MII_MGMT_STATUS_ADDR); - xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); - - return data; -} -EXPORT_SYMBOL(xgene_mdio_rgmii_read); - -int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) -{ - struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; - u32 val, done; - u8 wait = 10; - - val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, val); - - xgene_mdio_wr_mac(pdata, MII_MGMT_CONTROL_ADDR, data); - do { - usleep_range(5, 10); - done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); - } while ((done & BUSY_MASK) && wait--); - - if (done & BUSY_MASK) { - dev_err(&bus->dev, "MII_MGMT write failed\n"); - return -EBUSY; - } - - return 0; -} -EXPORT_SYMBOL(xgene_mdio_rgmii_write); - -static u32 xgene_menet_rd_diag_csr(struct xgene_mdio_pdata *pdata, u32 offset) -{ - return ioread32(pdata->diag_csr_addr + offset); -} - -static void xgene_menet_wr_diag_csr(struct xgene_mdio_pdata *pdata, - u32 offset, u32 val) -{ - iowrite32(val, pdata->diag_csr_addr + offset); -} - -static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) -{ - u32 data; - u8 wait = 10; - - xgene_menet_wr_diag_csr(pdata, MENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); - do { - usleep_range(100, 110); - data = xgene_menet_rd_diag_csr(pdata, MENET_BLOCK_MEM_RDY_ADDR); - } while ((data != 0xffffffff) && wait--); - - if (data != 0xffffffff) { - dev_err(pdata->dev, "Failed to release memory from shutdown\n"); - return -ENODEV; - } - - return 0; -} - -static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) -{ - xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET); - xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); -} - -static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) -{ - int ret; - - if (pdata->dev->of_node) { - clk_prepare_enable(pdata->clk); - udelay(5); - clk_disable_unprepare(pdata->clk); - udelay(5); - clk_prepare_enable(pdata->clk); - udelay(5); - } else { -#ifdef CONFIG_ACPI - acpi_evaluate_object(ACPI_HANDLE(pdata->dev), - "_RST", NULL, NULL); -#endif - } - - ret = xgene_enet_ecc_init(pdata); - if (ret) { - if (pdata->dev->of_node) - clk_disable_unprepare(pdata->clk); - return ret; - } - xgene_gmac_reset(pdata); - - return 0; -} - -static void xgene_enet_rd_mdio_csr(void __iomem *base_addr, - u32 offset, u32 *val) -{ - void __iomem *addr = base_addr + offset; - - *val = ioread32(addr); -} - -static void xgene_enet_wr_mdio_csr(void __iomem *base_addr, - u32 offset, u32 val) -{ - void __iomem *addr = base_addr + offset; - - iowrite32(val, addr); -} - -static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id, - int reg, u16 data) -{ - void __iomem *addr = (void __iomem *)bus->priv; - int timeout = 100; - u32 status, val; - - val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) | - SET_VAL(HSTMIIMWRDAT, data); - xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); - - val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE); - xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); - - do { - usleep_range(5, 10); - xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); - } while ((status & BUSY_MASK) && timeout--); - - xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); - - return 0; -} - -static int xgene_xfi_mdio_read(struct mii_bus *bus, int phy_id, int reg) -{ - void __iomem *addr = (void __iomem *)bus->priv; - u32 data, status, val; - int timeout = 100; - - val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg); - xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); - - val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_READ); - xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); - - do { - usleep_range(5, 10); - xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); - } while ((status & BUSY_MASK) && timeout--); - - if (status & BUSY_MASK) { - pr_err("XGENET_MII_MGMT write failed\n"); - return -EBUSY; - } - - xgene_enet_rd_mdio_csr(addr, MIIMRD_FIELD_ADDR, &data); - xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); - - return data; -} - -struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr) -{ - struct phy_device *phy_dev; - - phy_dev = get_phy_device(bus, phy_addr, false); - if (!phy_dev || IS_ERR(phy_dev)) - return NULL; - - if (phy_device_register(phy_dev)) - phy_device_free(phy_dev); - - return phy_dev; -} -EXPORT_SYMBOL(xgene_enet_phy_register); - -#ifdef CONFIG_ACPI -static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl, - void *context, void **ret) -{ - struct mii_bus *mdio = context; - struct acpi_device *adev; - struct phy_device *phy_dev; - const union acpi_object *obj; - u32 phy_addr; - - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - - if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj)) - return AE_OK; - phy_addr = obj->integer.value; - - phy_dev = xgene_enet_phy_register(mdio, phy_addr); - adev->driver_data = phy_dev; - - return AE_OK; -} -#endif - -static const struct of_device_id xgene_mdio_of_match[] = { - { - .compatible = "apm,xgene-mdio-rgmii", - .data = (void *)XGENE_MDIO_RGMII - }, - { - .compatible = "apm,xgene-mdio-xfi", - .data = (void *)XGENE_MDIO_XFI - }, - {}, -}; -MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); - -#ifdef CONFIG_ACPI -static const struct acpi_device_id xgene_mdio_acpi_match[] = { - { "APMC0D65", XGENE_MDIO_RGMII }, - { "APMC0D66", XGENE_MDIO_XFI }, - { } -}; - -MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); -#endif - - -static int xgene_mdio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct mii_bus *mdio_bus; - const struct of_device_id *of_id; - struct xgene_mdio_pdata *pdata; - void __iomem *csr_base; - int mdio_id = 0, ret = 0; - - of_id = of_match_device(xgene_mdio_of_match, &pdev->dev); - if (of_id) { - mdio_id = (enum xgene_mdio_id)of_id->data; - } else { -#ifdef CONFIG_ACPI - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(xgene_mdio_acpi_match, &pdev->dev); - if (acpi_id) - mdio_id = (enum xgene_mdio_id)acpi_id->driver_data; -#endif - } - - if (!mdio_id) - return -ENODEV; - - pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - pdata->mdio_id = mdio_id; - pdata->dev = dev; - - csr_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(csr_base)) - return PTR_ERR(csr_base); - pdata->mac_csr_addr = csr_base; - pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; - pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; - - if (mdio_id == XGENE_MDIO_RGMII) - spin_lock_init(&pdata->mac_lock); - - if (dev->of_node) { - pdata->clk = devm_clk_get(dev, NULL); - if (IS_ERR(pdata->clk)) { - dev_err(dev, "Unable to retrieve clk\n"); - return PTR_ERR(pdata->clk); - } - } - - ret = xgene_mdio_reset(pdata); - if (ret) - return ret; - - mdio_bus = mdiobus_alloc(); - if (!mdio_bus) { - ret = -ENOMEM; - goto out_clk; - } - - mdio_bus->name = "APM X-Gene MDIO bus"; - - if (mdio_id == XGENE_MDIO_RGMII) { - mdio_bus->read = xgene_mdio_rgmii_read; - mdio_bus->write = xgene_mdio_rgmii_write; - mdio_bus->priv = (void __force *)pdata; - snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", - "xgene-mii-rgmii"); - } else { - mdio_bus->read = xgene_xfi_mdio_read; - mdio_bus->write = xgene_xfi_mdio_write; - mdio_bus->priv = (void __force *)pdata->mdio_csr_addr; - snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", - "xgene-mii-xfi"); - } - - mdio_bus->parent = dev; - platform_set_drvdata(pdev, pdata); - - if (dev->of_node) { - ret = of_mdiobus_register(mdio_bus, dev->of_node); - } else { -#ifdef CONFIG_ACPI - /* Mask out all PHYs from auto probing. */ - mdio_bus->phy_mask = ~0; - ret = mdiobus_register(mdio_bus); - if (ret) - goto out_mdiobus; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1, - acpi_register_phy, NULL, mdio_bus, NULL); -#endif - } - - if (ret) - goto out_mdiobus; - - pdata->mdio_bus = mdio_bus; - xgene_mdio_status = true; - - return 0; - -out_mdiobus: - mdiobus_free(mdio_bus); - -out_clk: - if (dev->of_node) - clk_disable_unprepare(pdata->clk); - - return ret; -} - -static int xgene_mdio_remove(struct platform_device *pdev) -{ - struct xgene_mdio_pdata *pdata = platform_get_drvdata(pdev); - struct mii_bus *mdio_bus = pdata->mdio_bus; - struct device *dev = &pdev->dev; - - mdiobus_unregister(mdio_bus); - mdiobus_free(mdio_bus); - - if (dev->of_node) - clk_disable_unprepare(pdata->clk); - - return 0; -} - -static struct platform_driver xgene_mdio_driver = { - .driver = { - .name = "xgene-mdio", - .of_match_table = of_match_ptr(xgene_mdio_of_match), - .acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match), - }, - .probe = xgene_mdio_probe, - .remove = xgene_mdio_remove, -}; - -module_platform_driver(xgene_mdio_driver); - -MODULE_DESCRIPTION("APM X-Gene SoC MDIO driver"); -MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h deleted file mode 100644 index 8af93ada8b64..000000000000 --- a/drivers/net/phy/mdio-xgene.h +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* Applied Micro X-Gene SoC MDIO Driver - * - * Copyright (c) 2016, Applied Micro Circuits Corporation - * Author: Iyappan Subramanian <isubramanian@apm.com> - */ - -#ifndef __MDIO_XGENE_H__ -#define __MDIO_XGENE_H__ - -#define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 -#define BLOCK_DIAG_CSR_OFFSET 0xd000 -#define XGENET_CONFIG_REG_ADDR 0x20 - -#define MAC_ADDR_REG_OFFSET 0x00 -#define MAC_COMMAND_REG_OFFSET 0x04 -#define MAC_WRITE_REG_OFFSET 0x08 -#define MAC_READ_REG_OFFSET 0x0c -#define MAC_COMMAND_DONE_REG_OFFSET 0x10 - -#define CLKEN_OFFSET 0x08 -#define SRST_OFFSET 0x00 - -#define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 -#define MENET_BLOCK_MEM_RDY_ADDR 0x74 - -#define MAC_CONFIG_1_ADDR 0x00 -#define MII_MGMT_COMMAND_ADDR 0x24 -#define MII_MGMT_ADDRESS_ADDR 0x28 -#define MII_MGMT_CONTROL_ADDR 0x2c -#define MII_MGMT_STATUS_ADDR 0x30 -#define MII_MGMT_INDICATORS_ADDR 0x34 -#define SOFT_RESET BIT(31) - -#define MII_MGMT_CONFIG_ADDR 0x20 -#define MII_MGMT_COMMAND_ADDR 0x24 -#define MII_MGMT_ADDRESS_ADDR 0x28 -#define MII_MGMT_CONTROL_ADDR 0x2c -#define MII_MGMT_STATUS_ADDR 0x30 -#define MII_MGMT_INDICATORS_ADDR 0x34 - -#define MIIM_COMMAND_ADDR 0x20 -#define MIIM_FIELD_ADDR 0x24 -#define MIIM_CONFIGURATION_ADDR 0x28 -#define MIIM_LINKFAILVECTOR_ADDR 0x2c -#define MIIM_INDICATOR_ADDR 0x30 -#define MIIMRD_FIELD_ADDR 0x34 - -#define MDIO_CSR_OFFSET 0x5000 - -#define REG_ADDR_POS 0 -#define REG_ADDR_LEN 5 -#define PHY_ADDR_POS 8 -#define PHY_ADDR_LEN 5 - -#define HSTMIIMWRDAT_POS 0 -#define HSTMIIMWRDAT_LEN 16 -#define HSTPHYADX_POS 23 -#define HSTPHYADX_LEN 5 -#define HSTREGADX_POS 18 -#define HSTREGADX_LEN 5 -#define HSTLDCMD BIT(3) -#define HSTMIIMCMD_POS 0 -#define HSTMIIMCMD_LEN 3 - -#define BUSY_MASK BIT(0) -#define READ_CYCLE_MASK BIT(0) - -enum xgene_enet_cmd { - XGENE_ENET_WR_CMD = BIT(31), - XGENE_ENET_RD_CMD = BIT(30) -}; - -enum { - MIIM_CMD_IDLE, - MIIM_CMD_LEGACY_WRITE, - MIIM_CMD_LEGACY_READ, -}; - -enum xgene_mdio_id { - XGENE_MDIO_RGMII = 1, - XGENE_MDIO_XFI -}; - -struct xgene_mdio_pdata { - struct clk *clk; - struct device *dev; - void __iomem *mac_csr_addr; - void __iomem *diag_csr_addr; - void __iomem *mdio_csr_addr; - struct mii_bus *mdio_bus; - int mdio_id; - spinlock_t mac_lock; /* mac lock */ -}; - -/* Set the specified value into a bit-field defined by its starting position - * and length within a single u64. - */ -static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) -{ - return (val & ((1ULL << len) - 1)) << pos; -} - -#define SET_VAL(field, val) \ - xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) - -#define SET_BIT(field) \ - xgene_enet_set_field_value(field ## _POS, 1, 1) - -/* Get the value from a bit-field defined by its starting position - * and length within the specified u64. - */ -static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) -{ - return (src >> pos) & ((1ULL << len) - 1); -} - -#define GET_VAL(field, src) \ - xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) - -#define GET_BIT(field, src) \ - xgene_enet_get_field_value(field ## _POS, 1, src) - -u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr); -void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data); -int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); -int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); -struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); - -#endif /* __MDIO_XGENE_H__ */ diff --git a/drivers/net/phy/mdio-xpcs.c b/drivers/net/phy/mdio-xpcs.c deleted file mode 100644 index 0d66a8ba7eb6..000000000000 --- a/drivers/net/phy/mdio-xpcs.c +++ /dev/null @@ -1,716 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. - * Synopsys DesignWare XPCS helpers - * - * Author: Jose Abreu <Jose.Abreu@synopsys.com> - */ - -#include <linux/delay.h> -#include <linux/mdio.h> -#include <linux/mdio-xpcs.h> -#include <linux/phylink.h> -#include <linux/workqueue.h> - -#define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0 -#define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0 -#define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0 -#define SYNOPSYS_XPCS_MASK 0xffffffff - -/* Vendor regs access */ -#define DW_VENDOR BIT(15) - -/* VR_XS_PCS */ -#define DW_USXGMII_RST BIT(10) -#define DW_USXGMII_EN BIT(9) -#define DW_VR_XS_PCS_DIG_STS 0x0010 -#define DW_RXFIFO_ERR GENMASK(6, 5) - -/* SR_MII */ -#define DW_USXGMII_FULL BIT(8) -#define DW_USXGMII_SS_MASK (BIT(13) | BIT(6) | BIT(5)) -#define DW_USXGMII_10000 (BIT(13) | BIT(6)) -#define DW_USXGMII_5000 (BIT(13) | BIT(5)) -#define DW_USXGMII_2500 (BIT(5)) -#define DW_USXGMII_1000 (BIT(6)) -#define DW_USXGMII_100 (BIT(13)) -#define DW_USXGMII_10 (0) - -/* SR_AN */ -#define DW_SR_AN_ADV1 0x10 -#define DW_SR_AN_ADV2 0x11 -#define DW_SR_AN_ADV3 0x12 -#define DW_SR_AN_LP_ABL1 0x13 -#define DW_SR_AN_LP_ABL2 0x14 -#define DW_SR_AN_LP_ABL3 0x15 - -/* Clause 73 Defines */ -/* AN_LP_ABL1 */ -#define DW_C73_PAUSE BIT(10) -#define DW_C73_ASYM_PAUSE BIT(11) -#define DW_C73_AN_ADV_SF 0x1 -/* AN_LP_ABL2 */ -#define DW_C73_1000KX BIT(5) -#define DW_C73_10000KX4 BIT(6) -#define DW_C73_10000KR BIT(7) -/* AN_LP_ABL3 */ -#define DW_C73_2500KX BIT(0) -#define DW_C73_5000KR BIT(1) - -static const int xpcs_usxgmii_features[] = { - ETHTOOL_LINK_MODE_Pause_BIT, - ETHTOOL_LINK_MODE_Asym_Pause_BIT, - ETHTOOL_LINK_MODE_Autoneg_BIT, - ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, - ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, - ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, - ETHTOOL_LINK_MODE_2500baseX_Full_BIT, - __ETHTOOL_LINK_MODE_MASK_NBITS, -}; - -static const int xpcs_10gkr_features[] = { - ETHTOOL_LINK_MODE_Pause_BIT, - ETHTOOL_LINK_MODE_Asym_Pause_BIT, - ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, - __ETHTOOL_LINK_MODE_MASK_NBITS, -}; - -static const int xpcs_xlgmii_features[] = { - ETHTOOL_LINK_MODE_Pause_BIT, - ETHTOOL_LINK_MODE_Asym_Pause_BIT, - ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, - ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, - ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, - ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, - ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, - ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, - ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, - ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, - ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, - ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, - ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, - ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, - ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, - ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, - ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, - ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, - ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, - ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, - ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, - ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, - ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, - ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, - ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, - ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, - __ETHTOOL_LINK_MODE_MASK_NBITS, -}; - -static const phy_interface_t xpcs_usxgmii_interfaces[] = { - PHY_INTERFACE_MODE_USXGMII, - PHY_INTERFACE_MODE_MAX, -}; - -static const phy_interface_t xpcs_10gkr_interfaces[] = { - PHY_INTERFACE_MODE_10GKR, - PHY_INTERFACE_MODE_MAX, -}; - -static const phy_interface_t xpcs_xlgmii_interfaces[] = { - PHY_INTERFACE_MODE_XLGMII, - PHY_INTERFACE_MODE_MAX, -}; - -static struct xpcs_id { - u32 id; - u32 mask; - const int *supported; - const phy_interface_t *interface; -} xpcs_id_list[] = { - { - .id = SYNOPSYS_XPCS_USXGMII_ID, - .mask = SYNOPSYS_XPCS_MASK, - .supported = xpcs_usxgmii_features, - .interface = xpcs_usxgmii_interfaces, - }, { - .id = SYNOPSYS_XPCS_10GKR_ID, - .mask = SYNOPSYS_XPCS_MASK, - .supported = xpcs_10gkr_features, - .interface = xpcs_10gkr_interfaces, - }, { - .id = SYNOPSYS_XPCS_XLGMII_ID, - .mask = SYNOPSYS_XPCS_MASK, - .supported = xpcs_xlgmii_features, - .interface = xpcs_xlgmii_interfaces, - }, -}; - -static int xpcs_read(struct mdio_xpcs_args *xpcs, int dev, u32 reg) -{ - u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg; - - return mdiobus_read(xpcs->bus, xpcs->addr, reg_addr); -} - -static int xpcs_write(struct mdio_xpcs_args *xpcs, int dev, u32 reg, u16 val) -{ - u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg; - - return mdiobus_write(xpcs->bus, xpcs->addr, reg_addr, val); -} - -static int xpcs_read_vendor(struct mdio_xpcs_args *xpcs, int dev, u32 reg) -{ - return xpcs_read(xpcs, dev, DW_VENDOR | reg); -} - -static int xpcs_write_vendor(struct mdio_xpcs_args *xpcs, int dev, int reg, - u16 val) -{ - return xpcs_write(xpcs, dev, DW_VENDOR | reg, val); -} - -static int xpcs_read_vpcs(struct mdio_xpcs_args *xpcs, int reg) -{ - return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg); -} - -static int xpcs_write_vpcs(struct mdio_xpcs_args *xpcs, int reg, u16 val) -{ - return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val); -} - -static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev) -{ - /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ - unsigned int retries = 12; - int ret; - - do { - msleep(50); - ret = xpcs_read(xpcs, dev, MDIO_CTRL1); - if (ret < 0) - return ret; - } while (ret & MDIO_CTRL1_RESET && --retries); - - return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0; -} - -static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs, int dev) -{ - int ret; - - ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET); - if (ret < 0) - return ret; - - return xpcs_poll_reset(xpcs, dev); -} - -#define xpcs_warn(__xpcs, __state, __args...) \ -({ \ - if ((__state)->link) \ - dev_warn(&(__xpcs)->bus->dev, ##__args); \ -}) - -static int xpcs_read_fault(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - int ret; - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1); - if (ret < 0) - return ret; - - if (ret & MDIO_STAT1_FAULT) { - xpcs_warn(xpcs, state, "Link fault condition detected!\n"); - return -EFAULT; - } - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2); - if (ret < 0) - return ret; - - if (ret & MDIO_STAT2_RXFAULT) - xpcs_warn(xpcs, state, "Receiver fault detected!\n"); - if (ret & MDIO_STAT2_TXFAULT) - xpcs_warn(xpcs, state, "Transmitter fault detected!\n"); - - ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS); - if (ret < 0) - return ret; - - if (ret & DW_RXFIFO_ERR) { - xpcs_warn(xpcs, state, "FIFO fault condition detected!\n"); - return -EFAULT; - } - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK)) - xpcs_warn(xpcs, state, "Link is not locked!\n"); - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2); - if (ret < 0) - return ret; - - if (ret & MDIO_PCS_10GBRT_STAT2_ERR) { - xpcs_warn(xpcs, state, "Link has errors!\n"); - return -EFAULT; - } - - return 0; -} - -static int xpcs_read_link(struct mdio_xpcs_args *xpcs, bool an) -{ - bool link = true; - int ret; - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_STAT1_LSTATUS)) - link = false; - - if (an) { - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_STAT1_LSTATUS)) - link = false; - } - - return link; -} - -static int xpcs_get_max_usxgmii_speed(const unsigned long *supported) -{ - int max = SPEED_UNKNOWN; - - if (phylink_test(supported, 1000baseKX_Full)) - max = SPEED_1000; - if (phylink_test(supported, 2500baseX_Full)) - max = SPEED_2500; - if (phylink_test(supported, 10000baseKX4_Full)) - max = SPEED_10000; - if (phylink_test(supported, 10000baseKR_Full)) - max = SPEED_10000; - - return max; -} - -static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed) -{ - int ret, speed_sel; - - switch (speed) { - case SPEED_10: - speed_sel = DW_USXGMII_10; - break; - case SPEED_100: - speed_sel = DW_USXGMII_100; - break; - case SPEED_1000: - speed_sel = DW_USXGMII_1000; - break; - case SPEED_2500: - speed_sel = DW_USXGMII_2500; - break; - case SPEED_5000: - speed_sel = DW_USXGMII_5000; - break; - case SPEED_10000: - speed_sel = DW_USXGMII_10000; - break; - default: - /* Nothing to do here */ - return -EINVAL; - } - - ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1); - if (ret < 0) - return ret; - - ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN); - if (ret < 0) - return ret; - - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1); - if (ret < 0) - return ret; - - ret &= ~DW_USXGMII_SS_MASK; - ret |= speed_sel | DW_USXGMII_FULL; - - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret); - if (ret < 0) - return ret; - - ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1); - if (ret < 0) - return ret; - - return xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST); -} - -static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs) -{ - int ret, adv; - - /* By default, in USXGMII mode XPCS operates at 10G baud and - * replicates data to achieve lower speeds. Hereby, in this - * default configuration we need to advertise all supported - * modes and not only the ones we want to use. - */ - - /* SR_AN_ADV3 */ - adv = 0; - if (phylink_test(xpcs->supported, 2500baseX_Full)) - adv |= DW_C73_2500KX; - - /* TODO: 5000baseKR */ - - ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv); - if (ret < 0) - return ret; - - /* SR_AN_ADV2 */ - adv = 0; - if (phylink_test(xpcs->supported, 1000baseKX_Full)) - adv |= DW_C73_1000KX; - if (phylink_test(xpcs->supported, 10000baseKX4_Full)) - adv |= DW_C73_10000KX4; - if (phylink_test(xpcs->supported, 10000baseKR_Full)) - adv |= DW_C73_10000KR; - - ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv); - if (ret < 0) - return ret; - - /* SR_AN_ADV1 */ - adv = DW_C73_AN_ADV_SF; - if (phylink_test(xpcs->supported, Pause)) - adv |= DW_C73_PAUSE; - if (phylink_test(xpcs->supported, Asym_Pause)) - adv |= DW_C73_ASYM_PAUSE; - - return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv); -} - -static int xpcs_config_aneg(struct mdio_xpcs_args *xpcs) -{ - int ret; - - ret = xpcs_config_aneg_c73(xpcs); - if (ret < 0) - return ret; - - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1); - if (ret < 0) - return ret; - - ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART; - - return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret); -} - -static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - int ret; - - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); - if (ret < 0) - return ret; - - if (ret & MDIO_AN_STAT1_COMPLETE) { - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1); - if (ret < 0) - return ret; - - /* Check if Aneg outcome is valid */ - if (!(ret & DW_C73_AN_ADV_SF)) { - xpcs_config_aneg(xpcs); - return 0; - } - - return 1; - } - - return 0; -} - -static int xpcs_read_lpa(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - int ret; - - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_AN_STAT1_LPABLE)) { - phylink_clear(state->lp_advertising, Autoneg); - return 0; - } - - phylink_set(state->lp_advertising, Autoneg); - - /* Clause 73 outcome */ - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3); - if (ret < 0) - return ret; - - if (ret & DW_C73_2500KX) - phylink_set(state->lp_advertising, 2500baseX_Full); - - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2); - if (ret < 0) - return ret; - - if (ret & DW_C73_1000KX) - phylink_set(state->lp_advertising, 1000baseKX_Full); - if (ret & DW_C73_10000KX4) - phylink_set(state->lp_advertising, 10000baseKX4_Full); - if (ret & DW_C73_10000KR) - phylink_set(state->lp_advertising, 10000baseKR_Full); - - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1); - if (ret < 0) - return ret; - - if (ret & DW_C73_PAUSE) - phylink_set(state->lp_advertising, Pause); - if (ret & DW_C73_ASYM_PAUSE) - phylink_set(state->lp_advertising, Asym_Pause); - - linkmode_and(state->lp_advertising, state->lp_advertising, - state->advertising); - return 0; -} - -static void xpcs_resolve_lpa(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising); - - state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; - state->speed = max_speed; - state->duplex = DUPLEX_FULL; -} - -static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - unsigned long *adv = state->advertising; - int speed = SPEED_UNKNOWN; - int bit; - - for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) { - int new_speed = SPEED_UNKNOWN; - - switch (bit) { - case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT: - case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT: - case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT: - new_speed = SPEED_25000; - break; - case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT: - case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT: - case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT: - case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT: - new_speed = SPEED_40000; - break; - case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT: - case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT: - new_speed = SPEED_50000; - break; - case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT: - case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT: - new_speed = SPEED_100000; - break; - default: - continue; - } - - if (new_speed > speed) - speed = new_speed; - } - - return speed; -} - -static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; - state->duplex = DUPLEX_FULL; - - switch (state->interface) { - case PHY_INTERFACE_MODE_10GKR: - state->speed = SPEED_10000; - break; - case PHY_INTERFACE_MODE_XLGMII: - state->speed = xpcs_get_max_xlgmii_speed(xpcs, state); - break; - default: - state->speed = SPEED_UNKNOWN; - break; - } -} - -static int xpcs_validate(struct mdio_xpcs_args *xpcs, - unsigned long *supported, - struct phylink_link_state *state) -{ - linkmode_and(supported, supported, xpcs->supported); - linkmode_and(state->advertising, state->advertising, xpcs->supported); - return 0; -} - -static int xpcs_config(struct mdio_xpcs_args *xpcs, - const struct phylink_link_state *state) -{ - int ret; - - if (state->an_enabled) { - ret = xpcs_config_aneg(xpcs); - if (ret) - return ret; - } - - return 0; -} - -static int xpcs_get_state(struct mdio_xpcs_args *xpcs, - struct phylink_link_state *state) -{ - int ret; - - /* Link needs to be read first ... */ - state->link = xpcs_read_link(xpcs, state->an_enabled) > 0 ? 1 : 0; - - /* ... and then we check the faults. */ - ret = xpcs_read_fault(xpcs, state); - if (ret) { - ret = xpcs_soft_reset(xpcs, MDIO_MMD_PCS); - if (ret) - return ret; - - state->link = 0; - - return xpcs_config(xpcs, state); - } - - if (state->an_enabled && xpcs_aneg_done(xpcs, state)) { - state->an_complete = true; - xpcs_read_lpa(xpcs, state); - xpcs_resolve_lpa(xpcs, state); - } else if (state->an_enabled) { - state->link = 0; - } else if (state->link) { - xpcs_resolve_pma(xpcs, state); - } - - return 0; -} - -static int xpcs_link_up(struct mdio_xpcs_args *xpcs, int speed, - phy_interface_t interface) -{ - if (interface == PHY_INTERFACE_MODE_USXGMII) - return xpcs_config_usxgmii(xpcs, speed); - - return 0; -} - -static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) -{ - int ret; - u32 id; - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1); - if (ret < 0) - return 0xffffffff; - - id = ret << 16; - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2); - if (ret < 0) - return 0xffffffff; - - return id | ret; -} - -static bool xpcs_check_features(struct mdio_xpcs_args *xpcs, - struct xpcs_id *match, - phy_interface_t interface) -{ - int i; - - for (i = 0; match->interface[i] != PHY_INTERFACE_MODE_MAX; i++) { - if (match->interface[i] == interface) - break; - } - - if (match->interface[i] == PHY_INTERFACE_MODE_MAX) - return false; - - for (i = 0; match->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++) - set_bit(match->supported[i], xpcs->supported); - - return true; -} - -static int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface) -{ - u32 xpcs_id = xpcs_get_id(xpcs); - struct xpcs_id *match = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) { - struct xpcs_id *entry = &xpcs_id_list[i]; - - if ((xpcs_id & entry->mask) == entry->id) { - match = entry; - - if (xpcs_check_features(xpcs, match, interface)) - return xpcs_soft_reset(xpcs, MDIO_MMD_PCS); - } - } - - return -ENODEV; -} - -static struct mdio_xpcs_ops xpcs_ops = { - .validate = xpcs_validate, - .config = xpcs_config, - .get_state = xpcs_get_state, - .link_up = xpcs_link_up, - .probe = xpcs_probe, -}; - -struct mdio_xpcs_ops *mdio_xpcs_get_ops(void) -{ - return &xpcs_ops; -} -EXPORT_SYMBOL_GPL(mdio_xpcs_get_ops); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 0af20faad69d..757e950fb745 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -825,9 +825,6 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum) { int retval; - if (WARN_ON_ONCE(in_interrupt())) - return -EINVAL; - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); retval = __mdiobus_read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); @@ -850,9 +847,6 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) { int retval; - if (WARN_ON_ONCE(in_interrupt())) - return -EINVAL; - mutex_lock(&bus->mdio_lock); retval = __mdiobus_read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); @@ -879,9 +873,6 @@ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val) { int err; - if (WARN_ON_ONCE(in_interrupt())) - return -EINVAL; - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); err = __mdiobus_write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); @@ -905,9 +896,6 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) { int err; - if (WARN_ON_ONCE(in_interrupt())) - return -EINVAL; - mutex_lock(&bus->mdio_lock); err = __mdiobus_write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); @@ -929,9 +917,6 @@ int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set) { int err; - if (WARN_ON_ONCE(in_interrupt())) - return -EINVAL; - mutex_lock(&bus->mdio_lock); err = __mdiobus_modify_changed(bus, addr, regnum, mask, set); mutex_unlock(&bus->mdio_lock); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 3fe552675dd2..a7f74b3b97af 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1315,6 +1315,19 @@ static struct phy_driver ksphy_driver[] = { .suspend = genphy_suspend, .resume = kszphy_resume, }, { + .phy_id = PHY_ID_LAN8814, + .phy_id_mask = MICREL_PHY_ID_MASK, + .name = "Microchip INDY Gigabit Quad PHY", + .driver_data = &ksz9021_type, + .probe = kszphy_probe, + .soft_reset = genphy_soft_reset, + .read_status = ksz9031_read_status, + .get_sset_count = kszphy_get_sset_count, + .get_strings = kszphy_get_strings, + .get_stats = kszphy_get_stats, + .suspend = genphy_suspend, + .resume = kszphy_resume, +}, { .phy_id = PHY_ID_KSZ9131, .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Microchip KSZ9131 Gigabit PHY", @@ -1387,6 +1400,7 @@ static struct mdio_device_id __maybe_unused micrel_tbl[] = { { PHY_ID_KSZ8081, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ886X, MICREL_PHY_ID_MASK }, + { PHY_ID_LAN8814, MICREL_PHY_ID_MASK }, { } }; diff --git a/drivers/net/phy/mscc/mscc_macsec.c b/drivers/net/phy/mscc/mscc_macsec.c index 1d4c012194e9..10be266e48e8 100644 --- a/drivers/net/phy/mscc/mscc_macsec.c +++ b/drivers/net/phy/mscc/mscc_macsec.c @@ -958,7 +958,7 @@ static int vsc8584_macsec_del_txsa(struct macsec_context *ctx) return 0; } -static struct macsec_ops vsc8584_macsec_ops = { +static const struct macsec_ops vsc8584_macsec_ops = { .mdo_dev_open = vsc8584_macsec_dev_open, .mdo_dev_stop = vsc8584_macsec_dev_stop, .mdo_add_secy = vsc8584_macsec_add_secy, @@ -981,7 +981,6 @@ int vsc8584_macsec_init(struct phy_device *phydev) switch (phydev->phy_id & phydev->drv->phy_id_mask) { case PHY_ID_VSC856X: - case PHY_ID_VSC8575: case PHY_ID_VSC8582: case PHY_ID_VSC8584: INIT_LIST_HEAD(&vsc8531->macsec_flows); diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index ff8e14b01eeb..8d333d3084ed 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -6,9 +6,14 @@ #include <linux/phy.h> #include <linux/of.h> +/** + * phy_speed_to_str - Return a string representing the PHY link speed + * + * @speed: Speed of the link + */ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 90, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 92, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); @@ -52,6 +57,11 @@ const char *phy_speed_to_str(int speed) } EXPORT_SYMBOL_GPL(phy_speed_to_str); +/** + * phy_duplex_to_str - Return string describing the duplex + * + * @duplex: Duplex setting to describe + */ const char *phy_duplex_to_str(unsigned int duplex) { if (duplex == DUPLEX_HALF) @@ -160,6 +170,8 @@ static const struct phy_setting settings[] = { PHY_SETTING( 100, FULL, 100baseT_Full ), PHY_SETTING( 100, FULL, 100baseT1_Full ), PHY_SETTING( 100, HALF, 100baseT_Half ), + PHY_SETTING( 100, HALF, 100baseFX_Half ), + PHY_SETTING( 100, FULL, 100baseFX_Full ), /* 10M */ PHY_SETTING( 10, FULL, 10baseT_Full ), PHY_SETTING( 10, HALF, 10baseT_Half ), @@ -250,6 +262,16 @@ static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) return __set_linkmode_max_speed(max_speed, phydev->supported); } +/** + * phy_set_max_speed - Set the maximum speed the PHY should support + * + * @phydev: The phy_device struct + * @max_speed: Maximum speed + * + * The PHY might be more capable than the MAC. For example a Fast Ethernet + * is connected to a 1G PHY. This function allows the MAC to indicate its + * maximum speed, and so limit what the PHY will advertise. + */ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed) { int err; @@ -306,6 +328,16 @@ void of_set_phy_eee_broken(struct phy_device *phydev) phydev->eee_broken_modes = broken; } +/** + * phy_resolve_aneg_pause - Determine pause autoneg results + * + * @phydev: The phy_device struct + * + * Once autoneg has completed the local pause settings can be + * resolved. Determine if pause and asymmetric pause should be used + * by the MAC. + */ + void phy_resolve_aneg_pause(struct phy_device *phydev) { if (phydev->duplex == DUPLEX_FULL) { @@ -319,7 +351,7 @@ void phy_resolve_aneg_pause(struct phy_device *phydev) EXPORT_SYMBOL_GPL(phy_resolve_aneg_pause); /** - * phy_resolve_aneg_linkmode - resolve the advertisements into phy settings + * phy_resolve_aneg_linkmode - resolve the advertisements into PHY settings * @phydev: The phy_device struct * * Resolve our and the link partner advertisements into their corresponding diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 8947d58f2a25..35525a671400 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -456,7 +456,16 @@ int phy_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } EXPORT_SYMBOL(phy_do_ioctl); -/* same as phy_do_ioctl, but ensures that net_device is running */ +/** + * phy_do_ioctl_running - generic ndo_do_ioctl implementation but test first + * + * @dev: the net_device struct + * @ifr: &struct ifreq for socket ioctl's + * @cmd: ioctl cmd to execute + * + * Same as phy_do_ioctl, but ensures that net_device is running before + * handling the ioctl. + */ int phy_do_ioctl_running(struct net_device *dev, struct ifreq *ifr, int cmd) { if (!netif_running(dev)) @@ -466,6 +475,12 @@ int phy_do_ioctl_running(struct net_device *dev, struct ifreq *ifr, int cmd) } EXPORT_SYMBOL(phy_do_ioctl_running); +/** + * phy_queue_state_machine - Trigger the state machine to run soon + * + * @phydev: the phy_device struct + * @jiffies: Run the state machine after these jiffies + */ void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies) { mod_delayed_work(system_power_efficient_wq, &phydev->state_queue, @@ -473,6 +488,11 @@ void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies) } EXPORT_SYMBOL(phy_queue_state_machine); +/** + * phy_queue_state_machine - Trigger the state machine to run now + * + * @phydev: the phy_device struct + */ static void phy_trigger_machine(struct phy_device *phydev) { phy_queue_state_machine(phydev, 0); @@ -489,6 +509,12 @@ static void phy_abort_cable_test(struct phy_device *phydev) phydev_err(phydev, "Error while aborting cable test"); } +/** + * phy_ethtool_get_strings - Get the statistic counter names + * + * @phydev: the phy_device struct + * @data: Where to put the strings + */ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data) { if (!phydev->drv) @@ -502,6 +528,11 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data) } EXPORT_SYMBOL(phy_ethtool_get_strings); +/** + * phy_ethtool_get_sset_count - Get the number of statistic counters + * + * @phydev: the phy_device struct + */ int phy_ethtool_get_sset_count(struct phy_device *phydev) { int ret; @@ -523,6 +554,13 @@ int phy_ethtool_get_sset_count(struct phy_device *phydev) } EXPORT_SYMBOL(phy_ethtool_get_sset_count); +/** + * phy_ethtool_get_stats - Get the statistic counters + * + * @phydev: the phy_device struct + * @stats: What counters to get + * @data: Where to store the counters + */ int phy_ethtool_get_stats(struct phy_device *phydev, struct ethtool_stats *stats, u64 *data) { @@ -537,6 +575,12 @@ int phy_ethtool_get_stats(struct phy_device *phydev, } EXPORT_SYMBOL(phy_ethtool_get_stats); +/** + * phy_start_cable_test - Start a cable test + * + * @phydev: the phy_device struct + * @extack: extack for reporting useful error messages + */ int phy_start_cable_test(struct phy_device *phydev, struct netlink_ext_ack *extack) { @@ -600,6 +644,13 @@ out: } EXPORT_SYMBOL(phy_start_cable_test); +/** + * phy_start_cable_test_tdr - Start a raw TDR cable test + * + * @phydev: the phy_device struct + * @extack: extack for reporting useful error messages + * @config: Configuration of the test to run + */ int phy_start_cable_test_tdr(struct phy_device *phydev, struct netlink_ext_ack *extack, const struct phy_tdr_config *config) @@ -1363,6 +1414,12 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) } EXPORT_SYMBOL(phy_ethtool_set_eee); +/** + * phy_ethtool_set_wol - Configure Wake On LAN + * + * @phydev: target phy_device struct + * @wol: Configuration requested + */ int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { if (phydev->drv && phydev->drv->set_wol) @@ -1372,6 +1429,12 @@ int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) } EXPORT_SYMBOL(phy_ethtool_set_wol); +/** + * phy_ethtool_get_wol - Get the current Wake On LAN configuration + * + * @phydev: target phy_device struct + * @wol: Store the current configuration here + */ void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { if (phydev->drv && phydev->drv->get_wol) @@ -1405,6 +1468,10 @@ int phy_ethtool_set_link_ksettings(struct net_device *ndev, } EXPORT_SYMBOL(phy_ethtool_set_link_ksettings); +/** + * phy_ethtool_nway_reset - Restart auto negotiation + * @ndev: Network device to restart autoneg for + */ int phy_ethtool_nway_reset(struct net_device *ndev) { struct phy_device *phydev = ndev->phydev; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 32f4e8ec96cf..fe2296fdda19 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -535,8 +535,10 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, if (pl->pcs_ops) pl->pcs_ops->pcs_get_state(pl->pcs, state); - else + else if (pl->mac_ops->mac_pcs_get_state) pl->mac_ops->mac_pcs_get_state(pl->config, state); + else + state->link = 0; } /* The fixed state is... fixed except for the link state, @@ -2319,6 +2321,49 @@ static void phylink_decode_sgmii_word(struct phylink_link_state *state, } /** + * phylink_decode_usxgmii_word() - decode the USXGMII word from a MAC PCS + * @state: a pointer to a struct phylink_link_state. + * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word + * + * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation + * code word. Decode the USXGMII code word and populate the corresponding fields + * (speed, duplex) into the phylink_link_state structure. + */ +void phylink_decode_usxgmii_word(struct phylink_link_state *state, + uint16_t lpa) +{ + switch (lpa & MDIO_USXGMII_SPD_MASK) { + case MDIO_USXGMII_10: + state->speed = SPEED_10; + break; + case MDIO_USXGMII_100: + state->speed = SPEED_100; + break; + case MDIO_USXGMII_1000: + state->speed = SPEED_1000; + break; + case MDIO_USXGMII_2500: + state->speed = SPEED_2500; + break; + case MDIO_USXGMII_5000: + state->speed = SPEED_5000; + break; + case MDIO_USXGMII_10G: + state->speed = SPEED_10000; + break; + default: + state->link = false; + return; + } + + if (lpa & MDIO_USXGMII_FULL_DUPLEX) + state->duplex = DUPLEX_FULL; + else + state->duplex = DUPLEX_HALF; +} +EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word); + +/** * phylink_mii_c22_pcs_get_state() - read the MAC PCS state * @pcs: a pointer to a &struct mdio_device. * @state: a pointer to a &struct phylink_link_state. @@ -2361,6 +2406,7 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, break; case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: phylink_decode_sgmii_word(state, lpa); break; diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 0f0960971800..575580d3ffe0 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -26,11 +26,16 @@ #define RTL821x_EXT_PAGE_SELECT 0x1e #define RTL821x_PAGE_SELECT 0x1f +#define RTL8211F_PHYCR1 0x18 #define RTL8211F_INSR 0x1d #define RTL8211F_TX_DELAY BIT(8) #define RTL8211F_RX_DELAY BIT(3) +#define RTL8211F_ALDPS_PLL_OFF BIT(1) +#define RTL8211F_ALDPS_ENABLE BIT(2) +#define RTL8211F_ALDPS_XTAL_OFF BIT(12) + #define RTL8211E_CTRL_DELAY BIT(13) #define RTL8211E_TX_DELAY BIT(12) #define RTL8211E_RX_DELAY BIT(11) @@ -177,8 +182,12 @@ static int rtl8211f_config_init(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; u16 val_txdly, val_rxdly; + u16 val; int ret; + val = RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_XTAL_OFF; + phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, val, val); + switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: val_txdly = 0; @@ -401,7 +410,7 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, return ret; } -static int rtl8125_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) { int ret = rtlgen_read_mmd(phydev, devnum, regnum); @@ -425,7 +434,7 @@ static int rtl8125_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) return ret; } -static int rtl8125_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, +static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val) { int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); @@ -442,7 +451,7 @@ static int rtl8125_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, return ret; } -static int rtl8125_get_features(struct phy_device *phydev) +static int rtl822x_get_features(struct phy_device *phydev) { int val; @@ -460,7 +469,7 @@ static int rtl8125_get_features(struct phy_device *phydev) return genphy_read_abilities(phydev); } -static int rtl8125_config_aneg(struct phy_device *phydev) +static int rtl822x_config_aneg(struct phy_device *phydev) { int ret = 0; @@ -480,7 +489,7 @@ static int rtl8125_config_aneg(struct phy_device *phydev) return __genphy_config_aneg(phydev, ret); } -static int rtl8125_read_status(struct phy_device *phydev) +static int rtl822x_read_status(struct phy_device *phydev) { int ret; @@ -522,7 +531,7 @@ static int rtlgen_match_phy_device(struct phy_device *phydev) !rtlgen_supports_2_5gbps(phydev); } -static int rtl8125_match_phy_device(struct phy_device *phydev) +static int rtl8226_match_phy_device(struct phy_device *phydev) { return phydev->phy_id == RTL_GENERIC_PHYID && rtlgen_supports_2_5gbps(phydev); @@ -542,6 +551,8 @@ static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), .name = "RTL8201CP Ethernet", + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, }, { PHY_ID_MATCH_EXACT(0x001cc816), .name = "RTL8201F Fast Ethernet", @@ -627,29 +638,29 @@ static struct phy_driver realtek_drvs[] = { .read_mmd = rtlgen_read_mmd, .write_mmd = rtlgen_write_mmd, }, { - .name = "RTL8125 2.5Gbps internal", - .match_phy_device = rtl8125_match_phy_device, - .get_features = rtl8125_get_features, - .config_aneg = rtl8125_config_aneg, - .read_status = rtl8125_read_status, + .name = "RTL8226 2.5Gbps PHY", + .match_phy_device = rtl8226_match_phy_device, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, - .read_mmd = rtl8125_read_mmd, - .write_mmd = rtl8125_write_mmd, + .read_mmd = rtl822x_read_mmd, + .write_mmd = rtl822x_write_mmd, }, { PHY_ID_MATCH_EXACT(0x001cc840), - .name = "RTL8125B 2.5Gbps internal", - .get_features = rtl8125_get_features, - .config_aneg = rtl8125_config_aneg, - .read_status = rtl8125_read_status, + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, - .read_mmd = rtl8125_read_mmd, - .write_mmd = rtl8125_write_mmd, + .read_mmd = rtl822x_read_mmd, + .write_mmd = rtl822x_write_mmd, }, { PHY_ID_MATCH_EXACT(0x001cc961), .name = "RTL8366RB Gigabit Ethernet", diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index cf83314c8591..34aa196b7465 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -7,6 +7,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/jiffies.h> +#include <linux/mdio/mdio-i2c.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> @@ -16,7 +17,6 @@ #include <linux/slab.h> #include <linux/workqueue.h> -#include "mdio-i2c.h" #include "sfp.h" #include "swphy.h" @@ -2389,7 +2389,8 @@ static int sfp_probe(struct platform_device *pdev) continue; sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]); - if (!sfp->gpio_irq[i]) { + if (sfp->gpio_irq[i] < 0) { + sfp->gpio_irq[i] = 0; sfp->need_poll = true; continue; } diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 74568ae16125..0fc39ac5ca88 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -12,6 +12,7 @@ * */ +#include <linux/clk.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mii.h> @@ -21,6 +22,17 @@ #include <linux/netdevice.h> #include <linux/smscphy.h> +/* Vendor-specific PHY Definitions */ +/* EDPD NLP / crossover time configuration */ +#define PHY_EDPD_CONFIG 16 +#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x0001 + +/* Control/Status Indication Register */ +#define SPECIAL_CTRL_STS 27 +#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x8000 +#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x4000 +#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x2000 + struct smsc_hw_stat { const char *string; u8 reg; @@ -33,14 +45,22 @@ static struct smsc_hw_stat smsc_hw_stats[] = { struct smsc_phy_priv { bool energy_enable; + struct clk *refclk; }; static int smsc_phy_config_intr(struct phy_device *phydev) { - int rc = phy_write (phydev, MII_LAN83C185_IM, - ((PHY_INTERRUPT_ENABLED == phydev->interrupts) - ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS - : 0)); + struct smsc_phy_priv *priv = phydev->priv; + u16 intmask = 0; + int rc; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6; + if (priv->energy_enable) + intmask |= MII_LAN83C185_ISF_INT7; + } + + rc = phy_write(phydev, MII_LAN83C185_IM, intmask); return rc < 0 ? rc : 0; } @@ -55,19 +75,21 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev) { struct smsc_phy_priv *priv = phydev->priv; + int rc; - int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); + if (!priv->energy_enable) + return 0; + + rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0) return rc; - if (priv->energy_enable) { - /* Enable energy detect mode for this SMSC Transceivers */ - rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - if (rc < 0) - return rc; - } + /* Enable energy detect mode for this SMSC Transceivers */ + rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, + rc | MII_LAN83C185_EDPWRDOWN); + if (rc < 0) + return rc; return smsc_phy_ack_interrupt(phydev); } @@ -96,6 +118,54 @@ static int lan911x_config_init(struct phy_device *phydev) return smsc_phy_ack_interrupt(phydev); } +static int lan87xx_config_aneg(struct phy_device *phydev) +{ + int rc; + int val; + + switch (phydev->mdix_ctrl) { + case ETH_TP_MDI: + val = SPECIAL_CTRL_STS_OVRRD_AMDIX_; + break; + case ETH_TP_MDI_X: + val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ | + SPECIAL_CTRL_STS_AMDIX_STATE_; + break; + case ETH_TP_MDI_AUTO: + val = SPECIAL_CTRL_STS_AMDIX_ENABLE_; + break; + default: + return genphy_config_aneg(phydev); + } + + rc = phy_read(phydev, SPECIAL_CTRL_STS); + if (rc < 0) + return rc; + + rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ | + SPECIAL_CTRL_STS_AMDIX_ENABLE_ | + SPECIAL_CTRL_STS_AMDIX_STATE_); + rc |= val; + phy_write(phydev, SPECIAL_CTRL_STS, rc); + + phydev->mdix = phydev->mdix_ctrl; + return genphy_config_aneg(phydev); +} + +static int lan87xx_config_aneg_ext(struct phy_device *phydev) +{ + int rc; + + /* Extend Manual AutoMDIX timer */ + rc = phy_read(phydev, PHY_EDPD_CONFIG); + if (rc < 0) + return rc; + + rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_; + phy_write(phydev, PHY_EDPD_CONFIG, rc); + return lan87xx_config_aneg(phydev); +} + /* * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to @@ -185,11 +255,20 @@ static void smsc_get_stats(struct phy_device *phydev, data[i] = smsc_get_stat(phydev, i); } +static void smsc_phy_remove(struct phy_device *phydev) +{ + struct smsc_phy_priv *priv = phydev->priv; + + clk_disable_unprepare(priv->refclk); + clk_put(priv->refclk); +} + static int smsc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; struct smsc_phy_priv *priv; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -202,6 +281,21 @@ static int smsc_phy_probe(struct phy_device *phydev) phydev->priv = priv; + /* Make clk optional to keep DTB backward compatibility. */ + priv->refclk = clk_get_optional(dev, NULL); + if (IS_ERR(priv->refclk)) + dev_err_probe(dev, PTR_ERR(priv->refclk), "Failed to request clock\n"); + + ret = clk_prepare_enable(priv->refclk); + if (ret) + return ret; + + ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000); + if (ret) { + clk_disable_unprepare(priv->refclk); + return ret; + } + return 0; } @@ -250,6 +344,9 @@ static struct phy_driver smsc_phy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, }, { + /* This covers internal PHY (phy_id: 0x0007C0C3) for + * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505) + */ .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */ .phy_id_mask = 0xfffffff0, .name = "SMSC LAN8700", @@ -262,6 +359,7 @@ static struct phy_driver smsc_phy_driver[] = { .read_status = lan87xx_read_status, .config_init = smsc_phy_config_init, .soft_reset = smsc_phy_reset, + .config_aneg = lan87xx_config_aneg, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, @@ -293,19 +391,23 @@ static struct phy_driver smsc_phy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, }, { + /* This covers internal PHY (phy_id: 0x0007C0F0) for + * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01) + */ .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */ .phy_id_mask = 0xfffffff0, .name = "SMSC LAN8710/LAN8720", /* PHY_BASIC_FEATURES */ - .flags = PHY_RST_AFTER_CLK_EN, .probe = smsc_phy_probe, + .remove = smsc_phy_remove, /* basic functions */ .read_status = lan87xx_read_status, .config_init = smsc_phy_config_init, .soft_reset = smsc_phy_reset, + .config_aneg = lan87xx_config_aneg_ext, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index 7475cef17cf7..ca49c1ad3efc 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -300,7 +300,7 @@ static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, struct device *dev; struct ks8995_switch *ks8995; - dev = container_of(kobj, struct device, kobj); + dev = kobj_to_dev(kobj); ks8995 = dev_get_drvdata(dev); return ks8995_read(ks8995, buf, off, count); @@ -312,7 +312,7 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, struct device *dev; struct ks8995_switch *ks8995; - dev = container_of(kobj, struct device, kobj); + dev = kobj_to_dev(kobj); ks8995 = dev_get_drvdata(dev); return ks8995_write(ks8995, buf, off, count); |