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