1*7a40b8a8SJustin Hibbits /*
2*7a40b8a8SJustin Hibbits * Copyright (c) 2026 Justin Hibbits
3fd8d34ceSJustin Hibbits * Copyright (c) 2012 Semihalf.
4fd8d34ceSJustin Hibbits *
5*7a40b8a8SJustin Hibbits * SPDX-License-Identifier: BSD-2-Clause
6fd8d34ceSJustin Hibbits */
7fd8d34ceSJustin Hibbits
8fd8d34ceSJustin Hibbits #include <sys/param.h>
9fd8d34ceSJustin Hibbits #include <sys/systm.h>
10fd8d34ceSJustin Hibbits #include <sys/bus.h>
11fd8d34ceSJustin Hibbits #include <sys/kernel.h>
12fd8d34ceSJustin Hibbits #include <sys/module.h>
13fd8d34ceSJustin Hibbits #include <sys/rman.h>
14fd8d34ceSJustin Hibbits #include <sys/socket.h>
15fd8d34ceSJustin Hibbits
16fd8d34ceSJustin Hibbits #include <machine/bus.h>
17fd8d34ceSJustin Hibbits
18fd8d34ceSJustin Hibbits #include <powerpc/mpc85xx/mpc85xx.h>
19fd8d34ceSJustin Hibbits
20fd8d34ceSJustin Hibbits #include <net/if.h>
21fd8d34ceSJustin Hibbits #include <net/if_media.h>
22fd8d34ceSJustin Hibbits
23fd8d34ceSJustin Hibbits #include <dev/mii/mii.h>
24fd8d34ceSJustin Hibbits #include <dev/mii/miivar.h>
25fd8d34ceSJustin Hibbits #include <dev/mii/mii_fdt.h>
26fd8d34ceSJustin Hibbits
27fd8d34ceSJustin Hibbits #include <dev/ofw/ofw_bus.h>
28fd8d34ceSJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
29fd8d34ceSJustin Hibbits #include <dev/ofw/openfirm.h>
30fd8d34ceSJustin Hibbits
31fd8d34ceSJustin Hibbits #include "miibus_if.h"
32fd8d34ceSJustin Hibbits
33fd8d34ceSJustin Hibbits #include "dpaa_eth.h"
34fd8d34ceSJustin Hibbits #include "if_memac.h"
35fd8d34ceSJustin Hibbits #include "fman.h"
36fd8d34ceSJustin Hibbits
37fd8d34ceSJustin Hibbits
38fd8d34ceSJustin Hibbits static int memac_fdt_probe(device_t dev);
39fd8d34ceSJustin Hibbits static int memac_fdt_attach(device_t dev);
40fd8d34ceSJustin Hibbits
41fd8d34ceSJustin Hibbits static device_method_t memac_methods[] = {
42fd8d34ceSJustin Hibbits /* Device interface */
43fd8d34ceSJustin Hibbits DEVMETHOD(device_probe, memac_fdt_probe),
44fd8d34ceSJustin Hibbits DEVMETHOD(device_attach, memac_fdt_attach),
45fd8d34ceSJustin Hibbits DEVMETHOD(device_detach, memac_detach),
46fd8d34ceSJustin Hibbits
47fd8d34ceSJustin Hibbits DEVMETHOD(device_shutdown, memac_shutdown),
48fd8d34ceSJustin Hibbits DEVMETHOD(device_suspend, memac_suspend),
49fd8d34ceSJustin Hibbits DEVMETHOD(device_resume, memac_resume),
50fd8d34ceSJustin Hibbits
51fd8d34ceSJustin Hibbits /* Bus interface */
52fd8d34ceSJustin Hibbits DEVMETHOD(bus_print_child, bus_generic_print_child),
53fd8d34ceSJustin Hibbits DEVMETHOD(bus_driver_added, bus_generic_driver_added),
54fd8d34ceSJustin Hibbits
55fd8d34ceSJustin Hibbits /* MII interface */
56fd8d34ceSJustin Hibbits DEVMETHOD(miibus_readreg, memac_miibus_readreg),
57fd8d34ceSJustin Hibbits DEVMETHOD(miibus_writereg, memac_miibus_writereg),
58fd8d34ceSJustin Hibbits DEVMETHOD(miibus_statchg, memac_miibus_statchg),
59fd8d34ceSJustin Hibbits
60fd8d34ceSJustin Hibbits DEVMETHOD_END
61fd8d34ceSJustin Hibbits };
62fd8d34ceSJustin Hibbits
63fd8d34ceSJustin Hibbits DEFINE_CLASS_0(memac, memac_driver, memac_methods, sizeof(struct memac_softc));
64fd8d34ceSJustin Hibbits
65fd8d34ceSJustin Hibbits DRIVER_MODULE(memac, fman, memac_driver, 0, 0);
66fd8d34ceSJustin Hibbits DRIVER_MODULE(miibus, memac, miibus_driver, 0, 0);
67fd8d34ceSJustin Hibbits MODULE_DEPEND(memac, ether, 1, 1, 1);
68fd8d34ceSJustin Hibbits MODULE_DEPEND(memac, miibus, 1, 1, 1);
69fd8d34ceSJustin Hibbits
70fd8d34ceSJustin Hibbits static int
memac_fdt_probe(device_t dev)71fd8d34ceSJustin Hibbits memac_fdt_probe(device_t dev)
72fd8d34ceSJustin Hibbits {
73fd8d34ceSJustin Hibbits
74fd8d34ceSJustin Hibbits if (!ofw_bus_status_okay(dev))
75fd8d34ceSJustin Hibbits return (ENXIO);
76fd8d34ceSJustin Hibbits
77fd8d34ceSJustin Hibbits if (!ofw_bus_is_compatible(dev, "fsl,fman-memac"))
78fd8d34ceSJustin Hibbits return (ENXIO);
79fd8d34ceSJustin Hibbits
80fd8d34ceSJustin Hibbits device_set_desc(dev,
81fd8d34ceSJustin Hibbits "Freescale Multirate Ethernet Media Access Controller");
82fd8d34ceSJustin Hibbits
83fd8d34ceSJustin Hibbits return (BUS_PROBE_DEFAULT);
84fd8d34ceSJustin Hibbits }
85fd8d34ceSJustin Hibbits
86fd8d34ceSJustin Hibbits static int
memac_fdt_attach(device_t dev)87fd8d34ceSJustin Hibbits memac_fdt_attach(device_t dev)
88fd8d34ceSJustin Hibbits {
89fd8d34ceSJustin Hibbits struct memac_softc *sc;
90fd8d34ceSJustin Hibbits device_t phy_dev;
91fd8d34ceSJustin Hibbits phandle_t enet_node, phy_node;
92fd8d34ceSJustin Hibbits phandle_t fman_rxtx_node[2];
93fd8d34ceSJustin Hibbits pcell_t fman_tx_cell, mac_id;
94fd8d34ceSJustin Hibbits
95fd8d34ceSJustin Hibbits sc = device_get_softc(dev);
96fd8d34ceSJustin Hibbits enet_node = ofw_bus_get_node(dev);
97fd8d34ceSJustin Hibbits
98fd8d34ceSJustin Hibbits if (OF_getprop(enet_node, "local-mac-address",
99fd8d34ceSJustin Hibbits (void *)sc->sc_base.sc_mac_addr, 6) == -1) {
100fd8d34ceSJustin Hibbits device_printf(dev,
101fd8d34ceSJustin Hibbits "Could not load local-mac-addr property from DTS\n");
102fd8d34ceSJustin Hibbits return (ENXIO);
103fd8d34ceSJustin Hibbits }
104fd8d34ceSJustin Hibbits
105fd8d34ceSJustin Hibbits /* Get PHY connection type */
106fd8d34ceSJustin Hibbits sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node);
107fd8d34ceSJustin Hibbits
108fd8d34ceSJustin Hibbits sc->sc_fixed_link = OF_hasprop(enet_node, "fixed-link") ||
109fd8d34ceSJustin Hibbits (ofw_bus_find_child(enet_node, "fixed-link") != 0);
110fd8d34ceSJustin Hibbits if (!sc->sc_fixed_link) {
111fd8d34ceSJustin Hibbits OF_getprop(enet_node, "phy-handle", &phy_node, sizeof(phy_node));
112fd8d34ceSJustin Hibbits phy_node = OF_node_from_xref(phy_node);
113fd8d34ceSJustin Hibbits
114fd8d34ceSJustin Hibbits if (OF_getencprop(phy_node, "reg", (void *)&sc->sc_base.sc_phy_addr,
115fd8d34ceSJustin Hibbits sizeof(sc->sc_base.sc_phy_addr)) <= 0)
116fd8d34ceSJustin Hibbits return (ENXIO);
117fd8d34ceSJustin Hibbits
118fd8d34ceSJustin Hibbits phy_dev = OF_device_from_xref(OF_xref_from_node(OF_parent(phy_node)));
119fd8d34ceSJustin Hibbits
120fd8d34ceSJustin Hibbits if (phy_dev == NULL) {
121fd8d34ceSJustin Hibbits device_printf(dev, "No PHY found.\n");
122fd8d34ceSJustin Hibbits return (ENXIO);
123fd8d34ceSJustin Hibbits }
124fd8d34ceSJustin Hibbits
125fd8d34ceSJustin Hibbits sc->sc_base.sc_mdio = phy_dev;
126fd8d34ceSJustin Hibbits }
127fd8d34ceSJustin Hibbits
128fd8d34ceSJustin Hibbits /* Get MAC memory offset in SoC */
129fd8d34ceSJustin Hibbits sc->sc_base.sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
130fd8d34ceSJustin Hibbits if (sc->sc_base.sc_mem == NULL)
131fd8d34ceSJustin Hibbits return (ENXIO);
132fd8d34ceSJustin Hibbits
133fd8d34ceSJustin Hibbits sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node);
134fd8d34ceSJustin Hibbits
135fd8d34ceSJustin Hibbits if (sc->sc_base.sc_mac_enet_mode == MII_CONTYPE_UNKNOWN) {
136fd8d34ceSJustin Hibbits device_printf(dev, "unknown MII type, defaulting to SGMII\n");
137fd8d34ceSJustin Hibbits sc->sc_base.sc_mac_enet_mode = MII_CONTYPE_SGMII;
138fd8d34ceSJustin Hibbits }
139fd8d34ceSJustin Hibbits
140fd8d34ceSJustin Hibbits if (OF_getencprop(enet_node, "cell-index",
141fd8d34ceSJustin Hibbits (void *)&mac_id, sizeof(mac_id)) <= 0)
142fd8d34ceSJustin Hibbits return (ENXIO);
143fd8d34ceSJustin Hibbits sc->sc_base.sc_eth_id = mac_id;
144fd8d34ceSJustin Hibbits
145fd8d34ceSJustin Hibbits /* Get RX/TX port handles */
146fd8d34ceSJustin Hibbits if (OF_getencprop(enet_node, "fsl,fman-ports", (void *)fman_rxtx_node,
147fd8d34ceSJustin Hibbits sizeof(fman_rxtx_node)) <= 0)
148fd8d34ceSJustin Hibbits return (ENXIO);
149fd8d34ceSJustin Hibbits
150fd8d34ceSJustin Hibbits if (fman_rxtx_node[0] == 0)
151fd8d34ceSJustin Hibbits return (ENXIO);
152fd8d34ceSJustin Hibbits
153fd8d34ceSJustin Hibbits if (fman_rxtx_node[1] == 0)
154fd8d34ceSJustin Hibbits return (ENXIO);
155fd8d34ceSJustin Hibbits
156fd8d34ceSJustin Hibbits sc->sc_base.sc_rx_port = OF_device_from_xref(fman_rxtx_node[0]);
157fd8d34ceSJustin Hibbits sc->sc_base.sc_tx_port = OF_device_from_xref(fman_rxtx_node[1]);
158fd8d34ceSJustin Hibbits
159fd8d34ceSJustin Hibbits if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL)
160fd8d34ceSJustin Hibbits return (ENXIO);
161fd8d34ceSJustin Hibbits
162fd8d34ceSJustin Hibbits fman_rxtx_node[1] = OF_node_from_xref(fman_rxtx_node[1]);
163fd8d34ceSJustin Hibbits if (OF_getencprop(fman_rxtx_node[1], "cell-index", &fman_tx_cell,
164fd8d34ceSJustin Hibbits sizeof(fman_tx_cell)) <= 0)
165fd8d34ceSJustin Hibbits return (ENXIO);
166fd8d34ceSJustin Hibbits /* Get QMan channel */
167fd8d34ceSJustin Hibbits sc->sc_base.sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev),
168fd8d34ceSJustin Hibbits fman_tx_cell);
169fd8d34ceSJustin Hibbits
170fd8d34ceSJustin Hibbits return (memac_attach(dev));
171fd8d34ceSJustin Hibbits }
172