1 /*-
2  * Copyright (c) 2014 Ruslan Bukin <[email protected]>
3  * All rights reserved.
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 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "opt_bus.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/condvar.h>
38 #include <sys/rman.h>
39 
40 #include <dev/ofw/ofw_bus.h>
41 #include <dev/ofw/ofw_bus_subr.h>
42 
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbdi.h>
45 #include <dev/usb/usb_busdma.h>
46 #include <dev/usb/usb_process.h>
47 #include <dev/usb/usb_controller.h>
48 #include <dev/usb/usb_bus.h>
49 #include <dev/usb/controller/xhci.h>
50 #include <dev/usb/controller/xhcireg.h>
51 
52 #include <machine/bus.h>
53 #include <machine/resource.h>
54 
55 #include <arm/samsung/exynos/exynos5_common.h>
56 
57 #include "opt_platform.h"
58 
59 #define	GSNPSID				0x20
60 #define	 GSNPSID_MASK			0xffff0000
61 #define	 REVISION_MASK			0xffff
62 #define	GCTL				0x10
63 #define	 GCTL_PWRDNSCALE(n)		((n) << 19)
64 #define	 GCTL_U2RSTECN			(1 << 16)
65 #define	 GCTL_CLK_BUS			(0)
66 #define	 GCTL_CLK_PIPE			(1)
67 #define	 GCTL_CLK_PIPEHALF		(2)
68 #define	 GCTL_CLK_M			(3)
69 #define	 GCTL_CLK_S			(6)
70 #define	 GCTL_PRTCAP(n)			(((n) & (3 << 12)) >> 12)
71 #define	 GCTL_PRTCAPDIR(n)		((n) << 12)
72 #define	 GCTL_PRTCAP_HOST		1
73 #define	 GCTL_PRTCAP_DEVICE		2
74 #define	 GCTL_PRTCAP_OTG		3
75 #define	 GCTL_CORESOFTRESET		(1 << 11)
76 #define	 GCTL_SCALEDOWN_MASK		3
77 #define	 GCTL_SCALEDOWN_SHIFT		4
78 #define	 GCTL_DISSCRAMBLE		(1 << 3)
79 #define	 GCTL_DSBLCLKGTNG		(1 << 0)
80 #define	GHWPARAMS1			0x3c
81 #define	 GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
82 #define	 GHWPARAMS1_EN_PWROPT_NO	0
83 #define	 GHWPARAMS1_EN_PWROPT_CLK	1
84 #define	GUSB2PHYCFG(n)			(0x100 + (n * 0x04))
85 #define	 GUSB2PHYCFG_PHYSOFTRST		(1 << 31)
86 #define	 GUSB2PHYCFG_SUSPHY		(1 << 6)
87 #define	GUSB3PIPECTL(n)			(0x1c0 + (n * 0x04))
88 #define	 GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
89 #define	 GUSB3PIPECTL_SUSPHY		(1 << 17)
90 
91 /* Forward declarations */
92 static device_attach_t exynos_xhci_attach;
93 static device_detach_t exynos_xhci_detach;
94 static device_probe_t exynos_xhci_probe;
95 
96 struct exynos_xhci_softc {
97 	device_t		dev;
98 	struct xhci_softc	base;
99 	struct resource		*res[3];
100 	bus_space_tag_t		bst;
101 	bus_space_handle_t	bsh;
102 };
103 
104 static struct resource_spec exynos_xhci_spec[] = {
105 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
106 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
107 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
108 	{ -1, 0 }
109 };
110 
111 static device_method_t xhci_methods[] = {
112 	/* Device interface */
113 	DEVMETHOD(device_probe, exynos_xhci_probe),
114 	DEVMETHOD(device_attach, exynos_xhci_attach),
115 	DEVMETHOD(device_detach, exynos_xhci_detach),
116 	DEVMETHOD(device_suspend, bus_generic_suspend),
117 	DEVMETHOD(device_resume, bus_generic_resume),
118 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
119 
120 	DEVMETHOD_END
121 };
122 
123 /* kobj_class definition */
124 static driver_t xhci_driver = {
125 	"xhci",
126 	xhci_methods,
127 	sizeof(struct xhci_softc)
128 };
129 
130 static devclass_t xhci_devclass;
131 
132 DRIVER_MODULE(xhci, simplebus, xhci_driver, xhci_devclass, 0, 0);
133 MODULE_DEPEND(xhci, usb, 1, 1, 1);
134 
135 /*
136  * Public methods
137  */
138 static int
exynos_xhci_probe(device_t dev)139 exynos_xhci_probe(device_t dev)
140 {
141 
142 	if (!ofw_bus_status_okay(dev))
143 		return (ENXIO);
144 
145 	if (ofw_bus_is_compatible(dev, "samsung,exynos5250-dwusb3") == 0)
146 		return (ENXIO);
147 
148 	device_set_desc(dev, "Exynos USB 3.0 controller");
149 	return (BUS_PROBE_DEFAULT);
150 }
151 
152 static int
dwc3_init(struct exynos_xhci_softc * esc)153 dwc3_init(struct exynos_xhci_softc *esc)
154 {
155 	int hwparams1;
156 	int rev;
157 	int reg;
158 
159 	rev = READ4(esc, GSNPSID);
160 	if ((rev & GSNPSID_MASK) != 0x55330000) {
161 		printf("It is not DWC3 controller\n");
162 		return (-1);
163 	}
164 
165 	/* Reset controller */
166 	WRITE4(esc, GCTL, GCTL_CORESOFTRESET);
167 	WRITE4(esc, GUSB3PIPECTL(0), GUSB3PIPECTL_PHYSOFTRST);
168 	WRITE4(esc, GUSB2PHYCFG(0), GUSB2PHYCFG_PHYSOFTRST);
169 
170 	DELAY(100000);
171 
172 	reg = READ4(esc, GUSB3PIPECTL(0));
173 	reg &= ~(GUSB3PIPECTL_PHYSOFTRST);
174 	WRITE4(esc, GUSB3PIPECTL(0), reg);
175 
176 	reg = READ4(esc, GUSB2PHYCFG(0));
177 	reg &= ~(GUSB2PHYCFG_PHYSOFTRST);
178 	WRITE4(esc, GUSB2PHYCFG(0), reg);
179 
180 	reg = READ4(esc, GCTL);
181 	reg &= ~GCTL_CORESOFTRESET;
182 	WRITE4(esc, GCTL, reg);
183 
184 	hwparams1 = READ4(esc, GHWPARAMS1);
185 
186 	reg = READ4(esc, GCTL);
187 	reg &= ~(GCTL_SCALEDOWN_MASK << GCTL_SCALEDOWN_SHIFT);
188 	reg &= ~(GCTL_DISSCRAMBLE);
189 
190 	if (GHWPARAMS1_EN_PWROPT(hwparams1) == \
191 	    GHWPARAMS1_EN_PWROPT_CLK)
192 		reg &= ~(GCTL_DSBLCLKGTNG);
193 
194 	if ((rev & REVISION_MASK) < 0x190a)
195 		reg |= (GCTL_U2RSTECN);
196 	WRITE4(esc, GCTL, reg);
197 
198 	/* Set host mode */
199 	reg = READ4(esc, GCTL);
200 	reg &= ~(GCTL_PRTCAPDIR(GCTL_PRTCAP_OTG));
201 	reg |= GCTL_PRTCAPDIR(GCTL_PRTCAP_HOST);
202 	WRITE4(esc, GCTL, reg);
203 
204 	return (0);
205 }
206 
207 static int
exynos_xhci_attach(device_t dev)208 exynos_xhci_attach(device_t dev)
209 {
210 	struct exynos_xhci_softc *esc = device_get_softc(dev);
211 	bus_space_handle_t bsh;
212 	int err;
213 
214 	esc->dev = dev;
215 
216 	if (bus_alloc_resources(dev, exynos_xhci_spec, esc->res)) {
217 		device_printf(dev, "could not allocate resources\n");
218 		return (ENXIO);
219 	}
220 
221 	/* XHCI registers */
222 	esc->base.sc_io_tag = rman_get_bustag(esc->res[0]);
223 	bsh = rman_get_bushandle(esc->res[0]);
224 	esc->base.sc_io_size = rman_get_size(esc->res[0]);
225 
226 	/* DWC3 ctrl registers */
227 	esc->bst = rman_get_bustag(esc->res[1]);
228 	esc->bsh = rman_get_bushandle(esc->res[1]);
229 
230 	/*
231 	 * Set handle to USB related registers subregion used by
232 	 * generic XHCI driver.
233 	 */
234 	err = bus_space_subregion(esc->base.sc_io_tag, bsh, 0x0,
235 	    esc->base.sc_io_size, &esc->base.sc_io_hdl);
236 	if (err != 0) {
237 		device_printf(dev, "Subregion failed\n");
238 		bus_release_resources(dev, exynos_xhci_spec, esc->res);
239 		return (ENXIO);
240 	}
241 
242 	if (xhci_init(&esc->base, dev, 0)) {
243 		device_printf(dev, "Could not initialize softc\n");
244 		bus_release_resources(dev, exynos_xhci_spec, esc->res);
245 		return (ENXIO);
246 	}
247 
248 	/* Setup interrupt handler */
249 	err = bus_setup_intr(dev, esc->res[2], INTR_TYPE_BIO | INTR_MPSAFE,
250 	    NULL, (driver_intr_t *)xhci_interrupt, &esc->base,
251 	    &esc->base.sc_intr_hdl);
252 	if (err) {
253 		device_printf(dev, "Could not setup irq, %d\n", err);
254 		esc->base.sc_intr_hdl = NULL;
255 		goto error;
256 	}
257 
258 	/* Add USB device */
259 	esc->base.sc_bus.bdev = device_add_child(dev, "usbus", -1);
260 	if (esc->base.sc_bus.bdev == NULL) {
261 		device_printf(dev, "Could not add USB device\n");
262 		goto error;
263 	}
264 	device_set_ivars(esc->base.sc_bus.bdev, &esc->base.sc_bus);
265 	strlcpy(esc->base.sc_vendor, "Samsung", sizeof(esc->base.sc_vendor));
266 
267 	dwc3_init(esc);
268 
269 	err = xhci_halt_controller(&esc->base);
270 	if (err == 0) {
271 		device_printf(dev, "Starting controller\n");
272 		err = xhci_start_controller(&esc->base);
273 	}
274 	if (err == 0) {
275 		device_printf(dev, "Controller started\n");
276 		err = device_probe_and_attach(esc->base.sc_bus.bdev);
277 	}
278 	if (err != 0)
279 		goto error;
280 	return (0);
281 
282 error:
283 	exynos_xhci_detach(dev);
284 	return (ENXIO);
285 }
286 
287 static int
exynos_xhci_detach(device_t dev)288 exynos_xhci_detach(device_t dev)
289 {
290 	struct exynos_xhci_softc *esc = device_get_softc(dev);
291 	int err;
292 
293 	/* During module unload there are lots of children leftover */
294 	device_delete_children(dev);
295 
296 	xhci_halt_controller(&esc->base);
297 
298 	if (esc->res[2] && esc->base.sc_intr_hdl) {
299 		err = bus_teardown_intr(dev, esc->res[2],
300 		    esc->base.sc_intr_hdl);
301 		if (err) {
302 			device_printf(dev, "Could not tear down IRQ,"
303 			    " %d\n", err);
304 			return (err);
305 		}
306 	}
307 
308 	bus_release_resources(dev, exynos_xhci_spec, esc->res);
309 
310 	xhci_uninit(&esc->base);
311 
312 	return (0);
313 }
314