1 /* 2 * Copyright (c) 2026 Justin Hibbits 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/param.h> 8 #include <sys/systm.h> 9 #include <sys/kernel.h> 10 #include <sys/bus.h> 11 #include <sys/module.h> 12 #include <sys/mutex.h> 13 #include <sys/resource.h> 14 #include <sys/socket.h> 15 16 #include <machine/bus.h> 17 18 #include <net/if.h> 19 #include <net/if_media.h> 20 #include <net/if_types.h> 21 #include <net/if_var.h> 22 23 #include <dev/mdio/mdio.h> 24 #include <dev/mii/mii.h> 25 #include <dev/mii/miivar.h> 26 27 #include <dev/ofw/ofw_bus.h> 28 #include <dev/ofw/ofw_bus_subr.h> 29 30 #include "fman.h" 31 #include "miibus_if.h" 32 #include "mdio_if.h" 33 34 #define MDIO_LOCK() mtx_lock(&sc->sc_lock) 35 #define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock) 36 #define MDIO_WRITE4(sc, r, v) \ 37 bus_write_4(sc->sc_res, r, v) 38 #define MDIO_READ4(sc, r) \ 39 bus_read_4(sc->sc_res, r) 40 41 #define MDIO_CFG 0x30 42 #define CFG_ENC45 0x00000040 43 #define MDIO_STAT 0x30 44 #define STAT_BUSY 0x80000000 45 #define STAT_MDIO_RD_ER 0x00000002 46 #define MDIO_CTL 0x34 47 #define CTL_READ 0x00008000 48 #define MDIO_DATA 0x38 49 #define MDIO_ADDR 0x3c 50 51 static int xmdio_fdt_probe(device_t dev); 52 static int xmdio_fdt_attach(device_t dev); 53 static int xmdio_detach(device_t dev); 54 static int xmdio_miibus_readreg(device_t dev, int phy, int reg); 55 static int xmdio_miibus_writereg(device_t dev, int phy, int reg, int value); 56 static int xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg); 57 static int xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, 58 int val); 59 60 struct xmdio_softc { 61 struct mtx sc_lock; 62 struct resource *sc_res; 63 }; 64 65 static struct ofw_compat_data mdio_compat_data[] = { 66 {"fsl,fman-memac-mdio", 0}, 67 {"fsl,fman-xmdio", 0}, 68 {NULL, 0} 69 }; 70 71 static device_method_t xmdio_methods[] = { 72 /* Device interface */ 73 DEVMETHOD(device_probe, xmdio_fdt_probe), 74 DEVMETHOD(device_attach, xmdio_fdt_attach), 75 DEVMETHOD(device_detach, xmdio_detach), 76 DEVMETHOD(bus_add_child, bus_generic_add_child), 77 78 /* MII interface */ 79 DEVMETHOD(miibus_readreg, xmdio_miibus_readreg), 80 DEVMETHOD(miibus_writereg, xmdio_miibus_writereg), 81 82 /* MDIO interface */ 83 DEVMETHOD(mdio_readreg, xmdio_miibus_readreg), 84 DEVMETHOD(mdio_writereg, xmdio_miibus_writereg), 85 DEVMETHOD(mdio_readextreg, xmdio_mdio_readextreg), 86 DEVMETHOD(mdio_writeextreg, xmdio_mdio_writeextreg), 87 88 DEVMETHOD_END 89 }; 90 91 static driver_t xmdio_driver = { 92 "xmdio", 93 xmdio_methods, 94 sizeof(struct xmdio_softc), 95 }; 96 97 EARLY_DRIVER_MODULE(xmdio, fman, xmdio_driver, 0, 0, 98 BUS_PASS_SUPPORTDEV); 99 DRIVER_MODULE(miibus, xmdio, miibus_driver, 0, 0); 100 DRIVER_MODULE(mdio, xmdio, mdio_driver, 0, 0); 101 MODULE_DEPEND(xmdio, miibus, 1, 1, 1); 102 103 static int 104 xmdio_fdt_probe(device_t dev) 105 { 106 107 if (!ofw_bus_status_okay(dev)) 108 return (ENXIO); 109 110 if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str) 111 return (ENXIO); 112 113 device_set_desc(dev, "Freescale XGMAC MDIO"); 114 115 return (BUS_PROBE_DEFAULT); 116 } 117 118 static int 119 xmdio_fdt_attach(device_t dev) 120 { 121 struct xmdio_softc *sc; 122 123 sc = device_get_softc(dev); 124 125 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); 126 127 OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); 128 129 mtx_init(&sc->sc_lock, device_get_nameunit(dev), "XMDIO lock", 130 MTX_DEF); 131 132 return (0); 133 } 134 135 static int 136 xmdio_detach(device_t dev) 137 { 138 struct xmdio_softc *sc; 139 140 sc = device_get_softc(dev); 141 142 mtx_destroy(&sc->sc_lock); 143 144 return (0); 145 } 146 147 static void 148 set_clause45(struct xmdio_softc *sc) 149 { 150 uint32_t reg; 151 152 reg = MDIO_READ4(sc, MDIO_CFG); 153 MDIO_WRITE4(sc, MDIO_CFG, reg | CFG_ENC45); 154 } 155 156 static void 157 set_clause22(struct xmdio_softc *sc) 158 { 159 uint32_t reg; 160 161 reg = MDIO_READ4(sc, MDIO_CFG); 162 MDIO_WRITE4(sc, MDIO_CFG, reg & ~CFG_ENC45); 163 } 164 165 static int 166 xmdio_wait_no_busy(struct xmdio_softc *sc) 167 { 168 uint32_t count, val; 169 170 for (count = 1000; count > 0; count--) { 171 val = MDIO_READ4(sc, MDIO_CFG); 172 if ((val & STAT_BUSY) == 0) 173 break; 174 DELAY(1); 175 } 176 177 if (count == 0) 178 return (0xffff); 179 180 return (0); 181 } 182 183 int 184 xmdio_miibus_readreg(device_t dev, int phy, int reg) 185 { 186 struct xmdio_softc *sc; 187 int rv; 188 uint32_t ctl; 189 190 sc = device_get_softc(dev); 191 192 MDIO_LOCK(); 193 194 set_clause22(sc); 195 ctl = (phy << 5) | reg; 196 MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); 197 198 MDIO_READ4(sc, MDIO_CTL); 199 200 if (xmdio_wait_no_busy(sc)) 201 rv = 0xffff; 202 else 203 rv = MDIO_READ4(sc, MDIO_DATA); 204 205 MDIO_WRITE4(sc, MDIO_CTL, 0); 206 MDIO_UNLOCK(); 207 208 return (rv); 209 } 210 211 int 212 xmdio_miibus_writereg(device_t dev, int phy, int reg, int value) 213 { 214 struct xmdio_softc *sc; 215 216 sc = device_get_softc(dev); 217 218 MDIO_LOCK(); 219 set_clause22(sc); 220 /* Stop the MII management read cycle */ 221 MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | reg); 222 223 MDIO_WRITE4(sc, MDIO_DATA, value); 224 225 /* Wait till MII management write is complete */ 226 xmdio_wait_no_busy(sc); 227 MDIO_UNLOCK(); 228 229 return (0); 230 } 231 232 static int 233 xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg) 234 { 235 struct xmdio_softc *sc; 236 int rv; 237 uint32_t ctl; 238 239 sc = device_get_softc(dev); 240 241 MDIO_LOCK(); 242 243 set_clause45(sc); 244 ctl = (phy << 5) | devad; 245 MDIO_WRITE4(sc, MDIO_CTL, ctl); 246 MDIO_WRITE4(sc, MDIO_ADDR, reg); 247 xmdio_wait_no_busy(sc); 248 MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); 249 MDIO_READ4(sc, MDIO_CTL); 250 251 xmdio_wait_no_busy(sc); 252 253 if (MDIO_READ4(sc, MDIO_STAT) & STAT_MDIO_RD_ER) 254 rv = 0xffff; 255 else 256 rv = MDIO_READ4(sc, MDIO_DATA); 257 258 MDIO_WRITE4(sc, MDIO_CTL, 0); 259 MDIO_UNLOCK(); 260 261 return (rv); 262 } 263 264 static int 265 xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, int val) 266 { 267 struct xmdio_softc *sc; 268 269 sc = device_get_softc(dev); 270 271 MDIO_LOCK(); 272 set_clause45(sc); 273 /* Stop the MII management read cycle */ 274 MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | devad); 275 276 MDIO_WRITE4(sc, MDIO_DATA, val); 277 278 /* Wait till MII management write is complete */ 279 xmdio_wait_no_busy(sc); 280 MDIO_UNLOCK(); 281 282 return (0); 283 } 284 285