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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/rman.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/endian.h>
38 #include <sys/socket.h>
39
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42
43 #include <dev/ofw/ofw_bus.h>
44 #include <dev/ofw/ofw_bus_subr.h>
45 #include <dev/fdt/simplebus.h>
46
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/if_media.h>
50
51 #include <dev/mii/mii.h>
52 #include <dev/mii/miivar.h>
53
54 #include "memac_mdio.h"
55 #include "memac_mdio_if.h"
56 #include "ofw_bus_if.h"
57 #include "miibus_if.h"
58
59 /* -------------------------------------------------------------------------- */
60
61 struct memacphy_softc_fdt {
62 struct memacphy_softc_common scc;
63 uint32_t reg;
64 phandle_t xref;
65 };
66
67 static void
68 memacphy_fdt_miibus_statchg(device_t dev)
69 {
70 struct memacphy_softc_fdt *sc;
71
72 sc = device_get_softc(dev);
73 memacphy_miibus_statchg(&sc->scc);
74 }
75
76 static int
77 memacphy_fdt_set_ni_dev(device_t dev, device_t nidev)
78 {
79 struct memacphy_softc_fdt *sc;
80
81 sc = device_get_softc(dev);
82 return (memacphy_set_ni_dev(&sc->scc, nidev));
83 }
84
85 static int
86 memacphy_fdt_get_phy_loc(device_t dev, int *phy_loc)
87 {
88 struct memacphy_softc_fdt *sc;
89
90 sc = device_get_softc(dev);
91 return (memacphy_get_phy_loc(&sc->scc, phy_loc));
92 }
93
94 static int
95 memacphy_fdt_probe(device_t dev)
96 {
97
98 if (!ofw_bus_status_okay(dev))
99 return (ENXIO);
100
101 device_set_desc(dev, "MEMAC PHY (fdt)");
102 return (BUS_PROBE_DEFAULT);
103 }
104
105 static int
106 memacphy_fdt_attach(device_t dev)
107 {
108 struct memacphy_softc_fdt *sc;
109 phandle_t node;
110 ssize_t s;
111 int error;
112
113 sc = device_get_softc(dev);
114 sc->scc.dev = dev;
115 node = ofw_bus_get_node(dev);
116
117 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg),
118 DEVICE_PROP_UINT32);
119 if (s != -1)
120 sc->scc.phy = sc->reg;
121 else
122 sc->scc.phy = -1;
123 sc->xref = OF_xref_from_node(node);
124
125 error = OF_device_register_xref(sc->xref, dev);
126 if (error != 0)
127 device_printf(dev, "Failed to register xref %#x\n", sc->xref);
128
129 if (bootverbose)
130 device_printf(dev, "node %#x '%s': reg %#x xref %#x phy %u\n",
131 node, ofw_bus_get_name(dev), sc->reg, sc->xref, sc->scc.phy);
132
133 if (sc->scc.phy == -1)
134 error = ENXIO;
135 return (error);
136 }
137
138 static device_method_t memacphy_fdt_methods[] = {
139 /* Device interface */
140 DEVMETHOD(device_probe, memacphy_fdt_probe),
141 DEVMETHOD(device_attach, memacphy_fdt_attach),
142 DEVMETHOD(device_detach, bus_generic_detach),
143
144 /* MII interface */
145 DEVMETHOD(miibus_readreg, memacphy_miibus_readreg),
146 DEVMETHOD(miibus_writereg, memacphy_miibus_writereg),
147 DEVMETHOD(miibus_statchg, memacphy_fdt_miibus_statchg),
148
149 /* memac */
150 DEVMETHOD(memac_mdio_set_ni_dev, memacphy_fdt_set_ni_dev),
151 DEVMETHOD(memac_mdio_get_phy_loc, memacphy_fdt_get_phy_loc),
152
153 DEVMETHOD_END
154 };
155
156 DEFINE_CLASS_0(memacphy_fdt, memacphy_fdt_driver, memacphy_fdt_methods,
157 sizeof(struct memacphy_softc_fdt));
158
159 EARLY_DRIVER_MODULE(memacphy_fdt, memac_mdio_fdt, memacphy_fdt_driver, 0, 0,
160 BUS_PASS_SUPPORTDEV);
161 DRIVER_MODULE(miibus, memacphy_fdt, miibus_driver, 0, 0);
162 MODULE_DEPEND(memacphy_fdt, miibus, 1, 1, 1);
163
164 /* -------------------------------------------------------------------------- */
165
166 /*
167 * Order in this softc is important; memac_mdio_fdt_attach() calls
168 * simplebus_init() which expects sb_sc at the beginning.
169 */
170 struct memac_mdio_softc_fdt {
171 struct simplebus_softc sb_sc; /* Must stay first. */
172 struct memac_mdio_softc_common scc;
173 };
174
175 static int
176 memac_fdt_miibus_readreg(device_t dev, int phy, int reg)
177 {
178 struct memac_mdio_softc_fdt *sc;
179
180 sc = device_get_softc(dev);
181 return (memac_miibus_readreg(&sc->scc, phy, reg));
182 }
183
184 static int
185 memac_fdt_miibus_writereg(device_t dev, int phy, int reg, int data)
186 {
187 struct memac_mdio_softc_fdt *sc;
188
189 sc = device_get_softc(dev);
190 return (memac_miibus_writereg(&sc->scc, phy, reg, data));
191 }
192
193 static struct ofw_compat_data compat_data[] = {
194 { "fsl,fman-memac-mdio", 1 },
195 { NULL, 0 }
196 };
197
198 static int
199 memac_mdio_fdt_probe(device_t dev)
200 {
201
202 if (!ofw_bus_status_okay(dev))
203 return (ENXIO);
204
205 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
206 return (ENXIO);
207
208 device_set_desc(dev, "Freescale XGMAC MDIO Bus (FDT)");
209 return (BUS_PROBE_DEFAULT);
210 }
211
212 static int
213 memac_mdio_fdt_probe_child(device_t bus, phandle_t child)
214 {
215 device_t childdev;
216
217 /* Make sure we do not aliready have a device. */
218 childdev = ofw_bus_find_child_device_by_phandle(bus, child);
219 if (childdev != NULL)
220 return (0);
221
222 childdev = simplebus_add_device(bus, child, 0, NULL, -1, NULL);
223 if (childdev == NULL)
224 return (ENXIO);
225
226 return (device_probe_and_attach(childdev));
227 }
228
229 static int
230 memac_mdio_fdt_attach(device_t dev)
231 {
232 struct memac_mdio_softc_fdt *sc;
233 phandle_t node, child;
234 int error;
235
236 sc = device_get_softc(dev);
237 sc->scc.dev = dev;
238
239 error = memac_mdio_generic_attach(&sc->scc);
240 if (error != 0)
241 return (error);
242
243 /* Attach the *phy* children represented in the device tree. */
244 bus_generic_probe(dev);
245 bus_enumerate_hinted_children(dev);
246 node = ofw_bus_get_node(dev);
247 simplebus_init(dev, node);
248 for (child = OF_child(node); child > 0; child = OF_peer(child)) {
249 if (!OF_hasprop(child, "reg"))
250 continue;
251 if (memac_mdio_fdt_probe_child(dev, child) != 0)
252 continue;
253 }
254
255 return (0);
256 }
257
258 static int
259 memac_mdio_fdt_detach(device_t dev)
260 {
261 struct memac_mdio_softc_fdt *sc;
262
263 sc = device_get_softc(dev);
264 return (memac_mdio_generic_detach(&sc->scc));
265 }
266
267 static const struct ofw_bus_devinfo *
268 memac_simplebus_get_devinfo(device_t bus, device_t child)
269 {
270
271 return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child));
272 }
273
274 static device_method_t memac_mdio_fdt_methods[] = {
275 /* Device interface */
276 DEVMETHOD(device_probe, memac_mdio_fdt_probe),
277 DEVMETHOD(device_attach, memac_mdio_fdt_attach),
278 DEVMETHOD(device_detach, memac_mdio_fdt_detach),
279
280 /* MII interface */
281 DEVMETHOD(miibus_readreg, memac_fdt_miibus_readreg),
282 DEVMETHOD(miibus_writereg, memac_fdt_miibus_writereg),
283
284 /* OFW/simplebus */
285 DEVMETHOD(ofw_bus_get_devinfo, memac_simplebus_get_devinfo),
286 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
287 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
288 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
289 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
290 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
291
292 /* Bus interface */
293 DEVMETHOD(bus_add_child, bus_generic_add_child),
294 DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar),
295 DEVMETHOD(bus_get_property, memac_mdio_get_property),
296
297 DEVMETHOD_END
298 };
299
300 DEFINE_CLASS_0(memac_mdio_fdt, memac_mdio_fdt_driver, memac_mdio_fdt_methods,
301 sizeof(struct memac_mdio_softc_fdt));
302
303 EARLY_DRIVER_MODULE(memac_mdio_fdt, simplebus, memac_mdio_fdt_driver, 0, 0,
304 BUS_PASS_SUPPORTDEV);
305
306 DRIVER_MODULE(miibus, memac_mdio_fdt, miibus_driver, 0, 0);
307 MODULE_DEPEND(memac_mdio_fdt, miibus, 1, 1, 1);
308 MODULE_VERSION(memac_mdio_fdt, 1);
Cache object: b869ecf1d77dff4f14b67b77e6066cd2
|