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 const struct ofw_bus_devinfo *xmdio_fdt_get_devinfo(device_t, device_t); 55 static int xmdio_miibus_readreg(device_t dev, int phy, int reg); 56 static int xmdio_miibus_writereg(device_t dev, int phy, int reg, int value); 57 static int xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg); 58 static int xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, 59 int val); 60 61 struct xmdio_softc { 62 struct mtx sc_lock; 63 struct resource *sc_res; 64 }; 65 66 static struct ofw_compat_data mdio_compat_data[] = { 67 {"fsl,fman-memac-mdio", 0}, 68 {"fsl,fman-xmdio", 0}, 69 {NULL, 0} 70 }; 71 72 static device_method_t xmdio_methods[] = { 73 /* Device interface */ 74 DEVMETHOD(device_probe, xmdio_fdt_probe), 75 DEVMETHOD(device_attach, xmdio_fdt_attach), 76 DEVMETHOD(device_detach, xmdio_detach), 77 DEVMETHOD(bus_add_child, bus_generic_add_child), 78 79 /* MII interface */ 80 DEVMETHOD(miibus_readreg, xmdio_miibus_readreg), 81 DEVMETHOD(miibus_writereg, xmdio_miibus_writereg), 82 83 /* MDIO interface */ 84 DEVMETHOD(mdio_readreg, xmdio_miibus_readreg), 85 DEVMETHOD(mdio_writereg, xmdio_miibus_writereg), 86 DEVMETHOD(mdio_readextreg, xmdio_mdio_readextreg), 87 DEVMETHOD(mdio_writeextreg, xmdio_mdio_writeextreg), 88 89 /* ofw_bus interface -- expose devinfo of the FDT children we added. */ 90 DEVMETHOD(ofw_bus_get_devinfo, xmdio_fdt_get_devinfo), 91 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 92 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 93 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 94 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 95 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 96 97 DEVMETHOD_END 98 }; 99 100 static driver_t xmdio_driver = { 101 "mdio", 102 xmdio_methods, 103 sizeof(struct xmdio_softc), 104 }; 105 106 EARLY_DRIVER_MODULE(mdio, fman, xmdio_driver, 0, 0, BUS_PASS_SUPPORTDEV); 107 MODULE_DEPEND(mdio, miibus, 1, 1, 1); 108 109 static int 110 xmdio_fdt_probe(device_t dev) 111 { 112 113 if (!ofw_bus_status_okay(dev)) 114 return (ENXIO); 115 116 if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str) 117 return (ENXIO); 118 119 device_set_desc(dev, "Freescale XGMAC MDIO"); 120 121 return (BUS_PROBE_DEFAULT); 122 } 123 124 static int 125 xmdio_fdt_attach(device_t dev) 126 { 127 struct xmdio_softc *sc; 128 struct ofw_bus_devinfo *obd; 129 phandle_t node, child; 130 device_t cdev; 131 132 sc = device_get_softc(dev); 133 134 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); 135 136 OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); 137 138 mtx_init(&sc->sc_lock, device_get_nameunit(dev), "XMDIO lock", 139 MTX_DEF); 140 141 node = ofw_bus_get_node(dev); 142 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 143 if (!OF_hasprop(child, "reg")) 144 continue; 145 obd = malloc(sizeof(*obd), M_DEVBUF, M_WAITOK | M_ZERO); 146 if (ofw_bus_gen_setup_devinfo(obd, child) != 0) { 147 free(obd, M_DEVBUF); 148 continue; 149 } 150 cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 151 if (cdev == NULL) { 152 ofw_bus_gen_destroy_devinfo(obd); 153 free(obd, M_DEVBUF); 154 continue; 155 } 156 device_set_ivars(cdev, obd); 157 } 158 159 bus_identify_children(dev); 160 bus_enumerate_hinted_children(dev); 161 bus_attach_children(dev); 162 return (0); 163 164 return (0); 165 } 166 167 static int 168 xmdio_detach(device_t dev) 169 { 170 struct xmdio_softc *sc; 171 172 sc = device_get_softc(dev); 173 174 mtx_destroy(&sc->sc_lock); 175 176 return (0); 177 } 178 179 static void 180 set_clause45(struct xmdio_softc *sc) 181 { 182 uint32_t reg; 183 184 reg = MDIO_READ4(sc, MDIO_CFG); 185 MDIO_WRITE4(sc, MDIO_CFG, reg | CFG_ENC45); 186 } 187 188 static void 189 set_clause22(struct xmdio_softc *sc) 190 { 191 uint32_t reg; 192 193 reg = MDIO_READ4(sc, MDIO_CFG); 194 MDIO_WRITE4(sc, MDIO_CFG, reg & ~CFG_ENC45); 195 } 196 197 static int 198 xmdio_wait_no_busy(struct xmdio_softc *sc) 199 { 200 uint32_t count, val; 201 202 for (count = 1000; count > 0; count--) { 203 val = MDIO_READ4(sc, MDIO_CFG); 204 if ((val & STAT_BUSY) == 0) 205 break; 206 DELAY(1); 207 } 208 209 if (count == 0) 210 return (0xffff); 211 212 return (0); 213 } 214 215 int 216 xmdio_miibus_readreg(device_t dev, int phy, int reg) 217 { 218 struct xmdio_softc *sc; 219 int rv; 220 uint32_t ctl; 221 222 sc = device_get_softc(dev); 223 224 MDIO_LOCK(); 225 226 set_clause22(sc); 227 ctl = (phy << 5) | reg; 228 MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); 229 230 MDIO_READ4(sc, MDIO_CTL); 231 232 if (xmdio_wait_no_busy(sc)) 233 rv = 0xffff; 234 else 235 rv = MDIO_READ4(sc, MDIO_DATA); 236 237 MDIO_WRITE4(sc, MDIO_CTL, 0); 238 MDIO_UNLOCK(); 239 240 return (rv); 241 } 242 243 int 244 xmdio_miibus_writereg(device_t dev, int phy, int reg, int value) 245 { 246 struct xmdio_softc *sc; 247 248 sc = device_get_softc(dev); 249 250 MDIO_LOCK(); 251 set_clause22(sc); 252 /* Stop the MII management read cycle */ 253 MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | reg); 254 255 MDIO_WRITE4(sc, MDIO_DATA, value); 256 257 /* Wait till MII management write is complete */ 258 xmdio_wait_no_busy(sc); 259 MDIO_UNLOCK(); 260 261 return (0); 262 } 263 264 static int 265 xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg) 266 { 267 struct xmdio_softc *sc; 268 int rv; 269 uint32_t ctl; 270 271 sc = device_get_softc(dev); 272 273 MDIO_LOCK(); 274 275 set_clause45(sc); 276 ctl = (phy << 5) | devad; 277 MDIO_WRITE4(sc, MDIO_CTL, ctl); 278 MDIO_WRITE4(sc, MDIO_ADDR, reg); 279 xmdio_wait_no_busy(sc); 280 MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); 281 MDIO_READ4(sc, MDIO_CTL); 282 283 xmdio_wait_no_busy(sc); 284 285 if (MDIO_READ4(sc, MDIO_STAT) & STAT_MDIO_RD_ER) 286 rv = 0xffff; 287 else 288 rv = MDIO_READ4(sc, MDIO_DATA); 289 290 MDIO_WRITE4(sc, MDIO_CTL, 0); 291 MDIO_UNLOCK(); 292 293 return (rv); 294 } 295 296 static int 297 xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, int val) 298 { 299 struct xmdio_softc *sc; 300 301 sc = device_get_softc(dev); 302 303 MDIO_LOCK(); 304 set_clause45(sc); 305 /* Stop the MII management read cycle */ 306 MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | devad); 307 308 MDIO_WRITE4(sc, MDIO_DATA, val); 309 310 /* Wait till MII management write is complete */ 311 xmdio_wait_no_busy(sc); 312 MDIO_UNLOCK(); 313 314 return (0); 315 } 316 317 static const struct ofw_bus_devinfo * 318 xmdio_fdt_get_devinfo(device_t bus __unused, device_t child) 319 { 320 321 return (device_get_ivars(child)); 322 } 323 324