1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright © 2021-2022 Bjoern A. Zeeb 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/kernel.h> 30 #include <sys/bus.h> 31 #include <sys/rman.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/endian.h> 35 #include <sys/socket.h> 36 37 #include <machine/bus.h> 38 #include <machine/resource.h> 39 40 #include <contrib/dev/acpica/include/acpi.h> 41 #include <dev/acpica/acpivar.h> 42 43 #include <net/if.h> 44 #include <net/if_var.h> 45 #include <net/if_media.h> 46 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 50 #include "memac_mdio.h" 51 #include "memac_mdio_if.h" 52 #include "acpi_bus_if.h" 53 #include "miibus_if.h" 54 55 /* -------------------------------------------------------------------------- */ 56 57 struct memacphy_softc_acpi { 58 struct memacphy_softc_common scc; 59 int uid; 60 uint64_t phy_channel; 61 char compatible[64]; 62 }; 63 64 static void 65 memacphy_acpi_miibus_statchg(device_t dev) 66 { 67 struct memacphy_softc_acpi *sc; 68 69 sc = device_get_softc(dev); 70 memacphy_miibus_statchg(&sc->scc); 71 } 72 73 static int 74 memacphy_acpi_set_ni_dev(device_t dev, device_t nidev) 75 { 76 struct memacphy_softc_acpi *sc; 77 78 sc = device_get_softc(dev); 79 return (memacphy_set_ni_dev(&sc->scc, nidev)); 80 } 81 82 static int 83 memacphy_acpi_get_phy_loc(device_t dev, int *phy_loc) 84 { 85 struct memacphy_softc_acpi *sc; 86 87 sc = device_get_softc(dev); 88 return (memacphy_get_phy_loc(&sc->scc, phy_loc)); 89 } 90 91 static int 92 memacphy_acpi_probe(device_t dev) 93 { 94 95 device_set_desc(dev, "MEMAC PHY (acpi)"); 96 return (BUS_PROBE_DEFAULT); 97 } 98 99 static int 100 memacphy_acpi_attach(device_t dev) 101 { 102 struct memacphy_softc_acpi *sc; 103 ACPI_HANDLE h; 104 ssize_t s; 105 106 sc = device_get_softc(dev); 107 sc->scc.dev = dev; 108 h = acpi_get_handle(dev); 109 110 s = acpi_GetInteger(h, "_UID", &sc->uid); 111 if (ACPI_FAILURE(s)) { 112 device_printf(dev, "Cannot get '_UID' property: %zd\n", s); 113 return (ENXIO); 114 } 115 116 s = device_get_property(dev, "phy-channel", 117 &sc->phy_channel, sizeof(sc->phy_channel), DEVICE_PROP_UINT64); 118 if (s != -1) 119 sc->scc.phy = sc->phy_channel; 120 else 121 sc->scc.phy = -1; 122 s = device_get_property(dev, "compatible", 123 sc->compatible, sizeof(sc->compatible), DEVICE_PROP_ANY); 124 125 if (bootverbose) 126 device_printf(dev, "UID %#04x phy-channel %ju compatible '%s' phy %u\n", 127 sc->uid, sc->phy_channel, 128 sc->compatible[0] != '\0' ? sc->compatible : "", sc->scc.phy); 129 130 if (sc->scc.phy == -1) 131 return (ENXIO); 132 return (0); 133 } 134 135 static device_method_t memacphy_acpi_methods[] = { 136 /* Device interface */ 137 DEVMETHOD(device_probe, memacphy_acpi_probe), 138 DEVMETHOD(device_attach, memacphy_acpi_attach), 139 DEVMETHOD(device_detach, bus_generic_detach), 140 141 /* MII interface */ 142 DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), 143 DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), 144 DEVMETHOD(miibus_statchg, memacphy_acpi_miibus_statchg), 145 146 /* memac */ 147 DEVMETHOD(memac_mdio_set_ni_dev, memacphy_acpi_set_ni_dev), 148 DEVMETHOD(memac_mdio_get_phy_loc, memacphy_acpi_get_phy_loc), 149 150 DEVMETHOD_END 151 }; 152 153 DEFINE_CLASS_0(memacphy_acpi, memacphy_acpi_driver, memacphy_acpi_methods, 154 sizeof(struct memacphy_softc_acpi)); 155 156 EARLY_DRIVER_MODULE(memacphy_acpi, memac_mdio_acpi, memacphy_acpi_driver, 0, 0, 157 BUS_PASS_SUPPORTDEV); 158 DRIVER_MODULE(miibus, memacphy_acpi, miibus_driver, 0, 0); 159 MODULE_DEPEND(memacphy_acpi, miibus, 1, 1, 1); 160 161 /* -------------------------------------------------------------------------- */ 162 163 struct memac_mdio_softc_acpi { 164 struct memac_mdio_softc_common scc; 165 }; 166 167 static int 168 memac_acpi_miibus_readreg(device_t dev, int phy, int reg) 169 { 170 struct memac_mdio_softc_acpi *sc; 171 172 sc = device_get_softc(dev); 173 return (memac_miibus_readreg(&sc->scc, phy, reg)); 174 } 175 176 static int 177 memac_acpi_miibus_writereg(device_t dev, int phy, int reg, int data) 178 { 179 struct memac_mdio_softc_acpi *sc; 180 181 sc = device_get_softc(dev); 182 return (memac_miibus_writereg(&sc->scc, phy, reg, data)); 183 } 184 185 /* Context for walking PHY child devices. */ 186 struct memac_mdio_walk_ctx { 187 device_t dev; 188 int count; 189 int countok; 190 }; 191 192 static char *memac_mdio_ids[] = { 193 "NXP0006", 194 NULL 195 }; 196 197 static int 198 memac_mdio_acpi_probe(device_t dev) 199 { 200 int rc; 201 202 if (acpi_disabled("fsl_memac_mdio")) 203 return (ENXIO); 204 205 rc = ACPI_ID_PROBE(device_get_parent(dev), dev, memac_mdio_ids, NULL); 206 if (rc <= 0) 207 device_set_desc(dev, "Freescale XGMAC MDIO Bus"); 208 209 return (rc); 210 } 211 212 static ACPI_STATUS 213 memac_mdio_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) 214 { 215 struct memac_mdio_walk_ctx *ctx; 216 struct acpi_device *ad; 217 device_t child; 218 uint32_t adr; 219 220 ctx = (struct memac_mdio_walk_ctx *)arg; 221 ctx->count++; 222 223 if (ACPI_FAILURE(acpi_GetInteger(h, "_ADR", &adr))) 224 return (AE_OK); 225 226 /* Technically M_ACPIDEV */ 227 if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) 228 return (AE_OK); 229 230 child = device_add_child(ctx->dev, "memacphy_acpi", -1); 231 if (child == NULL) { 232 free(ad, M_DEVBUF); 233 return (AE_OK); 234 } 235 ad->ad_handle = h; 236 ad->ad_cls_class = 0xffffff; 237 resource_list_init(&ad->ad_rl); 238 device_set_ivars(child, ad); 239 *dev = child; 240 241 ctx->countok++; 242 return (AE_OK); 243 } 244 245 static int 246 memac_mdio_acpi_attach(device_t dev) 247 { 248 struct memac_mdio_softc_acpi *sc; 249 struct memac_mdio_walk_ctx ctx; 250 int error; 251 252 sc = device_get_softc(dev); 253 sc->scc.dev = dev; 254 255 error = memac_mdio_generic_attach(&sc->scc); 256 if (error != 0) 257 return (error); 258 259 ctx.dev = dev; 260 ctx.count = 0; 261 ctx.countok = 0; 262 ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 1, 263 memac_mdio_acpi_probe_child, &ctx); 264 if (ctx.countok > 0) { 265 bus_generic_probe(dev); 266 bus_generic_attach(dev); 267 } 268 269 return (0); 270 } 271 272 static int 273 memac_mdio_acpi_detach(device_t dev) 274 { 275 struct memac_mdio_softc_acpi *sc; 276 277 sc = device_get_softc(dev); 278 return (memac_mdio_generic_detach(&sc->scc)); 279 } 280 281 static device_method_t memac_mdio_acpi_methods[] = { 282 /* Device interface */ 283 DEVMETHOD(device_probe, memac_mdio_acpi_probe), 284 DEVMETHOD(device_attach, memac_mdio_acpi_attach), 285 DEVMETHOD(device_detach, memac_mdio_acpi_detach), 286 287 /* MII interface */ 288 DEVMETHOD(miibus_readreg, memac_acpi_miibus_readreg), 289 DEVMETHOD(miibus_writereg, memac_acpi_miibus_writereg), 290 291 /* .. */ 292 DEVMETHOD(bus_add_child, bus_generic_add_child), 293 DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), 294 DEVMETHOD(bus_get_property, memac_mdio_get_property), 295 296 DEVMETHOD_END 297 }; 298 299 DEFINE_CLASS_0(memac_mdio_acpi, memac_mdio_acpi_driver, memac_mdio_acpi_methods, 300 sizeof(struct memac_mdio_softc_acpi)); 301 302 EARLY_DRIVER_MODULE(memac_mdio_acpi, acpi, memac_mdio_acpi_driver, 0, 0, 303 BUS_PASS_SUPPORTDEV); 304 305 DRIVER_MODULE(miibus, memac_mdio_acpi, miibus_driver, 0, 0); 306 MODULE_DEPEND(memac_mdio_acpi, miibus, 1, 1, 1); 307 MODULE_VERSION(memac_mdio_acpi, 1); 308