1 /*-
2 * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org> All rights reserved.
3 * Copyright (c) 2006 M. Warner Losh <imp@FreeBSD.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /*
28 * Generic OHCI driver based on AT91 OHCI
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/rman.h>
38 #include <sys/condvar.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41
42 #include <machine/bus.h>
43 #include <dev/ofw/ofw_bus.h>
44 #include <dev/ofw/ofw_bus_subr.h>
45
46 #include <dev/usb/usb.h>
47 #include <dev/usb/usbdi.h>
48
49 #include <dev/usb/usb_core.h>
50 #include <dev/usb/usb_busdma.h>
51 #include <dev/usb/usb_process.h>
52 #include <dev/usb/usb_util.h>
53
54 #include <dev/usb/usb_controller.h>
55 #include <dev/usb/usb_bus.h>
56 #include <dev/usb/controller/ohci.h>
57 #include <dev/usb/controller/ohcireg.h>
58
59 #include <dev/extres/clk/clk.h>
60 #include <dev/extres/hwreset/hwreset.h>
61 #include <dev/extres/phy/phy.h>
62 #include <dev/extres/phy/phy_usb.h>
63
64 #include "generic_usb_if.h"
65
66 struct clk_list {
67 TAILQ_ENTRY(clk_list) next;
68 clk_t clk;
69 };
70 struct phy_list {
71 TAILQ_ENTRY(phy_list) next;
72 phy_t phy;
73 };
74 struct hwrst_list {
75 TAILQ_ENTRY(hwrst_list) next;
76 hwreset_t rst;
77 };
78
79 struct generic_ohci_softc {
80 ohci_softc_t ohci_sc;
81
82 TAILQ_HEAD(, clk_list) clk_list;
83 TAILQ_HEAD(, phy_list) phy_list;
84 TAILQ_HEAD(, hwrst_list) rst_list;
85 };
86
87 static int generic_ohci_detach(device_t);
88
89 static int
90 generic_ohci_probe(device_t dev)
91 {
92
93 if (!ofw_bus_status_okay(dev))
94 return (ENXIO);
95
96 if (!ofw_bus_is_compatible(dev, "generic-ohci"))
97 return (ENXIO);
98
99 device_set_desc(dev, "Generic OHCI Controller");
100
101 return (BUS_PROBE_DEFAULT);
102 }
103
104 static int
105 generic_ohci_attach(device_t dev)
106 {
107 struct generic_ohci_softc *sc = device_get_softc(dev);
108 int err, rid;
109 int off;
110 struct clk_list *clkp;
111 struct phy_list *phyp;
112 struct hwrst_list *rstp;
113 clk_t clk;
114 phy_t phy;
115 hwreset_t rst;
116
117 sc->ohci_sc.sc_bus.parent = dev;
118 sc->ohci_sc.sc_bus.devices = sc->ohci_sc.sc_devices;
119 sc->ohci_sc.sc_bus.devices_max = OHCI_MAX_DEVICES;
120 sc->ohci_sc.sc_bus.dma_bits = 32;
121
122 /* get all DMA memory */
123 if (usb_bus_mem_alloc_all(&sc->ohci_sc.sc_bus,
124 USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) {
125 return (ENOMEM);
126 }
127
128 rid = 0;
129 sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
130 &rid, RF_ACTIVE);
131 if (sc->ohci_sc.sc_io_res == 0) {
132 err = ENOMEM;
133 goto error;
134 }
135
136 sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res);
137 sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res);
138 sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res);
139
140 rid = 0;
141 sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
142 RF_ACTIVE);
143 if (sc->ohci_sc.sc_irq_res == 0) {
144 err = ENXIO;
145 goto error;
146 }
147 sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
148 if (sc->ohci_sc.sc_bus.bdev == 0) {
149 err = ENXIO;
150 goto error;
151 }
152 device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus);
153
154 strlcpy(sc->ohci_sc.sc_vendor, "Generic",
155 sizeof(sc->ohci_sc.sc_vendor));
156
157 err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res,
158 INTR_TYPE_BIO | INTR_MPSAFE, NULL,
159 (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl);
160 if (err) {
161 sc->ohci_sc.sc_intr_hdl = NULL;
162 goto error;
163 }
164
165 TAILQ_INIT(&sc->clk_list);
166 /* Enable clock */
167 for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
168 err = clk_enable(clk);
169 if (err != 0) {
170 device_printf(dev, "Could not enable clock %s\n",
171 clk_get_name(clk));
172 goto error;
173 }
174 clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO);
175 clkp->clk = clk;
176 TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next);
177 }
178
179 /* De-assert reset */
180 TAILQ_INIT(&sc->rst_list);
181 for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) {
182 err = hwreset_deassert(rst);
183 if (err != 0) {
184 device_printf(dev, "Could not de-assert reset\n");
185 goto error;
186 }
187 rstp = malloc(sizeof(*rstp), M_DEVBUF, M_WAITOK | M_ZERO);
188 rstp->rst = rst;
189 TAILQ_INSERT_TAIL(&sc->rst_list, rstp, next);
190 }
191
192 /* Enable phy */
193 TAILQ_INIT(&sc->phy_list);
194 for (off = 0; phy_get_by_ofw_idx(dev, 0, off, &phy) == 0; off++) {
195 err = phy_usb_set_mode(phy, PHY_USB_MODE_HOST);
196 if (err != 0) {
197 device_printf(dev, "Could not set phy to host mode\n");
198 goto error;
199 }
200 err = phy_enable(phy);
201 if (err != 0) {
202 device_printf(dev, "Could not enable phy\n");
203 goto error;
204 }
205 phyp = malloc(sizeof(*phyp), M_DEVBUF, M_WAITOK | M_ZERO);
206 phyp->phy = phy;
207 TAILQ_INSERT_TAIL(&sc->phy_list, phyp, next);
208 }
209
210 if (GENERIC_USB_INIT(dev) != 0) {
211 err = ENXIO;
212 goto error;
213 }
214
215 err = ohci_init(&sc->ohci_sc);
216 if (err == 0)
217 err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev);
218 if (err)
219 goto error;
220
221 return (0);
222 error:
223 generic_ohci_detach(dev);
224 return (err);
225 }
226
227 static int
228 generic_ohci_detach(device_t dev)
229 {
230 struct generic_ohci_softc *sc = device_get_softc(dev);
231 int err;
232 struct clk_list *clk, *clk_tmp;
233 struct phy_list *phy, *phy_tmp;
234 struct hwrst_list *rst, *rst_tmp;
235
236 /* during module unload there are lots of children leftover */
237 device_delete_children(dev);
238
239 /*
240 * Put the controller into reset, then disable clocks and do
241 * the MI tear down. We have to disable the clocks/hardware
242 * after we do the rest of the teardown. We also disable the
243 * clocks in the opposite order we acquire them, but that
244 * doesn't seem to be absolutely necessary. We free up the
245 * clocks after we disable them, so the system could, in
246 * theory, reuse them.
247 */
248 bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl,
249 OHCI_CONTROL, 0);
250
251 if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) {
252 /*
253 * only call ohci_detach() after ohci_init()
254 */
255 ohci_detach(&sc->ohci_sc);
256
257 err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res,
258 sc->ohci_sc.sc_intr_hdl);
259 sc->ohci_sc.sc_intr_hdl = NULL;
260 }
261 if (sc->ohci_sc.sc_irq_res) {
262 bus_release_resource(dev, SYS_RES_IRQ, 0,
263 sc->ohci_sc.sc_irq_res);
264 sc->ohci_sc.sc_irq_res = NULL;
265 }
266 if (sc->ohci_sc.sc_io_res) {
267 bus_release_resource(dev, SYS_RES_MEMORY, 0,
268 sc->ohci_sc.sc_io_res);
269 sc->ohci_sc.sc_io_res = NULL;
270 }
271 usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc);
272
273 /* Disable phy */
274 TAILQ_FOREACH_SAFE(phy, &sc->phy_list, next, phy_tmp) {
275 err = phy_disable(phy->phy);
276 if (err != 0)
277 device_printf(dev, "Could not disable phy\n");
278 phy_release(phy->phy);
279 TAILQ_REMOVE(&sc->phy_list, phy, next);
280 free(phy, M_DEVBUF);
281 }
282
283 /* Assert reset */
284 TAILQ_FOREACH_SAFE(rst, &sc->rst_list, next, rst_tmp) {
285 hwreset_assert(rst->rst);
286 hwreset_release(rst->rst);
287 TAILQ_REMOVE(&sc->rst_list, rst, next);
288 free(rst, M_DEVBUF);
289 }
290
291 /* Disable clock */
292 TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) {
293 err = clk_disable(clk->clk);
294 if (err != 0)
295 device_printf(dev, "Could not disable clock %s\n",
296 clk_get_name(clk->clk));
297 err = clk_release(clk->clk);
298 if (err != 0)
299 device_printf(dev, "Could not release clock %s\n",
300 clk_get_name(clk->clk));
301 TAILQ_REMOVE(&sc->clk_list, clk, next);
302 free(clk, M_DEVBUF);
303 }
304
305 if (GENERIC_USB_DEINIT(dev) != 0)
306 return (ENXIO);
307
308 return (0);
309 }
310
311 static device_method_t generic_ohci_methods[] = {
312 /* Device interface */
313 DEVMETHOD(device_probe, generic_ohci_probe),
314 DEVMETHOD(device_attach, generic_ohci_attach),
315 DEVMETHOD(device_detach, generic_ohci_detach),
316
317 DEVMETHOD(device_suspend, bus_generic_suspend),
318 DEVMETHOD(device_resume, bus_generic_resume),
319 DEVMETHOD(device_shutdown, bus_generic_shutdown),
320
321 DEVMETHOD_END
322 };
323
324 driver_t generic_ohci_driver = {
325 .name = "ohci",
326 .methods = generic_ohci_methods,
327 .size = sizeof(struct generic_ohci_softc),
328 };
329
330 DRIVER_MODULE(ohci, simplebus, generic_ohci_driver, 0, 0);
331 MODULE_DEPEND(ohci, usb, 1, 1, 1);
Cache object: 6b18dc8b6bdce6b10a576bb08deea658
|