sys/conf/files.arm64 | 6 +- sys/dev/dpaa2/dpaa2_mc_acpi.c | 4 +- sys/dev/dpaa2/dpaa2_mc_fdt.c | 6 +- sys/dev/dpaa2/dpaa2_ni.c | 10 +- sys/dev/dpaa2/memac_mdio.c | 724 -------------------------------------- sys/dev/dpaa2/memac_mdio.h | 64 ++++ sys/dev/dpaa2/memac_mdio_acpi.c | 310 ++++++++++++++++ sys/dev/dpaa2/memac_mdio_common.c | 307 ++++++++++++++++ sys/dev/dpaa2/memac_mdio_fdt.c | 308 ++++++++++++++++ sys/modules/dpaa2/Makefile | 11 +- 10 files changed, 1013 insertions(+), 737 deletions(-) diff --git sys/conf/files.arm64 sys/conf/files.arm64 index 3f0deb31ff11..77fb1398ab79 100644 --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -339,12 +339,14 @@ dev/dpaa2/dpaa2_mc_acpi.c optional SOC_NXP_LS dpaa2 acpi dev/dpaa2/dpaa2_mc_fdt.c optional SOC_NXP_LS dpaa2 fdt dev/dpaa2/dpaa2_mc_if.m optional SOC_NXP_LS dpaa2 dev/dpaa2/dpaa2_mcp.c optional SOC_NXP_LS dpaa2 -dev/dpaa2/memac_mdio.c optional SOC_NXP_LS dpaa2 acpi | SOC_NXP_LS dpaa2 fdt -dev/dpaa2/memac_mdio_if.m optional SOC_NXP_LS dpaa2 acpi | SOC_NXP_LS dpaa2 fdt dev/dpaa2/dpaa2_ni.c optional SOC_NXP_LS dpaa2 dev/dpaa2/dpaa2_rc.c optional SOC_NXP_LS dpaa2 dev/dpaa2/dpaa2_swp.c optional SOC_NXP_LS dpaa2 dev/dpaa2/dpaa2_swp_if.m optional SOC_NXP_LS dpaa2 +dev/dpaa2/memac_mdio_acpi.c optional soc_nxp_ls dpaa2 acpi +dev/dpaa2/memac_mdio_common.c optional soc_nxp_ls dpaa2 acpi | soc_nxp_ls dpaa2 fdt +dev/dpaa2/memac_mdio_fdt.c optional soc_nxp_ls dpaa2 fdt +dev/dpaa2/memac_mdio_if.m optional soc_nxp_ls dpaa2 acpi | soc_nxp_ls dpaa2 fdt ## ## SoC Support diff --git sys/dev/dpaa2/dpaa2_mc_acpi.c sys/dev/dpaa2/dpaa2_mc_acpi.c index 82473aa1056d..34076c1ce8e2 100644 --- sys/dev/dpaa2/dpaa2_mc_acpi.c +++ sys/dev/dpaa2/dpaa2_mc_acpi.c @@ -203,7 +203,7 @@ DEFINE_CLASS_0(dpaa2_mac_dev, dpaa2_mac_dev_driver, dpaa2_mac_dev_methods, DRIVER_MODULE(dpaa2_mac_dev, dpaa2_mc, dpaa2_mac_dev_driver, 0, 0); -MODULE_DEPEND(dpaa2_mac_dev, memac_mdio, 1, 1, 1); +MODULE_DEPEND(dpaa2_mac_dev, memac_mdio_acpi, 1, 1, 1); /* * Device interface. @@ -422,4 +422,4 @@ DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_acpi_driver, dpaa2_mc_acpi_methods, /* Make sure miibus gets procesed first. */ DRIVER_MODULE_ORDERED(dpaa2_mc, acpi, dpaa2_mc_acpi_driver, NULL, NULL, SI_ORDER_ANY); -MODULE_DEPEND(dpaa2_mc, memac_mdio, 1, 1, 1); +MODULE_DEPEND(dpaa2_mc, memac_mdio_acpi, 1, 1, 1); diff --git sys/dev/dpaa2/dpaa2_mc_fdt.c sys/dev/dpaa2/dpaa2_mc_fdt.c index c84df72a0941..5d5ad1f40fab 100644 --- sys/dev/dpaa2/dpaa2_mc_fdt.c +++ sys/dev/dpaa2/dpaa2_mc_fdt.c @@ -207,7 +207,7 @@ static device_method_t dpaa2_mac_fdt_methods[] = { DEFINE_CLASS_0(dpaa2_mac_fdt, dpaa2_mac_fdt_driver, dpaa2_mac_fdt_methods, sizeof(struct dpaa2_mac_fdt_softc)); DRIVER_MODULE(dpaa2_mac_fdt, dpaa2_mc, dpaa2_mac_fdt_driver, 0, 0); -MODULE_DEPEND(dpaa2_mac_fdt, memac_mdio, 1, 1, 1); +MODULE_DEPEND(dpaa2_mac_fdt, memac_mdio_fdt, 1, 1, 1); /* * Device interface. @@ -287,7 +287,7 @@ dpaa2_mc_fdt_attach(device_t dev) * FDT compat layer. */ static device_t -dpaa2_mc_acpi_find_dpaa2_mac_dev(device_t dev, uint32_t id) +dpaa2_mc_fdt_find_dpaa2_mac_dev(device_t dev, uint32_t id) { int devcount, error, i, len; device_t *devlist, mdev; @@ -320,7 +320,7 @@ dpaa2_mc_fdt_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id) { device_t mdev, pdev; - mdev = dpaa2_mc_acpi_find_dpaa2_mac_dev(dev, id); + mdev = dpaa2_mc_fdt_find_dpaa2_mac_dev(dev, id); if (mdev == NULL) { device_printf(dev, "%s: error finding dpmac device with id=%u\n", __func__, id); diff --git sys/dev/dpaa2/dpaa2_ni.c sys/dev/dpaa2/dpaa2_ni.c index 2a7a0d7d384f..652f919fc542 100644 --- sys/dev/dpaa2/dpaa2_ni.c +++ sys/dev/dpaa2/dpaa2_ni.c @@ -29,6 +29,9 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_acpi.h" +#include "opt_platform.h" + /* * The DPAA2 Network Interface (DPNI) driver. * @@ -3678,4 +3681,9 @@ DRIVER_MODULE(miibus, dpaa2_ni, miibus_driver, 0, 0); DRIVER_MODULE(dpaa2_ni, dpaa2_rc, dpaa2_ni_driver, 0, 0); MODULE_DEPEND(dpaa2_ni, miibus, 1, 1, 1); -MODULE_DEPEND(dpaa2_ni, memac_mdio, 1, 1, 1); +#ifdef DEV_ACPI +MODULE_DEPEND(dpaa2_ni, memac_mdio_acpi, 1, 1, 1); +#endif +#ifdef FDT +MODULE_DEPEND(dpaa2_ni, memac_mdio_fdt, 1, 1, 1); +#endif diff --git sys/dev/dpaa2/memac_mdio.c sys/dev/dpaa2/memac_mdio.c deleted file mode 100644 index 03ae987b4d1f..000000000000 --- sys/dev/dpaa2/memac_mdio.c +++ /dev/null @@ -1,724 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright © 2021-2022 Bjoern A. Zeeb - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "opt_acpi.h" -#include "opt_platform.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef DEV_ACPI -#include -#include -#endif - -#ifdef FDT -#include -#include -#include -#endif - -#include -#include -#include - -#include -#include - -#include "memac_mdio_if.h" -#ifdef DEV_ACPI -#include "acpi_bus_if.h" -#endif -#ifdef FDT -#include "ofw_bus_if.h" -#endif -#include "miibus_if.h" - -/* -------------------------------------------------------------------------- */ - -struct memacphy_softc { - int phy; -#ifdef FDT - uint32_t reg; - phandle_t xref; -#endif -#ifdef DEV_ACPI - int uid; - uint64_t phy_channel; - char compatible[64]; -#endif - device_t dpnidev; -}; - -static int -memacphy_miibus_readreg(device_t dev, int phy, int reg) -{ - - return (MIIBUS_READREG(device_get_parent(dev), phy, reg)); -} - -static int -memacphy_miibus_writereg(device_t dev, int phy, int reg, int data) -{ - - return (MIIBUS_WRITEREG(device_get_parent(dev), phy, reg, data)); -} - -static void -memacphy_miibus_statchg(device_t dev) -{ - struct memacphy_softc *sc; - - sc = device_get_softc(dev); - - if (sc->dpnidev != NULL) - MIIBUS_STATCHG(sc->dpnidev); -} - -static int -memacphy_set_ni_dev(device_t dev, device_t nidev) -{ - struct memacphy_softc *sc; - - if (nidev == NULL) - return (EINVAL); - -#if 0 - if (bootverbose) - device_printf(dev, "setting nidev %p (%s)\n", - nidev, device_get_nameunit(nidev)); -#endif - - sc = device_get_softc(dev); - if (sc->dpnidev != NULL) - return (EBUSY); - - sc->dpnidev = nidev; - return (0); -} - -static int -memacphy_get_phy_loc(device_t dev, int *phy_loc) -{ - struct memacphy_softc *sc; - int error; - - if (phy_loc == NULL) - return (EINVAL); - - sc = device_get_softc(dev); - if (sc->phy == -1) { - *phy_loc = MII_PHY_ANY; - error = ENODEV; - } else { - *phy_loc = sc->phy; - error = 0; - } - -#if 0 - if (bootverbose) - device_printf(dev, "returning phy_loc %d, error %d\n", - *phy_loc, error); -#endif - - return (error); -} - -#ifdef FDT -static int -memacphy_fdt_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - device_set_desc(dev, "MEMAC PHY (fdt)"); - return (BUS_PROBE_DEFAULT); -} - -static int -memacphy_fdt_attach(device_t dev) -{ - struct memacphy_softc *sc; - phandle_t node; - ssize_t s; - int error; - - sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - - s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg), - DEVICE_PROP_UINT32); - if (s != -1) - sc->phy = sc->reg; - else - sc->phy = -1; - sc->xref = OF_xref_from_node(node); - - error = OF_device_register_xref(sc->xref, dev); - if (error != 0) - device_printf(dev, "Failed to register xref %#x\n", sc->xref); - - if (bootverbose) - device_printf(dev, "node %#x '%s': reg %#x xref %#x phy %u\n", - node, ofw_bus_get_name(dev), sc->reg, sc->xref, sc->phy); - - if (sc->phy == -1) - error = ENXIO; - return (error); -} - -static device_method_t memacphy_fdt_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, memacphy_fdt_probe), - DEVMETHOD(device_attach, memacphy_fdt_attach), - DEVMETHOD(device_detach, bus_generic_detach), - - /* MII interface */ - DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), - DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), - DEVMETHOD(miibus_statchg, memacphy_miibus_statchg), - - /* memac */ - DEVMETHOD(memac_mdio_set_ni_dev, memacphy_set_ni_dev), - DEVMETHOD(memac_mdio_get_phy_loc, memacphy_get_phy_loc), - - DEVMETHOD_END -}; - -DEFINE_CLASS_0(memacphy_fdt, memacphy_fdt_driver, memacphy_fdt_methods, - sizeof(struct memacphy_softc)); - -EARLY_DRIVER_MODULE(memacphy_fdt, memac_mdio, memacphy_fdt_driver, 0, 0, - BUS_PASS_SUPPORTDEV); -DRIVER_MODULE(miibus, memacphy_fdt, miibus_driver, 0, 0); -MODULE_DEPEND(memacphy_fdt, miibus, 1, 1, 1); -#endif - -#ifdef DEV_ACPI -static int -memacphy_acpi_probe(device_t dev) -{ - - device_set_desc(dev, "MEMAC PHY (acpi)"); - return (BUS_PROBE_DEFAULT); -} - -static int -memacphy_acpi_attach(device_t dev) -{ - struct memacphy_softc *sc; - ACPI_HANDLE h; - ssize_t s; - - sc = device_get_softc(dev); - h = acpi_get_handle(dev); - - s = acpi_GetInteger(h, "_UID", &sc->uid); - if (ACPI_FAILURE(s)) { - device_printf(dev, "Cannot get '_UID' property: %zd\n", s); - return (ENXIO); - } - - s = device_get_property(dev, "phy-channel", - &sc->phy_channel, sizeof(sc->phy_channel), DEVICE_PROP_UINT64); - if (s != -1) - sc->phy = sc->phy_channel; - else - sc->phy = -1; - s = device_get_property(dev, "compatible", - sc->compatible, sizeof(sc->compatible), DEVICE_PROP_ANY); - - if (bootverbose) - device_printf(dev, "UID %#04x phy-channel %ju compatible '%s' phy %u\n", - sc->uid, sc->phy_channel, - sc->compatible[0] != '\0' ? sc->compatible : "", sc->phy); - - if (sc->phy == -1) - return (ENXIO); - return (0); -} - -static device_method_t memacphy_acpi_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, memacphy_acpi_probe), - DEVMETHOD(device_attach, memacphy_acpi_attach), - DEVMETHOD(device_detach, bus_generic_detach), - - /* MII interface */ - DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), - DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), - DEVMETHOD(miibus_statchg, memacphy_miibus_statchg), - - /* memac */ - DEVMETHOD(memac_mdio_set_ni_dev, memacphy_set_ni_dev), - DEVMETHOD(memac_mdio_get_phy_loc, memacphy_get_phy_loc), - - DEVMETHOD_END -}; - -DEFINE_CLASS_0(memacphy_acpi, memacphy_acpi_driver, memacphy_acpi_methods, - sizeof(struct memacphy_softc)); - -EARLY_DRIVER_MODULE(memacphy_acpi, memac_mdio, memacphy_acpi_driver, 0, 0, - BUS_PASS_SUPPORTDEV); -DRIVER_MODULE(miibus, memacphy_acpi, miibus_driver, 0, 0); -MODULE_DEPEND(memacphy_acpi, miibus, 1, 1, 1); -#endif - -/* -------------------------------------------------------------------------- */ - -struct memac_mdio_softc { -#ifdef FDT - struct simplebus_softc sb_sc; -#endif - struct resource *mem_res; - bool is_little_endian; -}; - -/* - * MDIO Ethernet Management Interface Registers (internal PCS MDIO PHY) - * 0x0030 MDIO Configuration Register (MDIO_CFG) - * 0x0034 MDIO Control Register (MDIO_CTL) - * 0x0038 MDIO Data Register (MDIO_DATA) - * 0x003c MDIO Register Address Register (MDIO_ADDR) - * - * External MDIO interfaces - * 0x0030 External MDIO Configuration Register (EMDIO_CFG) - * 0x0034 External MDIO Control Register (EMDIO_CTL) - * 0x0038 External MDIO Data Register (EMDIO_DATA) - * 0x003c External MDIO Register Address Register (EMDIO_ADDR) - */ -#define MDIO_CFG 0x00030 -#define MDIO_CFG_MDIO_RD_ER (1 << 1) -#define MDIO_CFG_ENC45 (1 << 6) -#define MDIO_CFG_BUSY (1 << 31) -#define MDIO_CTL 0x00034 -#define MDIO_CTL_READ (1 << 15) -#define MDIO_CTL_PORT_ADDR(_x) (((_x) & 0x1f) << 5) -#define MDIO_CTL_DEV_ADDR(_x) ((_x) & 0x1f) -#define MDIO_DATA 0x00038 -#define MDIO_ADDR 0x0003c - -static uint32_t -memac_read_4(struct memac_mdio_softc *sc, uint32_t reg) -{ - uint32_t v, r; - - v = bus_read_4(sc->mem_res, reg); - if (sc->is_little_endian) - r = le32toh(v); - else - r = be32toh(v); - - return (r); -} - -static void -memac_write_4(struct memac_mdio_softc *sc, uint32_t reg, uint32_t val) -{ - uint32_t v; - - if (sc->is_little_endian) - v = htole32(val); - else - v = htobe32(val); - bus_write_4(sc->mem_res, reg, v); -} - -static uint32_t -memac_miibus_wait_no_busy(struct memac_mdio_softc *sc) -{ - uint32_t count, val; - - for (count = 1000; count > 0; count--) { - val = memac_read_4(sc, MDIO_CFG); - if ((val & MDIO_CFG_BUSY) == 0) - break; - DELAY(1); - } - - if (count == 0) - return (0xffff); - - return (0); -} - -static int -memac_miibus_readreg(device_t dev, int phy, int reg) -{ - struct memac_mdio_softc *sc; - uint32_t cfg, ctl, val; - - sc = device_get_softc(dev); - - /* Set proper Clause 45 mode. */ - cfg = memac_read_4(sc, MDIO_CFG); - /* XXX 45 support? */ - cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */ - memac_write_4(sc, MDIO_CFG, cfg); - - val = memac_miibus_wait_no_busy(sc); - if (val != 0) - return (0xffff); - - /* To whom do we want to talk to.. */ - ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg); - /* XXX do we need two writes for this to work reliably? */ - memac_write_4(sc, MDIO_CTL, ctl | MDIO_CTL_READ); - - val = memac_miibus_wait_no_busy(sc); - if (val != 0) - return (0xffff); - - cfg = memac_read_4(sc, MDIO_CFG); - if (cfg & MDIO_CFG_MDIO_RD_ER) - return (0xffff); - - val = memac_read_4(sc, MDIO_DATA); - val &= 0xffff; - -#if 0 - device_printf(dev, "phy read %d:%d = %#06x\n", phy, reg, val); -#endif - - return (val); -} - -static int -memac_miibus_writereg(device_t dev, int phy, int reg, int data) -{ - struct memac_mdio_softc *sc; - uint32_t cfg, ctl, val; - - sc = device_get_softc(dev); - -#if 0 - device_printf(dev, "phy write %d:%d\n", phy, reg); -#endif - - /* Set proper Clause 45 mode. */ - cfg = memac_read_4(sc, MDIO_CFG); - /* XXX 45 support? */ - cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */ - memac_write_4(sc, MDIO_CFG, cfg); - - val = memac_miibus_wait_no_busy(sc); - if (val != 0) - return (0xffff); - - /* To whom do we want to talk to.. */ - ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg); - memac_write_4(sc, MDIO_CTL, ctl); - - memac_write_4(sc, MDIO_DATA, data & 0xffff); - - val = memac_miibus_wait_no_busy(sc); - if (val != 0) - return (0xffff); - - return (0); -} - -static ssize_t -memac_mdio_get_property(device_t dev, device_t child, const char *propname, - void *propvalue, size_t size, device_property_type_t type) -{ - - return (bus_generic_get_property(dev, child, propname, propvalue, size, type)); -} - -static int -memac_mdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) -{ - - return (BUS_READ_IVAR(device_get_parent(dev), dev, index, result)); -} - - -static int -memac_mdio_generic_attach(device_t dev) -{ - struct memac_mdio_softc *sc; - int rid; - - sc = device_get_softc(dev); - - rid = 0; - sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE | RF_SHAREABLE); - if (sc->mem_res == NULL) { - device_printf(dev, "%s: cannot allocate mem resource\n", - __func__); - return (ENXIO); - } - - sc->is_little_endian = device_has_property(dev, "little-endian"); - - return (0); -} - -static int -memac_mdio_detach(device_t dev) -{ - struct memac_mdio_softc *sc; - - sc = device_get_softc(dev); - - if (sc->mem_res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem_res), sc->mem_res); - - return (0); -} - -#ifdef FDT -static struct ofw_compat_data compat_data[] = { - { "fsl,fman-memac-mdio", 1 }, - { NULL, 0 } -}; - -static int -memac_mdio_fdt_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) - return (ENXIO); - - device_set_desc(dev, "Freescale XGMAC MDIO Bus (FDT)"); - return (BUS_PROBE_DEFAULT); -} - -static int -memac_mdio_fdt_probe_child(device_t bus, phandle_t child) -{ - device_t childdev; - - /* make sure we do not aliready have a device. */ - childdev = ofw_bus_find_child_device_by_phandle(bus, child); - if (childdev != NULL) - return (0); - - childdev = simplebus_add_device(bus, child, 0, NULL, -1, NULL); - if (childdev == NULL) - return (ENXIO); - - return (device_probe_and_attach(childdev)); -} - -static int -memac_mdio_fdt_attach(device_t dev) -{ - phandle_t node, child; - int error; - - error = memac_mdio_generic_attach(dev); - if (error != 0) - return (error); - - /* Attach the *phy* children represented in the device tree. */ - bus_generic_probe(dev); - bus_enumerate_hinted_children(dev); - node = ofw_bus_get_node(dev); - simplebus_init(dev, node); - for (child = OF_child(node); child > 0; child = OF_peer(child)) { - if (!OF_hasprop(child, "reg")) - continue; - if (memac_mdio_fdt_probe_child(dev, child) != 0) - continue; - } - - return (bus_generic_attach(dev)); -} - -static const struct ofw_bus_devinfo * -memac_simplebus_get_devinfo(device_t bus, device_t child) -{ - - return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child)); -} - -static device_method_t memac_mdio_fdt_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, memac_mdio_fdt_probe), - DEVMETHOD(device_attach, memac_mdio_fdt_attach), - DEVMETHOD(device_detach, memac_mdio_detach), - - /* MII interface */ - DEVMETHOD(miibus_readreg, memac_miibus_readreg), - DEVMETHOD(miibus_writereg, memac_miibus_writereg), - - /* OFW/simplebus */ - DEVMETHOD(ofw_bus_get_devinfo, memac_simplebus_get_devinfo), - DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), - DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), - DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), - DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), - DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), - - /* Bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), - DEVMETHOD(bus_get_property, memac_mdio_get_property), - - DEVMETHOD_END -}; - -DEFINE_CLASS_0(memac_mdio, memac_mdio_fdt_driver, memac_mdio_fdt_methods, - sizeof(struct memac_mdio_softc)); - -EARLY_DRIVER_MODULE(memac_mdio, simplebus, memac_mdio_fdt_driver, 0, 0, - BUS_PASS_SUPPORTDEV); -#endif - -#ifdef DEV_ACPI -/* Context for walking PHY child devices. */ -struct memac_mdio_walk_ctx { - device_t dev; - int count; - int countok; -}; - -static char *memac_mdio_ids[] = { - "NXP0006", - NULL -}; - -static int -memac_mdio_acpi_probe(device_t dev) -{ - int rc; - - if (acpi_disabled("fsl_memac_mdio")) - return (ENXIO); - - rc = ACPI_ID_PROBE(device_get_parent(dev), dev, memac_mdio_ids, NULL); - if (rc <= 0) - device_set_desc(dev, "Freescale XGMAC MDIO Bus"); - - return (rc); -} - -static ACPI_STATUS -memac_mdio_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) -{ - struct memac_mdio_walk_ctx *ctx; - struct acpi_device *ad; - device_t child; - uint32_t adr; - - ctx = (struct memac_mdio_walk_ctx *)arg; - ctx->count++; - - if (ACPI_FAILURE(acpi_GetInteger(h, "_ADR", &adr))) - return (AE_OK); - - /* Technically M_ACPIDEV */ - if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) - return (AE_OK); - - child = device_add_child(ctx->dev, "memacphy_acpi", -1); - if (child == NULL) { - free(ad, M_DEVBUF); - return (AE_OK); - } - ad->ad_handle = h; - ad->ad_cls_class = 0xffffff; - resource_list_init(&ad->ad_rl); - device_set_ivars(child, ad); - *dev = child; - - ctx->countok++; - return (AE_OK); -} - -static int -memac_mdio_acpi_attach(device_t dev) -{ - struct memac_mdio_walk_ctx ctx; - int error; - - error = memac_mdio_generic_attach(dev); - if (error != 0) - return (error); - - ctx.dev = dev; - ctx.count = 0; - ctx.countok = 0; - ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 1, - memac_mdio_acpi_probe_child, &ctx); - if (ctx.countok > 0) { - bus_generic_probe(dev); - bus_generic_attach(dev); - } - - return (0); -} - -static device_method_t memac_mdio_acpi_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, memac_mdio_acpi_probe), - DEVMETHOD(device_attach, memac_mdio_acpi_attach), - DEVMETHOD(device_detach, memac_mdio_detach), - - /* MII interface */ - DEVMETHOD(miibus_readreg, memac_miibus_readreg), - DEVMETHOD(miibus_writereg, memac_miibus_writereg), - - /* .. */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), - DEVMETHOD(bus_get_property, memac_mdio_get_property), - - DEVMETHOD_END -}; - -DEFINE_CLASS_0(memac_mdio, memac_mdio_acpi_driver, memac_mdio_acpi_methods, - sizeof(struct memac_mdio_softc)); - -EARLY_DRIVER_MODULE(memac_mdio, acpi, memac_mdio_acpi_driver, 0, 0, - BUS_PASS_SUPPORTDEV); -#endif - -DRIVER_MODULE(miibus, memac_mdio, miibus_driver, 0, 0); -MODULE_DEPEND(memac_mdio, miibus, 1, 1, 1); -MODULE_VERSION(memac_mdio, 1); diff --git sys/dev/dpaa2/memac_mdio.h sys/dev/dpaa2/memac_mdio.h new file mode 100644 index 000000000000..02e4c081f87c --- /dev/null +++ sys/dev/dpaa2/memac_mdio.h @@ -0,0 +1,64 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2021-2022 Bjoern A. Zeeb + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __MEMAC_MDIO_H +#define __MEMAC_MDIO_H + +/* -------------------------------------------------------------------------- */ + +struct memacphy_softc_common { + device_t dev; + device_t dpnidev; + int phy; +}; + +int memacphy_miibus_readreg(device_t, int, int); +int memacphy_miibus_writereg(device_t, int, int, int); +void memacphy_miibus_statchg(struct memacphy_softc_common *); +int memacphy_set_ni_dev(struct memacphy_softc_common *, device_t); +int memacphy_get_phy_loc(struct memacphy_softc_common *, int *); + + +/* -------------------------------------------------------------------------- */ + +struct memac_mdio_softc_common { + device_t dev; + struct resource *mem_res; + bool is_little_endian; +}; + +int memac_miibus_readreg(struct memac_mdio_softc_common *, int, int); +int memac_miibus_writereg(struct memac_mdio_softc_common *, int, int, int); + +ssize_t memac_mdio_get_property(device_t, device_t, const char *, + void *, size_t, device_property_type_t); +int memac_mdio_read_ivar(device_t, device_t, int, uintptr_t *); + +int memac_mdio_generic_attach(struct memac_mdio_softc_common *); +int memac_mdio_generic_detach(struct memac_mdio_softc_common *); + +#endif /* __MEMAC_MDIO_H */ diff --git sys/dev/dpaa2/memac_mdio_acpi.c sys/dev/dpaa2/memac_mdio_acpi.c new file mode 100644 index 000000000000..ed0c2802f60f --- /dev/null +++ sys/dev/dpaa2/memac_mdio_acpi.c @@ -0,0 +1,310 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2021-2022 Bjoern A. Zeeb + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "memac_mdio.h" +#include "memac_mdio_if.h" +#include "acpi_bus_if.h" +#include "miibus_if.h" + +/* -------------------------------------------------------------------------- */ + +struct memacphy_softc_acpi { + struct memacphy_softc_common scc; + int uid; + uint64_t phy_channel; + char compatible[64]; +}; + +static void +memacphy_acpi_miibus_statchg(device_t dev) +{ + struct memacphy_softc_acpi *sc; + + sc = device_get_softc(dev); + memacphy_miibus_statchg(&sc->scc); +} + +static int +memacphy_acpi_set_ni_dev(device_t dev, device_t nidev) +{ + struct memacphy_softc_acpi *sc; + + sc = device_get_softc(dev); + return (memacphy_set_ni_dev(&sc->scc, nidev)); +} + +static int +memacphy_acpi_get_phy_loc(device_t dev, int *phy_loc) +{ + struct memacphy_softc_acpi *sc; + + sc = device_get_softc(dev); + return (memacphy_get_phy_loc(&sc->scc, phy_loc)); +} + +static int +memacphy_acpi_probe(device_t dev) +{ + + device_set_desc(dev, "MEMAC PHY (acpi)"); + return (BUS_PROBE_DEFAULT); +} + +static int +memacphy_acpi_attach(device_t dev) +{ + struct memacphy_softc_acpi *sc; + ACPI_HANDLE h; + ssize_t s; + + sc = device_get_softc(dev); + sc->scc.dev = dev; + h = acpi_get_handle(dev); + + s = acpi_GetInteger(h, "_UID", &sc->uid); + if (ACPI_FAILURE(s)) { + device_printf(dev, "Cannot get '_UID' property: %zd\n", s); + return (ENXIO); + } + + s = device_get_property(dev, "phy-channel", + &sc->phy_channel, sizeof(sc->phy_channel), DEVICE_PROP_UINT64); + if (s != -1) + sc->scc.phy = sc->phy_channel; + else + sc->scc.phy = -1; + s = device_get_property(dev, "compatible", + sc->compatible, sizeof(sc->compatible), DEVICE_PROP_ANY); + + if (bootverbose) + device_printf(dev, "UID %#04x phy-channel %ju compatible '%s' phy %u\n", + sc->uid, sc->phy_channel, + sc->compatible[0] != '\0' ? sc->compatible : "", sc->scc.phy); + + if (sc->scc.phy == -1) + return (ENXIO); + return (0); +} + +static device_method_t memacphy_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, memacphy_acpi_probe), + DEVMETHOD(device_attach, memacphy_acpi_attach), + DEVMETHOD(device_detach, bus_generic_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), + DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), + DEVMETHOD(miibus_statchg, memacphy_acpi_miibus_statchg), + + /* memac */ + DEVMETHOD(memac_mdio_set_ni_dev, memacphy_acpi_set_ni_dev), + DEVMETHOD(memac_mdio_get_phy_loc, memacphy_acpi_get_phy_loc), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(memacphy_acpi, memacphy_acpi_driver, memacphy_acpi_methods, + sizeof(struct memacphy_softc_acpi)); + +EARLY_DRIVER_MODULE(memacphy_acpi, memac_mdio_acpi, memacphy_acpi_driver, 0, 0, + BUS_PASS_SUPPORTDEV); +DRIVER_MODULE(miibus, memacphy_acpi, miibus_driver, 0, 0); +MODULE_DEPEND(memacphy_acpi, miibus, 1, 1, 1); + +/* -------------------------------------------------------------------------- */ + +struct memac_mdio_softc_acpi { + struct memac_mdio_softc_common scc; +}; + +static int +memac_acpi_miibus_readreg(device_t dev, int phy, int reg) +{ + struct memac_mdio_softc_acpi *sc; + + sc = device_get_softc(dev); + return (memac_miibus_readreg(&sc->scc, phy, reg)); +} + +static int +memac_acpi_miibus_writereg(device_t dev, int phy, int reg, int data) +{ + struct memac_mdio_softc_acpi *sc; + + sc = device_get_softc(dev); + return (memac_miibus_writereg(&sc->scc, phy, reg, data)); +} + +/* Context for walking PHY child devices. */ +struct memac_mdio_walk_ctx { + device_t dev; + int count; + int countok; +}; + +static char *memac_mdio_ids[] = { + "NXP0006", + NULL +}; + +static int +memac_mdio_acpi_probe(device_t dev) +{ + int rc; + + if (acpi_disabled("fsl_memac_mdio")) + return (ENXIO); + + rc = ACPI_ID_PROBE(device_get_parent(dev), dev, memac_mdio_ids, NULL); + if (rc <= 0) + device_set_desc(dev, "Freescale XGMAC MDIO Bus"); + + return (rc); +} + +static ACPI_STATUS +memac_mdio_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) +{ + struct memac_mdio_walk_ctx *ctx; + struct acpi_device *ad; + device_t child; + uint32_t adr; + + ctx = (struct memac_mdio_walk_ctx *)arg; + ctx->count++; + + if (ACPI_FAILURE(acpi_GetInteger(h, "_ADR", &adr))) + return (AE_OK); + + /* Technically M_ACPIDEV */ + if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) + return (AE_OK); + + child = device_add_child(ctx->dev, "memacphy_acpi", -1); + if (child == NULL) { + free(ad, M_DEVBUF); + return (AE_OK); + } + ad->ad_handle = h; + ad->ad_cls_class = 0xffffff; + resource_list_init(&ad->ad_rl); + device_set_ivars(child, ad); + *dev = child; + + ctx->countok++; + return (AE_OK); +} + +static int +memac_mdio_acpi_attach(device_t dev) +{ + struct memac_mdio_softc_acpi *sc; + struct memac_mdio_walk_ctx ctx; + int error; + + sc = device_get_softc(dev); + sc->scc.dev = dev; + + error = memac_mdio_generic_attach(&sc->scc); + if (error != 0) + return (error); + + ctx.dev = dev; + ctx.count = 0; + ctx.countok = 0; + ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 1, + memac_mdio_acpi_probe_child, &ctx); + if (ctx.countok > 0) { + bus_generic_probe(dev); + bus_generic_attach(dev); + } + + return (0); +} + +static int +memac_mdio_acpi_detach(device_t dev) +{ + struct memac_mdio_softc_acpi *sc; + + sc = device_get_softc(dev); + return (memac_mdio_generic_detach(&sc->scc)); +} + +static device_method_t memac_mdio_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, memac_mdio_acpi_probe), + DEVMETHOD(device_attach, memac_mdio_acpi_attach), + DEVMETHOD(device_detach, memac_mdio_acpi_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, memac_acpi_miibus_readreg), + DEVMETHOD(miibus_writereg, memac_acpi_miibus_writereg), + + /* .. */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), + DEVMETHOD(bus_get_property, memac_mdio_get_property), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(memac_mdio_acpi, memac_mdio_acpi_driver, memac_mdio_acpi_methods, + sizeof(struct memac_mdio_softc_acpi)); + +EARLY_DRIVER_MODULE(memac_mdio_acpi, acpi, memac_mdio_acpi_driver, 0, 0, + BUS_PASS_SUPPORTDEV); + +DRIVER_MODULE(miibus, memac_mdio_acpi, miibus_driver, 0, 0); +MODULE_DEPEND(memac_mdio_acpi, miibus, 1, 1, 1); +MODULE_VERSION(memac_mdio_acpi, 1); diff --git sys/dev/dpaa2/memac_mdio_common.c sys/dev/dpaa2/memac_mdio_common.c new file mode 100644 index 000000000000..c3fe9f6abc6f --- /dev/null +++ sys/dev/dpaa2/memac_mdio_common.c @@ -0,0 +1,307 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2021-2022 Bjoern A. Zeeb + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "memac_mdio.h" +#include "miibus_if.h" + +/* #define MEMAC_MDIO_DEBUG */ + +/* -------------------------------------------------------------------------- */ + +int +memacphy_miibus_readreg(device_t dev, int phy, int reg) +{ + + return (MIIBUS_READREG(device_get_parent(dev), phy, reg)); +} + +int +memacphy_miibus_writereg(device_t dev, int phy, int reg, int data) +{ + + return (MIIBUS_WRITEREG(device_get_parent(dev), phy, reg, data)); +} + +void +memacphy_miibus_statchg(struct memacphy_softc_common *sc) +{ + + if (sc->dpnidev != NULL) + MIIBUS_STATCHG(sc->dpnidev); +} + +int +memacphy_set_ni_dev(struct memacphy_softc_common *sc, device_t nidev) +{ + + if (nidev == NULL) + return (EINVAL); + +#if defined(MEMAC_MDIO_DEBUG) + if (bootverbose) + device_printf(sc->dev, "setting nidev %p (%s)\n", + nidev, device_get_nameunit(nidev)); +#endif + + if (sc->dpnidev != NULL) + return (EBUSY); + + sc->dpnidev = nidev; + return (0); +} + +int +memacphy_get_phy_loc(struct memacphy_softc_common *sc, int *phy_loc) +{ + int error; + + if (phy_loc == NULL) + return (EINVAL); + + if (sc->phy == -1) { + *phy_loc = MII_PHY_ANY; + error = ENODEV; + } else { + *phy_loc = sc->phy; + error = 0; + } + +#if defined(MEMAC_MDIO_DEBUG) + if (bootverbose) + device_printf(sc->dev, "returning phy_loc %d, error %d\n", + *phy_loc, error); +#endif + + return (error); +} + +/* -------------------------------------------------------------------------- */ + +/* + * MDIO Ethernet Management Interface Registers (internal PCS MDIO PHY) + * 0x0030 MDIO Configuration Register (MDIO_CFG) + * 0x0034 MDIO Control Register (MDIO_CTL) + * 0x0038 MDIO Data Register (MDIO_DATA) + * 0x003c MDIO Register Address Register (MDIO_ADDR) + * + * External MDIO interfaces + * 0x0030 External MDIO Configuration Register (EMDIO_CFG) + * 0x0034 External MDIO Control Register (EMDIO_CTL) + * 0x0038 External MDIO Data Register (EMDIO_DATA) + * 0x003c External MDIO Register Address Register (EMDIO_ADDR) + */ +#define MDIO_CFG 0x00030 +#define MDIO_CFG_MDIO_RD_ER (1 << 1) +#define MDIO_CFG_ENC45 (1 << 6) +#define MDIO_CFG_BUSY (1 << 31) +#define MDIO_CTL 0x00034 +#define MDIO_CTL_READ (1 << 15) +#define MDIO_CTL_PORT_ADDR(_x) (((_x) & 0x1f) << 5) +#define MDIO_CTL_DEV_ADDR(_x) ((_x) & 0x1f) +#define MDIO_DATA 0x00038 +#define MDIO_ADDR 0x0003c + +static uint32_t +memac_read_4(struct memac_mdio_softc_common *sc, uint32_t reg) +{ + uint32_t v, r; + + v = bus_read_4(sc->mem_res, reg); + if (sc->is_little_endian) + r = le32toh(v); + else + r = be32toh(v); + + return (r); +} + +static void +memac_write_4(struct memac_mdio_softc_common *sc, uint32_t reg, uint32_t val) +{ + uint32_t v; + + if (sc->is_little_endian) + v = htole32(val); + else + v = htobe32(val); + bus_write_4(sc->mem_res, reg, v); +} + +static uint32_t +memac_miibus_wait_no_busy(struct memac_mdio_softc_common *sc) +{ + uint32_t count, val; + + for (count = 1000; count > 0; count--) { + val = memac_read_4(sc, MDIO_CFG); + if ((val & MDIO_CFG_BUSY) == 0) + break; + DELAY(1); + } + + if (count == 0) + return (0xffff); + + return (0); +} + +int +memac_miibus_readreg(struct memac_mdio_softc_common *sc, int phy, int reg) +{ + uint32_t cfg, ctl, val; + + /* Set proper Clause 45 mode. */ + cfg = memac_read_4(sc, MDIO_CFG); + /* XXX 45 support? */ + cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */ + memac_write_4(sc, MDIO_CFG, cfg); + + val = memac_miibus_wait_no_busy(sc); + if (val != 0) + return (0xffff); + + /* To whom do we want to talk to.. */ + ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg); + /* XXX do we need two writes for this to work reliably? */ + memac_write_4(sc, MDIO_CTL, ctl | MDIO_CTL_READ); + + val = memac_miibus_wait_no_busy(sc); + if (val != 0) + return (0xffff); + + cfg = memac_read_4(sc, MDIO_CFG); + if (cfg & MDIO_CFG_MDIO_RD_ER) + return (0xffff); + + val = memac_read_4(sc, MDIO_DATA); + val &= 0xffff; + +#if defined(MEMAC_MDIO_DEBUG) + device_printf(sc->dev, "phy read %d:%d = %#06x\n", phy, reg, val); +#endif + + return (val); +} + +int +memac_miibus_writereg(struct memac_mdio_softc_common *sc, int phy, int reg, int data) +{ + uint32_t cfg, ctl, val; + +#if defined(MEMAC_MDIO_DEBUG) + device_printf(sc->dev, "phy write %d:%d\n", phy, reg); +#endif + + /* Set proper Clause 45 mode. */ + cfg = memac_read_4(sc, MDIO_CFG); + /* XXX 45 support? */ + cfg &= ~MDIO_CFG_ENC45; /* Use Clause 22 */ + memac_write_4(sc, MDIO_CFG, cfg); + + val = memac_miibus_wait_no_busy(sc); + if (val != 0) + return (0xffff); + + /* To whom do we want to talk to.. */ + ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(reg); + memac_write_4(sc, MDIO_CTL, ctl); + + memac_write_4(sc, MDIO_DATA, data & 0xffff); + + val = memac_miibus_wait_no_busy(sc); + if (val != 0) + return (0xffff); + + return (0); +} + +ssize_t +memac_mdio_get_property(device_t dev, device_t child, const char *propname, + void *propvalue, size_t size, device_property_type_t type) +{ + + return (bus_generic_get_property(dev, child, propname, propvalue, size, type)); +} + +int +memac_mdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + + return (BUS_READ_IVAR(device_get_parent(dev), dev, index, result)); +} + + +int +memac_mdio_generic_attach(struct memac_mdio_softc_common *sc) +{ + int rid; + + rid = 0; + sc->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE | RF_SHAREABLE); + if (sc->mem_res == NULL) { + device_printf(sc->dev, "%s: cannot allocate mem resource\n", + __func__); + return (ENXIO); + } + + sc->is_little_endian = device_has_property(sc->dev, "little-endian"); + + return (0); +} + +int +memac_mdio_generic_detach(struct memac_mdio_softc_common *sc) +{ + + if (sc->mem_res != NULL) + bus_release_resource(sc->dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem_res), sc->mem_res); + + return (0); +} + diff --git sys/dev/dpaa2/memac_mdio_fdt.c sys/dev/dpaa2/memac_mdio_fdt.c new file mode 100644 index 000000000000..8e349566b9e5 --- /dev/null +++ sys/dev/dpaa2/memac_mdio_fdt.c @@ -0,0 +1,308 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2021-2022 Bjoern A. Zeeb + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "memac_mdio.h" +#include "memac_mdio_if.h" +#include "ofw_bus_if.h" +#include "miibus_if.h" + +/* -------------------------------------------------------------------------- */ + +struct memacphy_softc_fdt { + struct memacphy_softc_common scc; + uint32_t reg; + phandle_t xref; +}; + +static void +memacphy_fdt_miibus_statchg(device_t dev) +{ + struct memacphy_softc_fdt *sc; + + sc = device_get_softc(dev); + memacphy_miibus_statchg(&sc->scc); +} + +static int +memacphy_fdt_set_ni_dev(device_t dev, device_t nidev) +{ + struct memacphy_softc_fdt *sc; + + sc = device_get_softc(dev); + return (memacphy_set_ni_dev(&sc->scc, nidev)); +} + +static int +memacphy_fdt_get_phy_loc(device_t dev, int *phy_loc) +{ + struct memacphy_softc_fdt *sc; + + sc = device_get_softc(dev); + return (memacphy_get_phy_loc(&sc->scc, phy_loc)); +} + +static int +memacphy_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + device_set_desc(dev, "MEMAC PHY (fdt)"); + return (BUS_PROBE_DEFAULT); +} + +static int +memacphy_fdt_attach(device_t dev) +{ + struct memacphy_softc_fdt *sc; + phandle_t node; + ssize_t s; + int error; + + sc = device_get_softc(dev); + sc->scc.dev = dev; + node = ofw_bus_get_node(dev); + + s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg), + DEVICE_PROP_UINT32); + if (s != -1) + sc->scc.phy = sc->reg; + else + sc->scc.phy = -1; + sc->xref = OF_xref_from_node(node); + + error = OF_device_register_xref(sc->xref, dev); + if (error != 0) + device_printf(dev, "Failed to register xref %#x\n", sc->xref); + + if (bootverbose) + device_printf(dev, "node %#x '%s': reg %#x xref %#x phy %u\n", + node, ofw_bus_get_name(dev), sc->reg, sc->xref, sc->scc.phy); + + if (sc->scc.phy == -1) + error = ENXIO; + return (error); +} + +static device_method_t memacphy_fdt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, memacphy_fdt_probe), + DEVMETHOD(device_attach, memacphy_fdt_attach), + DEVMETHOD(device_detach, bus_generic_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), + DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), + DEVMETHOD(miibus_statchg, memacphy_fdt_miibus_statchg), + + /* memac */ + DEVMETHOD(memac_mdio_set_ni_dev, memacphy_fdt_set_ni_dev), + DEVMETHOD(memac_mdio_get_phy_loc, memacphy_fdt_get_phy_loc), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(memacphy_fdt, memacphy_fdt_driver, memacphy_fdt_methods, + sizeof(struct memacphy_softc_fdt)); + +EARLY_DRIVER_MODULE(memacphy_fdt, memac_mdio_fdt, memacphy_fdt_driver, 0, 0, + BUS_PASS_SUPPORTDEV); +DRIVER_MODULE(miibus, memacphy_fdt, miibus_driver, 0, 0); +MODULE_DEPEND(memacphy_fdt, miibus, 1, 1, 1); + +/* -------------------------------------------------------------------------- */ + +/* + * Order in this softc is important; memac_mdio_fdt_attach() calls + * simplebus_init() which expects sb_sc at the beginning. + */ +struct memac_mdio_softc_fdt { + struct simplebus_softc sb_sc; /* Must stay first. */ + struct memac_mdio_softc_common scc; +}; + +static int +memac_fdt_miibus_readreg(device_t dev, int phy, int reg) +{ + struct memac_mdio_softc_fdt *sc; + + sc = device_get_softc(dev); + return (memac_miibus_readreg(&sc->scc, phy, reg)); +} + +static int +memac_fdt_miibus_writereg(device_t dev, int phy, int reg, int data) +{ + struct memac_mdio_softc_fdt *sc; + + sc = device_get_softc(dev); + return (memac_miibus_writereg(&sc->scc, phy, reg, data)); +} + +static struct ofw_compat_data compat_data[] = { + { "fsl,fman-memac-mdio", 1 }, + { NULL, 0 } +}; + +static int +memac_mdio_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Freescale XGMAC MDIO Bus (FDT)"); + return (BUS_PROBE_DEFAULT); +} + +static int +memac_mdio_fdt_probe_child(device_t bus, phandle_t child) +{ + device_t childdev; + + /* Make sure we do not aliready have a device. */ + childdev = ofw_bus_find_child_device_by_phandle(bus, child); + if (childdev != NULL) + return (0); + + childdev = simplebus_add_device(bus, child, 0, NULL, -1, NULL); + if (childdev == NULL) + return (ENXIO); + + return (device_probe_and_attach(childdev)); +} + +static int +memac_mdio_fdt_attach(device_t dev) +{ + struct memac_mdio_softc_fdt *sc; + phandle_t node, child; + int error; + + sc = device_get_softc(dev); + sc->scc.dev = dev; + + error = memac_mdio_generic_attach(&sc->scc); + if (error != 0) + return (error); + + /* Attach the *phy* children represented in the device tree. */ + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + node = ofw_bus_get_node(dev); + simplebus_init(dev, node); + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + if (!OF_hasprop(child, "reg")) + continue; + if (memac_mdio_fdt_probe_child(dev, child) != 0) + continue; + } + + return (0); +} + +static int +memac_mdio_fdt_detach(device_t dev) +{ + struct memac_mdio_softc_fdt *sc; + + sc = device_get_softc(dev); + return (memac_mdio_generic_detach(&sc->scc)); +} + +static const struct ofw_bus_devinfo * +memac_simplebus_get_devinfo(device_t bus, device_t child) +{ + + return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child)); +} + +static device_method_t memac_mdio_fdt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, memac_mdio_fdt_probe), + DEVMETHOD(device_attach, memac_mdio_fdt_attach), + DEVMETHOD(device_detach, memac_mdio_fdt_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, memac_fdt_miibus_readreg), + DEVMETHOD(miibus_writereg, memac_fdt_miibus_writereg), + + /* OFW/simplebus */ + DEVMETHOD(ofw_bus_get_devinfo, memac_simplebus_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), + DEVMETHOD(bus_get_property, memac_mdio_get_property), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(memac_mdio_fdt, memac_mdio_fdt_driver, memac_mdio_fdt_methods, + sizeof(struct memac_mdio_softc_fdt)); + +EARLY_DRIVER_MODULE(memac_mdio_fdt, simplebus, memac_mdio_fdt_driver, 0, 0, + BUS_PASS_SUPPORTDEV); + +DRIVER_MODULE(miibus, memac_mdio_fdt, miibus_driver, 0, 0); +MODULE_DEPEND(memac_mdio_fdt, miibus, 1, 1, 1); +MODULE_VERSION(memac_mdio_fdt, 1); diff --git sys/modules/dpaa2/Makefile sys/modules/dpaa2/Makefile index 7cc4592022fd..556a1c531669 100644 --- sys/modules/dpaa2/Makefile +++ sys/modules/dpaa2/Makefile @@ -15,15 +15,14 @@ SRCS+= dpaa2_con.c SRCS+= dpaa2_cmd_if.c dpaa2_cmd_if.h SRCS+= dpaa2_swp_if.c dpaa2_swp_if.h SRCS+= dpaa2_mc_if.c dpaa2_mc_if.h -SRCS+= memac_mdio.c memac_mdio_if.c memac_mdio_if.h +SRCS+= memac_mdio_common.c memac_mdio_if.c memac_mdio_if.h -SRCS+= bus_if.h device_if.h miibus_if.h opt_platform.h +SRCS+= bus_if.h device_if.h miibus_if.h SRCS+= pcib_if.h pci_if.h -.if ${MACHINE_CPUARCH} == "aarch64" || \ - ${MACHINE_CPUARCH} == "amd64" || \ - ${MACHINE_CPUARCH} == "i386" +.if !empty(OPT_ACPI) SRCS+= dpaa2_mc_acpi.c \ + memac_mdio_acpi.c \ opt_acpi.h \ acpi_if.h \ acpi_bus_if.h @@ -31,6 +30,8 @@ SRCS+= dpaa2_mc_acpi.c \ .if !empty(OPT_FDT) SRCS+= dpaa2_mc_fdt.c \ + memac_mdio_fdt.c \ + opt_platform.h \ ofw_bus_if.h .endif