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"); 191