Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'add-support-for-pic64-hpsc-hx-mdio-controller'

Charles Perry says:

====================
Add support for PIC64-HPSC/HX MDIO controller

This series adds a driver for the two MDIO controllers of PIC64-HPSC/HX.
The hardware supports C22 and C45 but only C22 is implemented for now.

This MDIO hardware is based on a Microsemi design supported in Linux by
mdio-mscc-miim.c. However, The register interface is completely different
with pic64hpsc, hence the need for a separate driver.

The documentation recommends an input clock of 156.25MHz and a prescaler of
39, which yields an MDIO clock of 1.95MHz.

This was tested on Microchip HB1301 evalkit which has a VSC8574 and a
VSC8541. I've tested with bus frequencies of 0.6, 1.95 and 2.5 MHz.

This series also adds a PHY write barrier when disabling PHY interrupts as
discussed in: https://lore.kernel.org/acvUqDgepCIScs8M@shell.armlinux.org.uk
====================

Link: https://patch.msgid.link/20260408131821.1145334-1-charles.perry@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+296 -1
+68
Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/microchip,pic64hpsc-mdio.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Microchip PIC64-HPSC/HX MDIO controller 8 + 9 + maintainers: 10 + - Charles Perry <charles.perry@microchip.com> 11 + 12 + description: 13 + This is the MDIO bus controller present in Microchip PIC64-HPSC/HX SoCs. It 14 + supports C22 and C45 register access and is named "MDIO Initiator" in the 15 + documentation. 16 + 17 + allOf: 18 + - $ref: mdio.yaml# 19 + 20 + properties: 21 + compatible: 22 + oneOf: 23 + - const: microchip,pic64hpsc-mdio 24 + - items: 25 + - const: microchip,pic64hx-mdio 26 + - const: microchip,pic64hpsc-mdio 27 + 28 + reg: 29 + maxItems: 1 30 + 31 + clocks: 32 + maxItems: 1 33 + 34 + clock-frequency: 35 + default: 2500000 36 + 37 + interrupts: 38 + maxItems: 1 39 + 40 + required: 41 + - compatible 42 + - reg 43 + - clocks 44 + - interrupts 45 + 46 + unevaluatedProperties: false 47 + 48 + examples: 49 + - | 50 + #include <dt-bindings/interrupt-controller/irq.h> 51 + bus { 52 + #address-cells = <2>; 53 + #size-cells = <2>; 54 + 55 + mdio@4000c21e000 { 56 + compatible = "microchip,pic64hpsc-mdio"; 57 + reg = <0x400 0x0c21e000 0x0 0x1000>; 58 + #address-cells = <1>; 59 + #size-cells = <0>; 60 + clocks = <&svc_clk>; 61 + interrupt-parent = <&saplic0>; 62 + interrupts = <168 IRQ_TYPE_LEVEL_HIGH>; 63 + 64 + ethernet-phy@0 { 65 + reg = <0>; 66 + }; 67 + }; 68 + };
+6
MAINTAINERS
··· 17392 17392 S: Maintained 17393 17393 F: drivers/tty/serial/8250/8250_pci1xxxx.c 17394 17394 17395 + MICROCHIP PIC64-HPSC/HX DRIVERS 17396 + M: Charles Perry <charles.perry@microchip.com> 17397 + S: Supported 17398 + F: Documentation/devicetree/bindings/net/microchip,pic64hpsc-mdio.yaml 17399 + F: drivers/net/mdio/mdio-pic64hpsc.c 17400 + 17395 17401 MICROCHIP POLARFIRE FPGA DRIVERS 17396 17402 M: Conor Dooley <conor.dooley@microchip.com> 17397 17403 L: linux-fpga@vger.kernel.org
+7
drivers/net/mdio/Kconfig
··· 145 145 buses. It is required by the Octeon and ThunderX ethernet device 146 146 drivers on some systems. 147 147 148 + config MDIO_PIC64HPSC 149 + tristate "PIC64-HPSC/HX MDIO interface support" 150 + depends on HAS_IOMEM && OF_MDIO 151 + help 152 + This driver supports the MDIO interface found on the PIC64-HPSC/HX 153 + SoCs. 154 + 148 155 config MDIO_IPQ4019 149 156 tristate "Qualcomm IPQ4019 MDIO interface support" 150 157 depends on HAS_IOMEM && OF_MDIO
+1
drivers/net/mdio/Makefile
··· 20 20 obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o 21 21 obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o 22 22 obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o 23 + obj-$(CONFIG_MDIO_PIC64HPSC) += mdio-pic64hpsc.o 23 24 obj-$(CONFIG_MDIO_REALTEK_RTL9300) += mdio-realtek-rtl9300.o 24 25 obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o 25 26 obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
+190
drivers/net/mdio/mdio-pic64hpsc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Microchip PIC64-HPSC/HX MDIO controller driver 3 + * 4 + * Copyright (c) 2026 Microchip Technology Inc. and its subsidiaries. 5 + */ 6 + 7 + #include <linux/bitops.h> 8 + #include <linux/clk.h> 9 + #include <linux/io.h> 10 + #include <linux/iopoll.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/of_mdio.h> 14 + #include <linux/platform_device.h> 15 + 16 + #define MDIO_REG_PRESCALER 0x20 17 + #define MDIO_CFG_PRESCALE_MASK GENMASK(7, 0) 18 + 19 + #define MDIO_REG_FRAME_CFG_1 0x24 20 + #define MDIO_WDATA_MASK GENMASK(15, 0) 21 + 22 + #define MDIO_REG_FRAME_CFG_2 0x28 23 + #define MDIO_TRIGGER_BIT BIT(31) 24 + #define MDIO_REG_DEV_ADDR_MASK GENMASK(20, 16) 25 + #define MDIO_PHY_PRT_ADDR_MASK GENMASK(8, 4) 26 + #define MDIO_OPERATION_MASK GENMASK(3, 2) 27 + #define MDIO_START_OF_FRAME_MASK GENMASK(1, 0) 28 + 29 + /* Possible value of MDIO_OPERATION_MASK */ 30 + #define MDIO_OPERATION_WRITE BIT(0) 31 + #define MDIO_OPERATION_READ BIT(1) 32 + 33 + #define MDIO_REG_FRAME_STATUS 0x2C 34 + #define MDIO_READOK_BIT BIT(24) 35 + #define MDIO_RDATA_MASK GENMASK(15, 0) 36 + 37 + struct pic64hpsc_mdio_dev { 38 + void __iomem *regs; 39 + }; 40 + 41 + static int pic64hpsc_mdio_wait_trigger(struct mii_bus *bus) 42 + { 43 + struct pic64hpsc_mdio_dev *priv = bus->priv; 44 + u32 val; 45 + int ret; 46 + 47 + /* The MDIO_TRIGGER bit returns 0 when a transaction has completed. */ 48 + ret = readl_poll_timeout(priv->regs + MDIO_REG_FRAME_CFG_2, val, 49 + !(val & MDIO_TRIGGER_BIT), 50, 10000); 50 + 51 + if (ret < 0) 52 + dev_dbg(&bus->dev, "TRIGGER bit timeout: %x\n", val); 53 + 54 + return ret; 55 + } 56 + 57 + static int pic64hpsc_mdio_c22_read(struct mii_bus *bus, int mii_id, int regnum) 58 + { 59 + struct pic64hpsc_mdio_dev *priv = bus->priv; 60 + u32 val; 61 + int ret; 62 + 63 + ret = pic64hpsc_mdio_wait_trigger(bus); 64 + if (ret) 65 + return ret; 66 + 67 + writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) | 68 + FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) | 69 + FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_READ) | 70 + FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1), 71 + priv->regs + MDIO_REG_FRAME_CFG_2); 72 + 73 + ret = pic64hpsc_mdio_wait_trigger(bus); 74 + if (ret) 75 + return ret; 76 + 77 + val = readl(priv->regs + MDIO_REG_FRAME_STATUS); 78 + 79 + /* The MDIO_READOK is a 1-bit value reflecting the inverse of the MDIO 80 + * bus value captured during the 2nd TA cycle. A PHY/Port should drive 81 + * the MDIO bus with a logic 0 on the 2nd TA cycle, however, the 82 + * PHY/Port could optionally drive a logic 1, to communicate a read 83 + * failure. This feature is optional, not defined by the 802.3 standard 84 + * and not supported in standard external PHYs. 85 + */ 86 + if (!(bus->phy_ignore_ta_mask & 1 << mii_id) && 87 + !FIELD_GET(MDIO_READOK_BIT, val)) { 88 + dev_dbg(&bus->dev, "READOK bit cleared\n"); 89 + return -EIO; 90 + } 91 + 92 + return FIELD_GET(MDIO_RDATA_MASK, val); 93 + } 94 + 95 + static int pic64hpsc_mdio_c22_write(struct mii_bus *bus, int mii_id, int regnum, 96 + u16 value) 97 + { 98 + struct pic64hpsc_mdio_dev *priv = bus->priv; 99 + int ret; 100 + 101 + ret = pic64hpsc_mdio_wait_trigger(bus); 102 + if (ret < 0) 103 + return ret; 104 + 105 + writel(FIELD_PREP(MDIO_WDATA_MASK, value), 106 + priv->regs + MDIO_REG_FRAME_CFG_1); 107 + 108 + writel(MDIO_TRIGGER_BIT | FIELD_PREP(MDIO_REG_DEV_ADDR_MASK, regnum) | 109 + FIELD_PREP(MDIO_PHY_PRT_ADDR_MASK, mii_id) | 110 + FIELD_PREP(MDIO_OPERATION_MASK, MDIO_OPERATION_WRITE) | 111 + FIELD_PREP(MDIO_START_OF_FRAME_MASK, 1), 112 + priv->regs + MDIO_REG_FRAME_CFG_2); 113 + 114 + return 0; 115 + } 116 + 117 + static int pic64hpsc_mdio_probe(struct platform_device *pdev) 118 + { 119 + struct device_node *np = pdev->dev.of_node; 120 + struct device *dev = &pdev->dev; 121 + struct pic64hpsc_mdio_dev *priv; 122 + struct mii_bus *bus; 123 + unsigned long rate; 124 + struct clk *clk; 125 + u32 bus_freq; 126 + u32 div; 127 + int ret; 128 + 129 + bus = devm_mdiobus_alloc_size(dev, sizeof(*priv)); 130 + if (!bus) 131 + return -ENOMEM; 132 + 133 + priv = bus->priv; 134 + 135 + priv->regs = devm_platform_ioremap_resource(pdev, 0); 136 + if (IS_ERR(priv->regs)) 137 + return PTR_ERR(priv->regs); 138 + 139 + bus->name = KBUILD_MODNAME; 140 + bus->read = pic64hpsc_mdio_c22_read; 141 + bus->write = pic64hpsc_mdio_c22_write; 142 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); 143 + bus->parent = dev; 144 + 145 + clk = devm_clk_get_enabled(dev, NULL); 146 + if (IS_ERR(clk)) 147 + return PTR_ERR(clk); 148 + 149 + if (of_property_read_u32(np, "clock-frequency", &bus_freq)) 150 + bus_freq = 2500000; 151 + 152 + rate = clk_get_rate(clk); 153 + 154 + div = DIV_ROUND_UP(rate, 2 * bus_freq) - 1; 155 + if (div == 0 || div & ~MDIO_CFG_PRESCALE_MASK) { 156 + dev_err(dev, "MDIO clock-frequency out of range\n"); 157 + return -EINVAL; 158 + } 159 + 160 + dev_dbg(dev, "rate=%lu bus_freq=%u real_bus_freq=%lu div=%u\n", rate, 161 + bus_freq, rate / (2 * (1 + div)), div); 162 + writel(div, priv->regs + MDIO_REG_PRESCALER); 163 + 164 + ret = devm_of_mdiobus_register(dev, bus, np); 165 + if (ret) { 166 + dev_err(dev, "Cannot register MDIO bus (%d)\n", ret); 167 + return ret; 168 + } 169 + 170 + return 0; 171 + } 172 + 173 + static const struct of_device_id pic64hpsc_mdio_match[] = { 174 + { .compatible = "microchip,pic64hpsc-mdio" }, 175 + {} 176 + }; 177 + MODULE_DEVICE_TABLE(of, pic64hpsc_mdio_match); 178 + 179 + static struct platform_driver pic64hpsc_mdio_driver = { 180 + .probe = pic64hpsc_mdio_probe, 181 + .driver = { 182 + .name = KBUILD_MODNAME, 183 + .of_match_table = pic64hpsc_mdio_match, 184 + }, 185 + }; 186 + module_platform_driver(pic64hpsc_mdio_driver); 187 + 188 + MODULE_AUTHOR("Charles Perry <charles.perry@microchip.com>"); 189 + MODULE_DESCRIPTION("Microchip PIC64-HPSC/HX MDIO driver"); 190 + MODULE_LICENSE("GPL");
+24 -1
drivers/net/phy/phy.c
··· 1369 1369 EXPORT_SYMBOL(phy_error); 1370 1370 1371 1371 /** 1372 + * phy_write_barrier - ensure the last write completed for this PHY device 1373 + * @phydev: target phy_device struct 1374 + * 1375 + * MDIO bus controllers are not required to wait for write transactions to 1376 + * complete before returning. Calling this function ensures that the previous 1377 + * write has completed. 1378 + */ 1379 + static void phy_write_barrier(struct phy_device *phydev) 1380 + { 1381 + if (mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, MII_PHYSID1) == 1382 + -EOPNOTSUPP) 1383 + mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr, 1384 + MDIO_MMD_PMAPMD, MII_PHYSID1); 1385 + } 1386 + 1387 + /** 1372 1388 * phy_disable_interrupts - Disable the PHY interrupts from the PHY side 1373 1389 * @phydev: target phy_device struct 1374 1390 */ 1375 1391 int phy_disable_interrupts(struct phy_device *phydev) 1376 1392 { 1393 + int err; 1394 + 1377 1395 /* Disable PHY interrupts */ 1378 - return phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); 1396 + err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); 1397 + if (err) 1398 + return err; 1399 + 1400 + phy_write_barrier(phydev); 1401 + return 0; 1379 1402 } 1380 1403 1381 1404 /**