1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: stable/11/sys/mips/rt305x/rt305x_ehci.c 308401 2016-11-07 08:36:06Z hselasky $");
3
4/*-
5 * Copyright (c) 2015 Stanislav Galabov. All rights reserved.
6 * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved.
7 * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/stdint.h>
32#include <sys/stddef.h>
33#include <sys/param.h>
34#include <sys/queue.h>
35#include <sys/types.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/bus.h>
39#include <sys/module.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42#include <sys/condvar.h>
43#include <sys/sysctl.h>
44#include <sys/sx.h>
45#include <sys/unistd.h>
46#include <sys/callout.h>
47#include <sys/malloc.h>
48#include <sys/priv.h>
49#include <sys/rman.h>
50
51#include <dev/usb/usb.h>
52#include <dev/usb/usbdi.h>
53
54#include <dev/usb/usb_core.h>
55#include <dev/usb/usb_busdma.h>
56#include <dev/usb/usb_process.h>
57#include <dev/usb/usb_util.h>
58
59#include <dev/usb/usb_controller.h>
60#include <dev/usb/usb_bus.h>
61
62#include <dev/usb/controller/ehci.h>
63
64#include <mips/rt305x/rt305xreg.h>
65#include <mips/rt305x/rt305x_sysctlvar.h>
66
67#define EHCI_HC_DEVSTR	"Ralink integrated USB 2.0 controller"
68
69static device_probe_t ehci_obio_probe;
70static device_attach_t ehci_obio_attach;
71static device_detach_t ehci_obio_detach;
72
73static int
74ehci_obio_probe(device_t self)
75{
76	device_set_desc(self, EHCI_HC_DEVSTR);
77
78	return (BUS_PROBE_DEFAULT);
79}
80
81static int
82ehci_obio_attach(device_t self)
83{
84	ehci_softc_t *sc = device_get_softc(self);
85	uint32_t reg;
86	int err;
87	int rid;
88
89	/* setup controller interface softc */
90	reg = rt305x_sysctl_get(SYSCTL_SYSCFG1);
91	reg |= SYSCTL_SYSCFG1_USB0_HOST_MODE;
92	rt305x_sysctl_set(SYSCTL_SYSCFG1, reg);
93
94	reg = rt305x_sysctl_get(SYSCTL_CLKCFG1);
95	reg |= SYSCTL_CLKCFG1_UPHY0_CLK_EN;
96#ifdef MT7620
97	reg |= SYSCTL_CLKCFG1_UPHY1_CLK_EN;
98#endif
99	rt305x_sysctl_set(SYSCTL_CLKCFG1, reg);
100
101	reg = rt305x_sysctl_get(SYSCTL_RSTCTRL);
102	reg |= SYSCTL_RSTCTRL_UPHY0 | SYSCTL_RSTCTRL_UPHY1;
103	rt305x_sysctl_set(SYSCTL_RSTCTRL, reg);
104	reg &= ~(SYSCTL_RSTCTRL_UPHY0 | SYSCTL_RSTCTRL_UPHY1);
105	DELAY(100000);
106	rt305x_sysctl_set(SYSCTL_RSTCTRL, reg);
107	DELAY(100000);
108
109	/* initialise some bus fields */
110	sc->sc_bus.parent = self;
111	sc->sc_bus.devices = sc->sc_devices;
112	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
113	sc->sc_bus.dma_bits = 32;
114
115	/* get all DMA memory */
116	if (usb_bus_mem_alloc_all(&sc->sc_bus,
117	    USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
118		printf("No mem\n");
119		return (ENOMEM);
120	}
121
122	rid = 0;
123	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
124				RF_ACTIVE);
125	if (!sc->sc_io_res) {
126		device_printf(self, "Could not map memory\n");
127		goto error;
128	}
129	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
130	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
131	sc->sc_io_size = rman_get_size(sc->sc_io_res);
132
133	rid = 0;
134	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
135		RF_SHAREABLE | RF_ACTIVE);
136	if (sc->sc_irq_res == NULL) {
137		device_printf(self, "Could not allocate irq\n");
138		goto error;
139	}
140
141	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
142	if (!(sc->sc_bus.bdev)) {
143		device_printf(self, "Could not add USB device\n");
144		goto error;
145	}
146	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
147	device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
148
149	sprintf(sc->sc_vendor, "Ralink");
150
151	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
152		NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
153	if (err) {
154		device_printf(self, "Could not setup irq, %d\n", err);
155		sc->sc_intr_hdl = NULL;
156		goto error;
157	}
158
159	err = ehci_init(sc);
160	if (!err) {
161		err = device_probe_and_attach(sc->sc_bus.bdev);
162	}
163	if (err) {
164		device_printf(self, "USB init failed err=%d\n", err);
165		goto error;
166	}
167	return (0);
168
169error:
170	ehci_obio_detach(self);
171	return (ENXIO);
172}
173
174static int
175ehci_obio_detach(device_t self)
176{
177	ehci_softc_t *sc = device_get_softc(self);
178	int err;
179
180	/* during module unload there are lots of children leftover */
181	device_delete_children(self);
182
183	if (sc->sc_irq_res && sc->sc_intr_hdl) {
184		/*
185		 * only call ehci_detach() after ehci_init()
186		 */
187		ehci_detach(sc);
188
189		/* Stop EHCI clock */
190		rt305x_sysctl_set(SYSCTL_CLKCFG1,
191		  rt305x_sysctl_get(SYSCTL_CLKCFG1) &
192		  ~(SYSCTL_CLKCFG1_UPHY0_CLK_EN
193#ifdef MT7620
194		    | SYSCTL_CLKCFG1_UPHY1_CLK_EN
195#endif
196		));
197
198		err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
199		if (err)
200			device_printf(self, "Could not tear down irq, %d\n",
201				err);
202		sc->sc_intr_hdl = NULL;
203	}
204	if (sc->sc_irq_res) {
205		bus_release_resource(self, SYS_RES_IRQ, 0,
206		    sc->sc_irq_res);
207		sc->sc_irq_res = NULL;
208	}
209	if (sc->sc_io_res) {
210		bus_release_resource(self, SYS_RES_MEMORY, 0,
211		    sc->sc_io_res);
212		sc->sc_io_res = NULL;
213	}
214	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
215
216	return (0);
217}
218
219static device_method_t ehci_obio_methods[] = {
220	/* Device interface */
221	DEVMETHOD(device_probe, ehci_obio_probe),
222	DEVMETHOD(device_attach, ehci_obio_attach),
223	DEVMETHOD(device_detach, ehci_obio_detach),
224	DEVMETHOD(device_suspend, bus_generic_suspend),
225	DEVMETHOD(device_resume, bus_generic_resume),
226	DEVMETHOD(device_shutdown, bus_generic_shutdown),
227
228	DEVMETHOD_END
229};
230
231static driver_t ehci_obio_driver = {
232	.name = "ehci",
233	.methods = ehci_obio_methods,
234	.size = sizeof(ehci_softc_t),
235};
236
237static devclass_t ehci_obio_devclass;
238
239DRIVER_MODULE(ehci, obio, ehci_obio_driver, ehci_obio_devclass, 0, 0);
240