ar71xx_ehci.c revision 290910
1275988Sngie/*-
2240116Smarcel * Copyright (c) 2008 Sam Leffler.  All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14240116Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15240116Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16240116Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17240116Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18240116Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19240116Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20240116Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21240116Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22240116Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23240116Smarcel */
24275988Sngie
25240116Smarcel/*
26275988Sngie * AR71XX attachment driver for the USB Enhanced Host Controller.
27275988Sngie */
28240116Smarcel
29240116Smarcel#include <sys/cdefs.h>
30240116Smarcel__FBSDID("$FreeBSD: head/sys/mips/atheros/ar71xx_ehci.c 290910 2015-11-16 04:28:00Z adrian $");
31275988Sngie
32275988Sngie#include "opt_bus.h"
33275988Sngie
34240116Smarcel#include <sys/param.h>
35240116Smarcel#include <sys/systm.h>
36240116Smarcel#include <sys/bus.h>
37240116Smarcel#include <sys/rman.h>
38240116Smarcel#include <sys/condvar.h>
39240116Smarcel#include <sys/kernel.h>
40240116Smarcel#include <sys/module.h>
41240116Smarcel
42275988Sngie#include <machine/bus.h>
43240116Smarcel
44240116Smarcel#include <dev/usb/usb.h>
45240116Smarcel#include <dev/usb/usbdi.h>
46240116Smarcel
47275988Sngie#include <dev/usb/usb_core.h>
48275988Sngie#include <dev/usb/usb_busdma.h>
49240116Smarcel#include <dev/usb/usb_process.h>
50240116Smarcel#include <dev/usb/usb_util.h>
51240116Smarcel
52240116Smarcel#include <dev/usb/usb_controller.h>
53240116Smarcel#include <dev/usb/usb_bus.h>
54240116Smarcel#include <dev/usb/controller/ehci.h>
55240116Smarcel#include <dev/usb/controller/ehcireg.h>
56240116Smarcel
57240116Smarcel#include <mips/atheros/ar71xx_setup.h>
58240116Smarcel#include <mips/atheros/ar71xxreg.h> /* for stuff in ar71xx_cpudef.h */
59240116Smarcel#include <mips/atheros/ar71xx_cpudef.h>
60240116Smarcel#include <mips/atheros/ar71xx_bus_space_reversed.h>
61240116Smarcel
62240116Smarcel#define EHCI_HC_DEVSTR		"AR71XX Integrated USB 2.0 controller"
63240116Smarcel
64240116Smarcelstruct ar71xx_ehci_softc {
65240116Smarcel	ehci_softc_t		base;	/* storage for EHCI code */
66240116Smarcel};
67240116Smarcel
68240116Smarcelstatic device_attach_t ar71xx_ehci_attach;
69240116Smarcelstatic device_detach_t ar71xx_ehci_detach;
70240116Smarcel
71240116Smarcelbs_r_1_proto(reversed);
72240116Smarcelbs_w_1_proto(reversed);
73240116Smarcel
74240116Smarcelstatic int
75240116Smarcelar71xx_ehci_probe(device_t self)
76240116Smarcel{
77240116Smarcel
78240116Smarcel	device_set_desc(self, EHCI_HC_DEVSTR);
79240116Smarcel
80240116Smarcel	return (BUS_PROBE_NOWILDCARD);
81240116Smarcel}
82240116Smarcel
83240116Smarcelstatic void
84240116Smarcelar71xx_ehci_intr(void *arg)
85240116Smarcel{
86240116Smarcel
87240116Smarcel	/* XXX TODO: should really see if this was our interrupt.. */
88240116Smarcel	ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB);
89240116Smarcel	ehci_interrupt(arg);
90240116Smarcel}
91240116Smarcel
92240116Smarcelstatic int
93240116Smarcelar71xx_ehci_attach(device_t self)
94240116Smarcel{
95240116Smarcel	struct ar71xx_ehci_softc *isc = device_get_softc(self);
96240116Smarcel	ehci_softc_t *sc = &isc->base;
97240116Smarcel	int err;
98240116Smarcel	int rid;
99240116Smarcel
100240116Smarcel	/* initialise some bus fields */
101240116Smarcel	sc->sc_bus.parent = self;
102240116Smarcel	sc->sc_bus.devices = sc->sc_devices;
103240116Smarcel	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
104240116Smarcel	sc->sc_bus.dma_bits = 32;
105240116Smarcel
106240116Smarcel	/* get all DMA memory */
107240116Smarcel	if (usb_bus_mem_alloc_all(&sc->sc_bus,
108240116Smarcel	    USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
109240116Smarcel		return (ENOMEM);
110240116Smarcel	}
111240116Smarcel
112240116Smarcel	sc->sc_bus.usbrev = USB_REV_2_0;
113240116Smarcel
114240116Smarcel	/* NB: hints fix the memory location and irq */
115240116Smarcel
116240116Smarcel	rid = 0;
117240116Smarcel	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
118240116Smarcel	if (!sc->sc_io_res) {
119240116Smarcel		device_printf(self, "Could not map memory\n");
120240116Smarcel		goto error;
121240116Smarcel	}
122240116Smarcel
123240116Smarcel	/*
124240116Smarcel	 * Craft special resource for bus space ops that handle
125240116Smarcel	 * byte-alignment of non-word addresses.
126240116Smarcel	 */
127240116Smarcel	sc->sc_io_tag = ar71xx_bus_space_reversed;
128240116Smarcel	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
129240116Smarcel	sc->sc_io_size = rman_get_size(sc->sc_io_res);
130240116Smarcel
131240116Smarcel	rid = 0;
132240116Smarcel	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
133240116Smarcel	    RF_ACTIVE | RF_SHAREABLE);
134240116Smarcel	if (sc->sc_irq_res == NULL) {
135240116Smarcel		device_printf(self, "Could not allocate irq\n");
136240116Smarcel		goto error;
137240116Smarcel	}
138240116Smarcel	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
139240116Smarcel	if (!sc->sc_bus.bdev) {
140240116Smarcel		device_printf(self, "Could not add USB device\n");
141240116Smarcel		goto error;
142240116Smarcel	}
143240116Smarcel	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
144240116Smarcel	device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
145240116Smarcel
146240116Smarcel	sprintf(sc->sc_vendor, "Atheros");
147240116Smarcel
148240116Smarcel	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
149240116Smarcel	    NULL, ar71xx_ehci_intr, sc, &sc->sc_intr_hdl);
150240116Smarcel	if (err) {
151240116Smarcel		device_printf(self, "Could not setup irq, %d\n", err);
152240116Smarcel		sc->sc_intr_hdl = NULL;
153240116Smarcel		goto error;
154240116Smarcel	}
155240116Smarcel
156240116Smarcel	/*
157240116Smarcel	 * Arrange to force Host mode, select big-endian byte alignment,
158275988Sngie	 * and arrange to not terminate reset operations (the adapter
159240116Smarcel	 * will ignore it if we do but might as well save a reg write).
160240116Smarcel	 * Also, the controller has an embedded Transaction Translator
161240116Smarcel	 * which means port speed must be read from the Port Status
162275988Sngie	 * register following a port enable.
163275988Sngie	 */
164240116Smarcel	sc->sc_flags = EHCI_SCFLG_SETMODE;
165240116Smarcel
166240116Smarcel	switch (ar71xx_soc) {
167275988Sngie		case AR71XX_SOC_AR7241:
168240116Smarcel		case AR71XX_SOC_AR7242:
169240116Smarcel		case AR71XX_SOC_AR9130:
170240116Smarcel		case AR71XX_SOC_AR9132:
171240116Smarcel		case AR71XX_SOC_AR9330:
172240116Smarcel		case AR71XX_SOC_AR9331:
173240116Smarcel		case AR71XX_SOC_AR9341:
174240116Smarcel		case AR71XX_SOC_AR9342:
175240116Smarcel		case AR71XX_SOC_AR9344:
176240116Smarcel		case AR71XX_SOC_QCA9533:
177240116Smarcel		case AR71XX_SOC_QCA9533_V2:
178240116Smarcel		case AR71XX_SOC_QCA9556:
179240116Smarcel		case AR71XX_SOC_QCA9558:
180240116Smarcel			sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
181240116Smarcel			break;
182240116Smarcel		default:
183240116Smarcel			/* fallthrough */
184240116Smarcel			break;
185240116Smarcel	}
186240116Smarcel
187240116Smarcel	/*
188240116Smarcel	 * ehci_reset() needs the correct offset to access the host controller
189240116Smarcel	 * registers. The AR724x/AR913x offsets aren't 0.
190240116Smarcel	*/
191240116Smarcel	sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION));
192240116Smarcel
193240116Smarcel	(void) ehci_reset(sc);
194240116Smarcel
195240116Smarcel	err = ehci_init(sc);
196240116Smarcel	if (!err) {
197240116Smarcel		err = device_probe_and_attach(sc->sc_bus.bdev);
198240116Smarcel	}
199240116Smarcel	if (err) {
200240116Smarcel		device_printf(self, "USB init failed err=%d\n", err);
201240116Smarcel		goto error;
202240116Smarcel	}
203240116Smarcel	return (0);
204275988Sngie
205240116Smarcelerror:
206240116Smarcel	ar71xx_ehci_detach(self);
207240116Smarcel	return (ENXIO);
208275988Sngie}
209275988Sngie
210240116Smarcelstatic int
211240116Smarcelar71xx_ehci_detach(device_t self)
212240116Smarcel{
213240116Smarcel	struct ar71xx_ehci_softc *isc = device_get_softc(self);
214240116Smarcel	ehci_softc_t *sc = &isc->base;
215240116Smarcel	device_t bdev;
216240116Smarcel	int err;
217240116Smarcel
218240116Smarcel 	if (sc->sc_bus.bdev) {
219240116Smarcel		bdev = sc->sc_bus.bdev;
220240116Smarcel		device_detach(bdev);
221240116Smarcel		device_delete_child(self, bdev);
222240116Smarcel	}
223240116Smarcel	/* during module unload there are lots of children leftover */
224240116Smarcel	device_delete_children(self);
225240116Smarcel
226240116Smarcel 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
227240116Smarcel		/*
228240116Smarcel		 * only call ehci_detach() after ehci_init()
229240116Smarcel		 */
230240116Smarcel		ehci_detach(sc);
231240116Smarcel
232240116Smarcel		err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
233240116Smarcel
234240116Smarcel		if (err)
235240116Smarcel			/* XXX or should we panic? */
236240116Smarcel			device_printf(self, "Could not tear down irq, %d\n",
237240116Smarcel			    err);
238240116Smarcel		sc->sc_intr_hdl = NULL;
239240116Smarcel	}
240240116Smarcel
241240116Smarcel 	if (sc->sc_irq_res) {
242240116Smarcel		bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
243240116Smarcel		sc->sc_irq_res = NULL;
244240116Smarcel	}
245240116Smarcel	if (sc->sc_io_res) {
246240116Smarcel		bus_release_resource(self, SYS_RES_MEMORY, 0,
247240116Smarcel		    sc->sc_io_res);
248240116Smarcel		sc->sc_io_res = NULL;
249240116Smarcel	}
250275988Sngie	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
251240116Smarcel
252240116Smarcel	return (0);
253240116Smarcel}
254275988Sngie
255275988Sngiestatic device_method_t ehci_methods[] = {
256240116Smarcel	/* Device interface */
257240116Smarcel	DEVMETHOD(device_probe, ar71xx_ehci_probe),
258240116Smarcel	DEVMETHOD(device_attach, ar71xx_ehci_attach),
259275988Sngie	DEVMETHOD(device_detach, ar71xx_ehci_detach),
260275988Sngie	DEVMETHOD(device_suspend, bus_generic_suspend),
261240116Smarcel	DEVMETHOD(device_resume, bus_generic_resume),
262240116Smarcel	DEVMETHOD(device_shutdown, bus_generic_shutdown),
263240116Smarcel
264240116Smarcel	DEVMETHOD_END
265240116Smarcel};
266240116Smarcel
267240116Smarcelstatic driver_t ehci_driver = {
268240116Smarcel	.name = "ehci",
269240116Smarcel	.methods = ehci_methods,
270240116Smarcel	.size = sizeof(struct ar71xx_ehci_softc),
271240116Smarcel};
272240116Smarcel
273240116Smarcelstatic devclass_t ehci_devclass;
274240116Smarcel
275240116SmarcelDRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0);
276240116SmarcelDRIVER_MODULE(ehci, apb, ehci_driver, ehci_devclass, 0, 0);
277240116Smarcel
278240116SmarcelMODULE_DEPEND(ehci, usb, 1, 1, 1);
279240116Smarcel