xref: /freebsd/sys/dev/dpaa/if_memac_fdt.c (revision 7a40b8a89e7da2a7e8d8e132bc37885b22e9bfb1)
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