]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/tsec/if_tsec_fdt.c
Upgrade Unbound to 1.6.1. More to follow.
[FreeBSD/FreeBSD.git] / sys / dev / tsec / if_tsec_fdt.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski
5  * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
20  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * From: FreeBSD: head/sys/dev/tsec/if_tsec_ocp.c 188712 2009-02-17 14:59:47Z raj
29  */
30
31 /*
32  * FDT 'simple-bus' attachment for Freescale TSEC controller.
33  */
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/endian.h>
40 #include <sys/lock.h>
41 #include <sys/mbuf.h>
42 #include <sys/mutex.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47
48 #include <sys/bus.h>
49 #include <machine/bus.h>
50 #include <sys/rman.h>
51 #include <machine/resource.h>
52
53 #include <net/ethernet.h>
54 #include <net/if.h>
55 #include <net/if_media.h>
56
57 #include <dev/fdt/fdt_common.h>
58 #include <dev/mii/mii.h>
59 #include <dev/mii/miivar.h>
60 #include <dev/ofw/ofw_bus.h>
61 #include <dev/ofw/ofw_bus_subr.h>
62 #include <dev/ofw/openfirm.h>
63
64 #include <dev/tsec/if_tsec.h>
65 #include <dev/tsec/if_tsecreg.h>
66
67 #include "miibus_if.h"
68
69 #define TSEC_RID_TXIRQ  0
70 #define TSEC_RID_RXIRQ  1
71 #define TSEC_RID_ERRIRQ 2
72
73 static int tsec_fdt_probe(device_t dev);
74 static int tsec_fdt_attach(device_t dev);
75 static int tsec_fdt_detach(device_t dev);
76 static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires,
77     void **ihand, int *irid, driver_intr_t handler, const char *iname);
78 static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires,
79     void *ihand, int irid, const char *iname);
80
81 static device_method_t tsec_methods[] = {
82         /* Device interface */
83         DEVMETHOD(device_probe,         tsec_fdt_probe),
84         DEVMETHOD(device_attach,        tsec_fdt_attach),
85         DEVMETHOD(device_detach,        tsec_fdt_detach),
86
87         DEVMETHOD(device_shutdown,      tsec_shutdown),
88         DEVMETHOD(device_suspend,       tsec_suspend),
89         DEVMETHOD(device_resume,        tsec_resume),
90
91         /* MII interface */
92         DEVMETHOD(miibus_readreg,       tsec_miibus_readreg),
93         DEVMETHOD(miibus_writereg,      tsec_miibus_writereg),
94         DEVMETHOD(miibus_statchg,       tsec_miibus_statchg),
95
96         DEVMETHOD_END
97 };
98
99 static driver_t tsec_fdt_driver = {
100         "tsec",
101         tsec_methods,
102         sizeof(struct tsec_softc),
103 };
104
105 DRIVER_MODULE(tsec, simplebus, tsec_fdt_driver, tsec_devclass, 0, 0);
106
107 static int
108 tsec_fdt_probe(device_t dev)
109 {
110         struct tsec_softc *sc;
111         uint32_t id;
112
113         if (!ofw_bus_status_okay(dev))
114                 return (ENXIO);
115
116         if (ofw_bus_get_type(dev) == NULL ||
117             strcmp(ofw_bus_get_type(dev), "network") != 0)
118                 return (ENXIO);
119
120         if (!ofw_bus_is_compatible(dev, "gianfar") &&
121             !ofw_bus_is_compatible(dev, "fsl,etsec2"))
122                 return (ENXIO);
123
124         sc = device_get_softc(dev);
125
126         /*
127          * Device trees with "fsl,etsec2" compatible nodes don't have a reg
128          * property, as it's been relegated to the queue-group children.
129          */
130         if (ofw_bus_is_compatible(dev, "fsl,etsec2"))
131                 sc->is_etsec = 1;
132         else {
133                 sc->sc_rrid = 0;
134                 sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
135                     RF_ACTIVE);
136                 if (sc->sc_rres == NULL)
137                         return (ENXIO);
138
139                 sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
140                 sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
141
142                 /* Check if we are eTSEC (enhanced TSEC) */
143                 id = TSEC_READ(sc, TSEC_REG_ID);
144                 sc->is_etsec = ((id >> 16) == TSEC_ETSEC_ID) ? 1 : 0;
145                 id |= TSEC_READ(sc, TSEC_REG_ID2);
146
147                 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
148
149                 if (id == 0) {
150                         device_printf(dev, "could not identify TSEC type\n");
151                         return (ENXIO);
152                 }
153         }
154
155         if (sc->is_etsec)
156                 device_set_desc(dev, "Enhanced Three-Speed Ethernet Controller");
157         else
158                 device_set_desc(dev, "Three-Speed Ethernet Controller");
159
160         return (BUS_PROBE_DEFAULT);
161 }
162
163 static int
164 tsec_fdt_attach(device_t dev)
165 {
166         struct tsec_softc *sc;
167         struct resource_list *rl;
168         phandle_t child, mdio, phy;
169         int acells, scells;
170         int error = 0;
171
172         sc = device_get_softc(dev);
173         sc->dev = dev;
174         sc->node = ofw_bus_get_node(dev);
175
176         if (fdt_addrsize_cells(sc->node, &acells, &scells) != 0) {
177                 acells = 1;
178                 scells = 1;
179         }
180         if (ofw_bus_is_compatible(dev, "fsl,etsec2")) {
181                 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
182
183                 /*
184                  * TODO: Add all children resources to the list.  Will be
185                  * required to support multigroup mode.
186                  */
187                 child = OF_child(sc->node);
188                 ofw_bus_reg_to_rl(dev, child, acells, scells, rl);
189                 ofw_bus_intr_to_rl(dev, child, rl, NULL);
190         }
191
192         /* Get phy address from fdt */
193         if (OF_getencprop(sc->node, "phy-handle", &phy, sizeof(phy)) <= 0) {
194                 device_printf(dev, "PHY not found in device tree");
195                 return (ENXIO);
196         }
197
198         phy = OF_node_from_xref(phy);
199         mdio = OF_parent(phy);
200         OF_decode_addr(mdio, 0, &sc->phy_bst, &sc->phy_bsh, NULL);
201         OF_getencprop(phy, "reg", &sc->phyaddr, sizeof(sc->phyaddr));
202
203         /*
204          * etsec2 MDIO nodes are given the MDIO module base address, so we need
205          * to add the MII offset to get the PHY registers.
206          */
207         if (ofw_bus_node_is_compatible(mdio, "fsl,etsec2-mdio"))
208                 sc->phy_regoff = TSEC_REG_MIIBASE;
209
210         /* Init timer */
211         callout_init(&sc->tsec_callout, 1);
212
213         /* Init locks */
214         mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock",
215             MTX_DEF);
216         mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock",
217             MTX_DEF);
218         mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock",
219             MTX_DEF);
220
221         /* Allocate IO memory for TSEC registers */
222         sc->sc_rrid = 0;
223         sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
224             RF_ACTIVE);
225         if (sc->sc_rres == NULL) {
226                 device_printf(dev, "could not allocate IO memory range!\n");
227                 goto fail1;
228         }
229         sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
230         sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
231
232         /* TSEC attach */
233         if (tsec_attach(sc) != 0) {
234                 device_printf(dev, "could not be configured\n");
235                 goto fail2;
236         }
237
238         /* Set up interrupts (TX/RX/ERR) */
239         sc->sc_transmit_irid = TSEC_RID_TXIRQ;
240         error = tsec_setup_intr(sc, &sc->sc_transmit_ires,
241             &sc->sc_transmit_ihand, &sc->sc_transmit_irid,
242             tsec_transmit_intr, "TX");
243         if (error)
244                 goto fail2;
245
246         sc->sc_receive_irid = TSEC_RID_RXIRQ;
247         error = tsec_setup_intr(sc, &sc->sc_receive_ires,
248             &sc->sc_receive_ihand, &sc->sc_receive_irid,
249             tsec_receive_intr, "RX");
250         if (error)
251                 goto fail3;
252
253         sc->sc_error_irid = TSEC_RID_ERRIRQ;
254         error = tsec_setup_intr(sc, &sc->sc_error_ires,
255             &sc->sc_error_ihand, &sc->sc_error_irid,
256             tsec_error_intr, "ERR");
257         if (error)
258                 goto fail4;
259
260         return (0);
261
262 fail4:
263         tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
264             sc->sc_receive_irid, "RX");
265 fail3:
266         tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
267             sc->sc_transmit_irid, "TX");
268 fail2:
269         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
270 fail1:
271         mtx_destroy(&sc->receive_lock);
272         mtx_destroy(&sc->transmit_lock);
273         return (ENXIO);
274 }
275
276 static int
277 tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand,
278     int *irid, driver_intr_t handler, const char *iname)
279 {
280         int error;
281
282         *ires = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE);
283         if (*ires == NULL) {
284                 device_printf(sc->dev, "could not allocate %s IRQ\n", iname);
285                 return (ENXIO);
286         }
287         error = bus_setup_intr(sc->dev, *ires, INTR_TYPE_NET | INTR_MPSAFE,
288             NULL, handler, sc, ihand);
289         if (error) {
290                 device_printf(sc->dev, "failed to set up %s IRQ\n", iname);
291                 if (bus_release_resource(sc->dev, SYS_RES_IRQ, *irid, *ires))
292                         device_printf(sc->dev, "could not release %s IRQ\n", iname);
293                 *ires = NULL;
294                 return (error);
295         }
296         return (0);
297 }
298
299 static void
300 tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand,
301     int irid, const char *iname)
302 {
303         int error;
304
305         if (ires == NULL)
306                 return;
307
308         error = bus_teardown_intr(sc->dev, ires, ihand);
309         if (error)
310                 device_printf(sc->dev, "bus_teardown_intr() failed for %s intr"
311                     ", error %d\n", iname, error);
312
313         error = bus_release_resource(sc->dev, SYS_RES_IRQ, irid, ires);
314         if (error)
315                 device_printf(sc->dev, "bus_release_resource() failed for %s "
316                     "intr, error %d\n", iname, error);
317 }
318
319 static int
320 tsec_fdt_detach(device_t dev)
321 {
322         struct tsec_softc *sc;
323         int error;
324
325         sc = device_get_softc(dev);
326
327         /* Wait for stopping watchdog */
328         callout_drain(&sc->tsec_callout);
329
330         /* Stop and release all interrupts */
331         tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
332             sc->sc_transmit_irid, "TX");
333         tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
334             sc->sc_receive_irid, "RX");
335         tsec_release_intr(sc, sc->sc_error_ires, sc->sc_error_ihand,
336             sc->sc_error_irid, "ERR");
337
338         /* TSEC detach */
339         tsec_detach(sc);
340
341         /* Free IO memory handler */
342         if (sc->sc_rres) {
343                 error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid,
344                     sc->sc_rres);
345                 if (error)
346                         device_printf(dev, "bus_release_resource() failed for"
347                             " IO memory, error %d\n", error);
348         }
349
350         /* Destroy locks */
351         mtx_destroy(&sc->receive_lock);
352         mtx_destroy(&sc->transmit_lock);
353         mtx_destroy(&sc->ic_lock);
354         return (0);
355 }
356
357 void
358 tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr)
359 {
360         union {
361                 uint32_t reg[2];
362                 uint8_t addr[6];
363         } hw;
364         int i;
365
366         hw.reg[0] = hw.reg[1] = 0;
367
368         /* Retrieve the hardware address from the device tree. */
369         i = OF_getprop(sc->node, "local-mac-address", (void *)hw.addr, 6);
370         if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) {
371                 bcopy(hw.addr, addr, 6);
372                 return;
373         }
374
375         /* Also try the mac-address property, which is second-best */
376         i = OF_getprop(sc->node, "mac-address", (void *)hw.addr, 6);
377         if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) {
378                 bcopy(hw.addr, addr, 6);
379                 return;
380         }
381
382         /*
383          * Fall back -- use the currently programmed address in the hope that
384          * it was set be firmware...
385          */
386         hw.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1);
387         hw.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2);
388         for (i = 0; i < 6; i++)
389                 addr[5-i] = hw.addr[i];
390 }