generic_ohci.c revision 308401
1208625Sjkim/*-
2208625Sjkim * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
3208625Sjkim * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org>
4208625Sjkim * All rights reserved.
5208625Sjkim *
6208625Sjkim * Redistribution and use in source and binary forms, with or without
7217365Sjkim * modification, are permitted provided that the following conditions
8217365Sjkim * are met:
9208625Sjkim * 1. Redistributions of source code must retain the above copyright
10208625Sjkim *    notice, this list of conditions and the following disclaimer.
11217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright
12217365Sjkim *    notice, this list of conditions and the following disclaimer in the
13217365Sjkim *    documentation and/or other materials provided with the distribution.
14217365Sjkim *
15217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25208625Sjkim * SUCH DAMAGE.
26217365Sjkim */
27217365Sjkim
28217365Sjkim/*
29208625Sjkim * Generic OHCI driver based on AT91 OHCI
30217365Sjkim */
31217365Sjkim
32217365Sjkim#include <sys/cdefs.h>
33217365Sjkim__FBSDID("$FreeBSD: stable/11/sys/dev/usb/controller/generic_ohci.c 308401 2016-11-07 08:36:06Z hselasky $");
34217365Sjkim
35217365Sjkim#include <sys/param.h>
36217365Sjkim#include <sys/systm.h>
37217365Sjkim#include <sys/bus.h>
38217365Sjkim#include <sys/rman.h>
39217365Sjkim#include <sys/condvar.h>
40217365Sjkim#include <sys/kernel.h>
41217365Sjkim#include <sys/module.h>
42217365Sjkim
43208625Sjkim#include <machine/bus.h>
44208625Sjkim#include <dev/ofw/ofw_bus.h>
45208625Sjkim#include <dev/ofw/ofw_bus_subr.h>
46209746Sjkim
47209746Sjkim#include <dev/usb/usb.h>
48209746Sjkim#include <dev/usb/usbdi.h>
49208625Sjkim
50208625Sjkim#include <dev/usb/usb_core.h>
51208625Sjkim#include <dev/usb/usb_busdma.h>
52208625Sjkim#include <dev/usb/usb_process.h>
53208625Sjkim#include <dev/usb/usb_util.h>
54208625Sjkim
55208625Sjkim#include <dev/usb/usb_controller.h>
56208625Sjkim#include <dev/usb/usb_bus.h>
57208625Sjkim#include <dev/usb/controller/ohci.h>
58208625Sjkim#include <dev/usb/controller/ohcireg.h>
59208625Sjkim
60208625Sjkim#ifdef EXT_RESOURCES
61208625Sjkim#include <dev/extres/clk/clk.h>
62208625Sjkim#include <dev/extres/hwreset/hwreset.h>
63208625Sjkim#include <dev/extres/phy/phy.h>
64208625Sjkim#endif
65208625Sjkim
66208625Sjkim#include "generic_usb_if.h"
67208625Sjkim
68208625Sjkim#ifdef EXT_RESOURCES
69208625Sjkimstruct clk_list {
70208625Sjkim	TAILQ_ENTRY(clk_list)	next;
71208625Sjkim	clk_t			clk;
72208625Sjkim};
73208625Sjkim#endif
74208625Sjkim
75208625Sjkimstruct generic_ohci_softc {
76208625Sjkim	ohci_softc_t	ohci_sc;
77208625Sjkim
78208625Sjkim#ifdef EXT_RESOURCES
79208625Sjkim	hwreset_t	rst;
80208625Sjkim	phy_t		phy;
81208625Sjkim	TAILQ_HEAD(, clk_list)	clk_list;
82208625Sjkim#endif
83208625Sjkim};
84208625Sjkim
85208625Sjkimstatic int generic_ohci_detach(device_t);
86208625Sjkim
87208625Sjkimstatic int
88208625Sjkimgeneric_ohci_probe(device_t dev)
89208625Sjkim{
90208625Sjkim
91208625Sjkim	if (!ofw_bus_status_okay(dev))
92208625Sjkim		return (ENXIO);
93208625Sjkim
94208625Sjkim	if (!ofw_bus_is_compatible(dev, "generic-ohci"))
95208625Sjkim		return (ENXIO);
96208625Sjkim
97208625Sjkim	device_set_desc(dev, "Generic OHCI Controller");
98208625Sjkim
99208625Sjkim	return (BUS_PROBE_DEFAULT);
100208625Sjkim}
101208625Sjkim
102208625Sjkimstatic int
103208625Sjkimgeneric_ohci_attach(device_t dev)
104208625Sjkim{
105208625Sjkim	struct generic_ohci_softc *sc = device_get_softc(dev);
106208625Sjkim	int err, rid;
107208625Sjkim#ifdef EXT_RESOURCES
108208625Sjkim	int off;
109208625Sjkim	struct clk_list *clkp;
110208625Sjkim	clk_t clk;
111208625Sjkim#endif
112208625Sjkim
113208625Sjkim	sc->ohci_sc.sc_bus.parent = dev;
114208625Sjkim	sc->ohci_sc.sc_bus.devices = sc->ohci_sc.sc_devices;
115208625Sjkim	sc->ohci_sc.sc_bus.devices_max = OHCI_MAX_DEVICES;
116208625Sjkim	sc->ohci_sc.sc_bus.dma_bits = 32;
117208625Sjkim
118208625Sjkim	/* get all DMA memory */
119208625Sjkim	if (usb_bus_mem_alloc_all(&sc->ohci_sc.sc_bus,
120208625Sjkim	    USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) {
121208625Sjkim		return (ENOMEM);
122208625Sjkim	}
123208625Sjkim
124208625Sjkim	rid = 0;
125208625Sjkim	sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
126208625Sjkim	    &rid, RF_ACTIVE);
127208625Sjkim	if (sc->ohci_sc.sc_io_res == 0) {
128208625Sjkim		err = ENOMEM;
129208625Sjkim		goto error;
130208625Sjkim	}
131208625Sjkim
132208625Sjkim	sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res);
133208625Sjkim	sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res);
134208625Sjkim	sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res);
135208625Sjkim
136208625Sjkim	rid = 0;
137208625Sjkim	sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
138208625Sjkim	    RF_ACTIVE);
139208625Sjkim	if (sc->ohci_sc.sc_irq_res == 0) {
140208625Sjkim		err = ENXIO;
141208625Sjkim		goto error;
142208625Sjkim	}
143208625Sjkim	sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
144208625Sjkim	if (sc->ohci_sc.sc_bus.bdev == 0) {
145208625Sjkim		err = ENXIO;
146208625Sjkim		goto error;
147208625Sjkim	}
148208625Sjkim	device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus);
149208625Sjkim
150208625Sjkim	strlcpy(sc->ohci_sc.sc_vendor, "Generic",
151208625Sjkim	    sizeof(sc->ohci_sc.sc_vendor));
152208625Sjkim
153208625Sjkim	err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res,
154208625Sjkim	    INTR_TYPE_BIO | INTR_MPSAFE, NULL,
155208625Sjkim	    (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl);
156208625Sjkim	if (err) {
157208625Sjkim		sc->ohci_sc.sc_intr_hdl = NULL;
158208625Sjkim		goto error;
159208625Sjkim	}
160208625Sjkim
161208625Sjkim#ifdef EXT_RESOURCES
162208625Sjkim	TAILQ_INIT(&sc->clk_list);
163208625Sjkim	/* Enable clock */
164208625Sjkim	for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
165208625Sjkim		err = clk_enable(clk);
166208625Sjkim		if (err != 0) {
167208625Sjkim			device_printf(dev, "Could not enable clock %s\n",
168208625Sjkim			    clk_get_name(clk));
169208625Sjkim			goto error;
170208625Sjkim		}
171208625Sjkim		clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO);
172208625Sjkim		clkp->clk = clk;
173208625Sjkim		TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next);
174208625Sjkim	}
175208625Sjkim
176208625Sjkim	/* De-assert reset */
177208625Sjkim	if (hwreset_get_by_ofw_idx(dev, 0, 0, &sc->rst) == 0) {
178208625Sjkim		err = hwreset_deassert(sc->rst);
179208625Sjkim		if (err != 0) {
180208625Sjkim			device_printf(dev, "Could not de-assert reset %d\n",
181208625Sjkim			    off);
182208625Sjkim			goto error;
183208625Sjkim		}
184208625Sjkim	}
185208625Sjkim
186208625Sjkim	/* Enable phy */
187208625Sjkim	if (phy_get_by_ofw_name(dev, 0, "usb", &sc->phy) == 0) {
188208625Sjkim		err = phy_enable(dev, sc->phy);
189208625Sjkim		if (err != 0) {
190208625Sjkim			device_printf(dev, "Could not enable phy\n");
191208625Sjkim			goto error;
192208625Sjkim		}
193208625Sjkim	}
194208625Sjkim#endif
195208625Sjkim
196208625Sjkim	if (GENERIC_USB_INIT(dev) != 0) {
197208625Sjkim		err = ENXIO;
198208625Sjkim		goto error;
199208625Sjkim	}
200208625Sjkim
201208625Sjkim	err = ohci_init(&sc->ohci_sc);
202208625Sjkim	if (err == 0)
203208625Sjkim		err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev);
204208625Sjkim	if (err)
205208625Sjkim		goto error;
206208625Sjkim
207208625Sjkim	return (0);
208208625Sjkimerror:
209208625Sjkim	generic_ohci_detach(dev);
210208625Sjkim	return (err);
211208625Sjkim}
212208625Sjkim
213208625Sjkimstatic int
214208625Sjkimgeneric_ohci_detach(device_t dev)
215208625Sjkim{
216208625Sjkim	struct generic_ohci_softc *sc = device_get_softc(dev);
217208625Sjkim	int err;
218208625Sjkim#ifdef EXT_RESOURCES
219208625Sjkim	struct clk_list *clk, *clk_tmp;
220208625Sjkim#endif
221208625Sjkim
222208625Sjkim	/* during module unload there are lots of children leftover */
223208625Sjkim	device_delete_children(dev);
224208625Sjkim
225208625Sjkim	/*
226208625Sjkim	 * Put the controller into reset, then disable clocks and do
227208625Sjkim	 * the MI tear down.  We have to disable the clocks/hardware
228208625Sjkim	 * after we do the rest of the teardown.  We also disable the
229208625Sjkim	 * clocks in the opposite order we acquire them, but that
230208625Sjkim	 * doesn't seem to be absolutely necessary.  We free up the
231208625Sjkim	 * clocks after we disable them, so the system could, in
232208625Sjkim	 * theory, reuse them.
233208625Sjkim	 */
234208625Sjkim	bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl,
235208625Sjkim	    OHCI_CONTROL, 0);
236208625Sjkim
237208625Sjkim	if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) {
238208625Sjkim		/*
239208625Sjkim		 * only call ohci_detach() after ohci_init()
240208625Sjkim		 */
241208625Sjkim		ohci_detach(&sc->ohci_sc);
242208625Sjkim
243208625Sjkim		err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res,
244208625Sjkim		    sc->ohci_sc.sc_intr_hdl);
245208625Sjkim		sc->ohci_sc.sc_intr_hdl = NULL;
246208625Sjkim	}
247208625Sjkim	if (sc->ohci_sc.sc_irq_res) {
248208625Sjkim		bus_release_resource(dev, SYS_RES_IRQ, 0,
249208625Sjkim		    sc->ohci_sc.sc_irq_res);
250208625Sjkim		sc->ohci_sc.sc_irq_res = NULL;
251208625Sjkim	}
252208625Sjkim	if (sc->ohci_sc.sc_io_res) {
253208625Sjkim		bus_release_resource(dev, SYS_RES_MEMORY, 0,
254208625Sjkim		    sc->ohci_sc.sc_io_res);
255208625Sjkim		sc->ohci_sc.sc_io_res = NULL;
256208625Sjkim	}
257208625Sjkim	usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc);
258208625Sjkim
259208625Sjkim#ifdef EXT_RESOURCES
260208625Sjkim	/* Disable phy */
261208625Sjkim	if (sc->phy) {
262208625Sjkim		err = phy_disable(dev, sc->phy);
263208625Sjkim		if (err != 0)
264208625Sjkim			device_printf(dev, "Could not disable phy\n");
265208625Sjkim		phy_release(sc->phy);
266208625Sjkim	}
267208625Sjkim
268208625Sjkim	/* Disable clock */
269208625Sjkim	TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) {
270208625Sjkim		err = clk_disable(clk->clk);
271208625Sjkim		if (err != 0)
272208625Sjkim			device_printf(dev, "Could not disable clock %s\n",
273208625Sjkim			    clk_get_name(clk->clk));
274208625Sjkim		err = clk_release(clk->clk);
275208625Sjkim		if (err != 0)
276208625Sjkim			device_printf(dev, "Could not release clock %s\n",
277208625Sjkim			    clk_get_name(clk->clk));
278208625Sjkim		TAILQ_REMOVE(&sc->clk_list, clk, next);
279208625Sjkim		free(clk, M_DEVBUF);
280208625Sjkim	}
281208625Sjkim
282208625Sjkim	/* De-assert reset */
283208625Sjkim	if (sc->rst) {
284208625Sjkim		err = hwreset_assert(sc->rst);
285208625Sjkim		if (err != 0)
286208625Sjkim			device_printf(dev, "Could not assert reset\n");
287208625Sjkim		hwreset_release(sc->rst);
288208625Sjkim	}
289208625Sjkim#endif
290208625Sjkim
291208625Sjkim	if (GENERIC_USB_DEINIT(dev) != 0)
292208625Sjkim		return (ENXIO);
293208625Sjkim
294208625Sjkim	return (0);
295208625Sjkim}
296208625Sjkim
297208625Sjkimstatic device_method_t generic_ohci_methods[] = {
298208625Sjkim	/* Device interface */
299208625Sjkim	DEVMETHOD(device_probe, generic_ohci_probe),
300208625Sjkim	DEVMETHOD(device_attach, generic_ohci_attach),
301208625Sjkim	DEVMETHOD(device_detach, generic_ohci_detach),
302208625Sjkim
303208625Sjkim	DEVMETHOD(device_suspend, bus_generic_suspend),
304208625Sjkim	DEVMETHOD(device_resume, bus_generic_resume),
305208625Sjkim	DEVMETHOD(device_shutdown, bus_generic_shutdown),
306208625Sjkim
307208625Sjkim	DEVMETHOD_END
308208625Sjkim};
309208625Sjkim
310208625Sjkimdriver_t generic_ohci_driver = {
311208625Sjkim	.name = "ohci",
312208625Sjkim	.methods = generic_ohci_methods,
313208625Sjkim	.size = sizeof(struct generic_ohci_softc),
314208625Sjkim};
315208625Sjkim
316208625Sjkimstatic devclass_t generic_ohci_devclass;
317208625Sjkim
318208625SjkimDRIVER_MODULE(ohci, simplebus, generic_ohci_driver,
319208625Sjkim    generic_ohci_devclass, 0, 0);
320208625SjkimMODULE_DEPEND(ohci, usb, 1, 1, 1);
321208625Sjkim