summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-01-15 08:50:53 -0600
committerTom Rini <[email protected]>2026-01-15 08:50:53 -0600
commit5665d1f4e7cfd6895417d199dd7db73500c5d36c (patch)
treea57a8ba13152f9416a756b85a2e0abee8e288304 /drivers
parentd503633a36767d756c7de28305cf0de79440cbc0 (diff)
parentb61d7d95cc62525060f0d05881bdaaf994a55b11 (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/Kconfig8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/mdio-mscc-miim.c136
-rw-r--r--drivers/net/phy/marvell10g.c14
-rw-r--r--drivers/net/phy/micrel_ksz90x1.c66
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;