diff options
| author | Tom Rini <[email protected]> | 2026-01-15 08:50:53 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-01-15 08:50:53 -0600 |
| commit | 5665d1f4e7cfd6895417d199dd7db73500c5d36c (patch) | |
| tree | a57a8ba13152f9416a756b85a2e0abee8e288304 /drivers | |
| parent | d503633a36767d756c7de28305cf0de79440cbc0 (diff) | |
| parent | b61d7d95cc62525060f0d05881bdaaf994a55b11 (diff) | |
Merge tag 'net-20260115' of https://source.denx.de/u-boot/custodians/u-boot-net
Pull request net-20260115.
CI: https://source.denx.de/u-boot/custodians/u-boot-net/-/pipelines/29008
net:
- phy: micrel KSZ9031 and KSZ9021 fixes
- phy: marvell10g fix
- Fix "net stats" help
- Add Microsemi/Microchip MDIO driver
- tftpput: Rework to exclude code from xPL phases
net-legacy:
- Some refactoring to help with lwIP NF support
net-lwip:
- Add NFS support
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/net/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/mdio-mscc-miim.c | 136 | ||||
| -rw-r--r-- | drivers/net/phy/marvell10g.c | 14 | ||||
| -rw-r--r-- | drivers/net/phy/micrel_ksz90x1.c | 66 |
5 files changed, 212 insertions, 13 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 13e631c55dc..0089f74c69d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1069,6 +1069,14 @@ config ASPEED_MDIO This driver supports the MDIO bus of Aspeed AST2600 SOC. The driver currently supports Clause 22. +config MDIO_MSCC_MIIM + bool "Microsemi MIIM interface support" + depends on DM_MDIO + select REGMAP + help + This driver supports MDIO interface found in Microsemi and Microchip + network switches. + config MDIO_MUX_MMIOREG bool "MDIO MUX accessed as a MMIO register access" depends on DM_MDIO_MUX diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a3c3420898c..5bb40480d88 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_LITEETH) += liteeth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o +obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o diff --git a/drivers/net/mdio-mscc-miim.c b/drivers/net/mdio-mscc-miim.c new file mode 100644 index 00000000000..5700b872586 --- /dev/null +++ b/drivers/net/mdio-mscc-miim.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <asm/io.h> +#include <dm.h> +#include <time.h> +#include <regmap.h> +#include <miiphy.h> +#include <linux/bitfield.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_MIIM_DATA_MASK GENMASK(15, 0) +#define MSCC_MIIM_REG_CFG 0x10 +#define MSCC_MIIM_CFG_PRESCALE_MASK GENMASK(7, 0) +/* 01 = Clause 22, 00 = Clause 45 */ +#define MSCC_MIIM_CFG_ST_CFG_MASK GENMASK(10, 9) +#define MSCC_MIIM_C22 1 +#define MSCC_MIIM_C45 0 + +#define MSCC_MDIO_TIMEOUT 10000 +#define MSCC_MDIO_SLEEP 50 + +struct mscc_mdio_priv { + struct regmap *map; +}; + +static int mscc_mdio_wait_busy(struct mscc_mdio_priv *priv) +{ + u32 busy; + + return regmap_read_poll_timeout(priv->map, MSCC_MIIM_REG_STATUS, busy, + (busy & MSCC_MIIM_STATUS_STAT_BUSY) == 0, + MSCC_MDIO_SLEEP, + MSCC_MDIO_TIMEOUT); +} + +static int mscc_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mscc_mdio_priv *priv = dev_get_priv(dev); + u32 val; + int ret; + + if (mscc_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + ret = regmap_write(priv->map, MSCC_MIIM_REG_CMD, + MSCC_MIIM_CMD_VLD | + (addr << MSCC_MIIM_CMD_PHYAD_SHIFT) | + (reg << MSCC_MIIM_CMD_REGAD_SHIFT) | + MSCC_MIIM_CMD_OPR_READ); + if (ret) + return ret; + + if (mscc_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + regmap_read(priv->map, MSCC_MIIM_REG_DATA, &val); + if (val & MSCC_MIIM_DATA_ERROR) + return -EIO; + + return FIELD_GET(MSCC_MIIM_DATA_MASK, val); +} + +int mscc_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val) +{ + struct mscc_mdio_priv *priv = dev_get_priv(dev); + int ret; + + if (mscc_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + ret = regmap_write(priv->map, MSCC_MIIM_REG_CMD, + MSCC_MIIM_CMD_VLD | + (addr << MSCC_MIIM_CMD_PHYAD_SHIFT) | + (reg << MSCC_MIIM_CMD_REGAD_SHIFT) | + (val << MSCC_MIIM_CMD_WRDATA_SHIFT) | + MSCC_MIIM_CMD_OPR_WRITE); + + return ret; +} + +static const struct mdio_ops mscc_mdio_ops = { + .read = mscc_mdio_read, + .write = mscc_mdio_write, +}; + +static int mscc_mdio_bind(struct udevice *dev) +{ + if (ofnode_valid(dev_ofnode(dev))) + device_set_name(dev, ofnode_get_name(dev_ofnode(dev))); + + return 0; +} + +static int mscc_mdio_probe(struct udevice *dev) +{ + struct mscc_mdio_priv *priv = dev_get_priv(dev); + int ret; + + ret = regmap_init_mem(dev_ofnode(dev), &priv->map); + if (ret) + return -EINVAL; + + /* Enter Clause 22 mode */ + ret = regmap_update_bits(priv->map, MSCC_MIIM_REG_CFG, + MSCC_MIIM_CFG_ST_CFG_MASK, + FIELD_PREP(MSCC_MIIM_CFG_ST_CFG_MASK, + MSCC_MIIM_C22)); + + return ret; +} + +static const struct udevice_id mscc_mdio_ids[] = { + { .compatible = "mscc,ocelot-miim", }, + { } +}; + +U_BOOT_DRIVER(mscc_mdio) = { + .name = "mscc_mdio", + .id = UCLASS_MDIO, + .of_match = mscc_mdio_ids, + .bind = mscc_mdio_bind, + .probe = mscc_mdio_probe, + .ops = &mscc_mdio_ops, + .priv_auto = sizeof(struct mscc_mdio_priv), +}; diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 8c95bcbb9ad..d6115eea025 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -342,8 +342,7 @@ static int mv2110_select_mactype(struct phy_device *phydev) { if (phydev->interface == PHY_INTERFACE_MODE_USXGMII) return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII; - else if (phydev->interface == PHY_INTERFACE_MODE_SGMII && - !(phydev->interface == PHY_INTERFACE_MODE_10GBASER)) + else if (phydev->interface == PHY_INTERFACE_MODE_SGMII) return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER; else if (phydev->interface == PHY_INTERFACE_MODE_10GBASER) return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; @@ -381,15 +380,6 @@ static int mv3310_select_mactype(struct phy_device *phydev) { if (phydev->interface == PHY_INTERFACE_MODE_USXGMII) return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII; - else if (phydev->interface == PHY_INTERFACE_MODE_SGMII && - phydev->interface == PHY_INTERFACE_MODE_10GBASER) - return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER; - else if (phydev->interface == PHY_INTERFACE_MODE_SGMII && - phydev->interface == PHY_INTERFACE_MODE_RXAUI) - return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI; - else if (phydev->interface == PHY_INTERFACE_MODE_SGMII && - phydev->interface == PHY_INTERFACE_MODE_XAUI) - return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI; else if (phydev->interface == PHY_INTERFACE_MODE_10GBASER) return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; else if (phydev->interface == PHY_INTERFACE_MODE_RXAUI) @@ -542,7 +532,7 @@ static bool mv3310_has_downshift(struct phy_device *phydev) } #define mv_test_bit(iface, phydev) \ - ({ if ((phydev)->interface & (iface)) return 0; }) + ({ if ((phydev)->interface == (iface)) return 0; }) static int mv3310_mv3340_test_supported_interfaces(struct phy_device *phydev) { diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index a02dbe900b8..f357e0f1c77 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -189,7 +189,10 @@ static int ksz9031_of_config(struct phy_device *phydev) { MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 }, { MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 }, }; + const unsigned int master = CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; + struct udevice *dev = phydev->dev; int i, ret = 0; + ofnode node; for (i = 0; i < ARRAY_SIZE(ofcfg); i++) { ret = ksz90x1_of_config_group(phydev, &ofcfg[i], @@ -198,7 +201,39 @@ static int ksz9031_of_config(struct phy_device *phydev) return ret; } - return 0; + node = phydev->node; + + /* Look for a PHY node under the Ethernet node */ + if (!ofnode_valid(node)) + node = dev_read_subnode(dev, "ethernet-phy"); + + /* No node found, look in the Ethernet node */ + if (!ofnode_valid(node)) + node = dev_ofnode(dev); + + /* Silicon Errata Sheet (DS80000691D or DS80000692D): + * When the device links in the 1000BASE-T slave mode only, + * the optional 125MHz reference output clock (CLK125_NDO) + * has wide duty cycle variation. + * + * The optional CLK125_NDO clock does not meet the RGMII + * 45/55 percent (min/max) duty cycle requirement and therefore + * cannot be used directly by the MAC side for clocking + * applications that have setup/hold time requirements on + * rising and falling clock edges. + * + * Workaround: + * Force the phy to be the master to receive a stable clock + * which meets the duty cycle requirement. + */ + if (ofnode_read_bool(node, "micrel,force-master")) { + ret = phy_modify(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, + master | CTRL1000_PREFER_MASTER, master); + if (ret < 0) + pr_err("KSZ9031: error applying 'micrel,force-master'\n"); + } + + return ret; } static int ksz9031_center_flp_timing(struct phy_device *phydev) @@ -217,6 +252,31 @@ static int ksz9031_center_flp_timing(struct phy_device *phydev) return ret; } +static void ksz90x1_workaround_asymmetric_pause(struct phy_device *phydev) +{ + u32 features = phydev->drv->features; + + /* Silicon Errata Sheet (DS80000691D or DS80000692D): + * Whenever the device's Asymmetric Pause capability is set to 1, + * link-up may fail after a link-up to link-down transition. + * + * The Errata Sheet is for ksz9031, but ksz9021 has the same issue + * + * Workaround: + * Do not enable the Asymmetric Pause capability bit. + */ + features &= ~ADVERTISE_PAUSE_ASYM; + + /* We force setting the Pause capability as the core will force the + * Asymmetric Pause capability to 1 otherwise. + */ + features |= ADVERTISE_PAUSE_CAP; + + /* update feature support and forward to advertised features */ + phydev->supported = features; + phydev->advertising = phydev->supported; +} + /* * KSZ9021 */ @@ -260,6 +320,8 @@ static int ksz9021_config(struct phy_device *phydev) if (ret) return ret; + ksz90x1_workaround_asymmetric_pause(phydev); + if (env_get("disable_giga")) features &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); @@ -345,6 +407,8 @@ static int ksz9031_config(struct phy_device *phydev) if (ret) return ret; + ksz90x1_workaround_asymmetric_pause(phydev); + /* add an option to disable the gigabit feature of this PHY */ if (env_get("disable_giga")) { unsigned features; |
