xref: /freebsd/sys/dev/usb/controller/musb_otg_allwinner.c (revision 029e367dd195ad2d92af50133a31bea4035ab9ee)
1*029e367dSAndriy Gapon /*-
2*029e367dSAndriy Gapon  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3*029e367dSAndriy Gapon  * Copyright (c) 2018 Andrew Turner <andrew@FreeBSD.org>
4*029e367dSAndriy Gapon  * All rights reserved.
5*029e367dSAndriy Gapon  *
6*029e367dSAndriy Gapon  * This software was developed by SRI International and the University of
7*029e367dSAndriy Gapon  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8*029e367dSAndriy Gapon  * ("CTSRD"), as part of the DARPA CRASH research programme.
9*029e367dSAndriy Gapon  *
10*029e367dSAndriy Gapon  * Redistribution and use in source and binary forms, with or without
11*029e367dSAndriy Gapon  * modification, are permitted provided that the following conditions
12*029e367dSAndriy Gapon  * are met:
13*029e367dSAndriy Gapon  * 1. Redistributions of source code must retain the above copyright
14*029e367dSAndriy Gapon  *    notice, this list of conditions and the following disclaimer.
15*029e367dSAndriy Gapon  * 2. Redistributions in binary form must reproduce the above copyright
16*029e367dSAndriy Gapon  *    notice, this list of conditions and the following disclaimer in the
17*029e367dSAndriy Gapon  *    documentation and/or other materials provided with the distribution.
18*029e367dSAndriy Gapon  *
19*029e367dSAndriy Gapon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20*029e367dSAndriy Gapon  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*029e367dSAndriy Gapon  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*029e367dSAndriy Gapon  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23*029e367dSAndriy Gapon  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*029e367dSAndriy Gapon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*029e367dSAndriy Gapon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*029e367dSAndriy Gapon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*029e367dSAndriy Gapon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*029e367dSAndriy Gapon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*029e367dSAndriy Gapon  * SUCH DAMAGE.
30*029e367dSAndriy Gapon  *
31*029e367dSAndriy Gapon  * $FreeBSD$
32*029e367dSAndriy Gapon  */
33*029e367dSAndriy Gapon 
34*029e367dSAndriy Gapon /*
35*029e367dSAndriy Gapon  * Allwinner USB Dual-Role Device (DRD) controller
36*029e367dSAndriy Gapon  */
37*029e367dSAndriy Gapon 
38*029e367dSAndriy Gapon #include <sys/cdefs.h>
39*029e367dSAndriy Gapon __FBSDID("$FreeBSD$");
40*029e367dSAndriy Gapon 
41*029e367dSAndriy Gapon #include <sys/param.h>
42*029e367dSAndriy Gapon #include <sys/systm.h>
43*029e367dSAndriy Gapon #include <sys/bus.h>
44*029e367dSAndriy Gapon #include <sys/rman.h>
45*029e367dSAndriy Gapon #include <sys/kernel.h>
46*029e367dSAndriy Gapon #include <sys/condvar.h>
47*029e367dSAndriy Gapon #include <sys/module.h>
48*029e367dSAndriy Gapon #include <machine/bus.h>
49*029e367dSAndriy Gapon 
50*029e367dSAndriy Gapon #include <dev/ofw/ofw_bus.h>
51*029e367dSAndriy Gapon #include <dev/ofw/ofw_bus_subr.h>
52*029e367dSAndriy Gapon 
53*029e367dSAndriy Gapon #include <dev/usb/usb.h>
54*029e367dSAndriy Gapon #include <dev/usb/usbdi.h>
55*029e367dSAndriy Gapon 
56*029e367dSAndriy Gapon #include <dev/usb/usb_core.h>
57*029e367dSAndriy Gapon #include <dev/usb/usb_busdma.h>
58*029e367dSAndriy Gapon #include <dev/usb/usb_process.h>
59*029e367dSAndriy Gapon #include <dev/usb/usb_util.h>
60*029e367dSAndriy Gapon 
61*029e367dSAndriy Gapon #include <dev/usb/usb_controller.h>
62*029e367dSAndriy Gapon #include <dev/usb/usb_bus.h>
63*029e367dSAndriy Gapon #include <dev/usb/controller/musb_otg.h>
64*029e367dSAndriy Gapon 
65*029e367dSAndriy Gapon #include <dev/extres/clk/clk.h>
66*029e367dSAndriy Gapon #include <dev/extres/hwreset/hwreset.h>
67*029e367dSAndriy Gapon 
68*029e367dSAndriy Gapon #ifdef __arm__
69*029e367dSAndriy Gapon #include <arm/allwinner/aw_machdep.h>
70*029e367dSAndriy Gapon #include <arm/allwinner/a10_sramc.h>
71*029e367dSAndriy Gapon #endif
72*029e367dSAndriy Gapon 
73*029e367dSAndriy Gapon #define	DRD_EP_MAX		5
74*029e367dSAndriy Gapon 
75*029e367dSAndriy Gapon #define	MUSB2_REG_AWIN_VEND0	0x0043
76*029e367dSAndriy Gapon #define	VEND0_PIO_MODE		0
77*029e367dSAndriy Gapon 
78*029e367dSAndriy Gapon #if defined(__arm__)
79*029e367dSAndriy Gapon #define	bs_parent_space(bs)	((bs)->bs_parent)
80*029e367dSAndriy Gapon typedef bus_space_tag_t	awusb_bs_tag;
81*029e367dSAndriy Gapon #elif defined(__aarch64__)
82*029e367dSAndriy Gapon #define	bs_parent_space(bs)	(bs)
83*029e367dSAndriy Gapon typedef void *		awusb_bs_tag;
84*029e367dSAndriy Gapon #endif
85*029e367dSAndriy Gapon 
86*029e367dSAndriy Gapon #define	AWUSB_OKAY		0x01
87*029e367dSAndriy Gapon #define	AWUSB_NO_CONFDATA	0x02
88*029e367dSAndriy Gapon static struct ofw_compat_data compat_data[] = {
89*029e367dSAndriy Gapon 	{ "allwinner,sun4i-a10-musb",	AWUSB_OKAY },
90*029e367dSAndriy Gapon 	{ "allwinner,sun6i-a31-musb",	AWUSB_OKAY },
91*029e367dSAndriy Gapon 	{ "allwinner,sun8i-a33-musb",	AWUSB_OKAY | AWUSB_NO_CONFDATA },
92*029e367dSAndriy Gapon 	{ NULL,				0 }
93*029e367dSAndriy Gapon };
94*029e367dSAndriy Gapon 
95*029e367dSAndriy Gapon static const struct musb_otg_ep_cfg musbotg_ep_allwinner[] = {
96*029e367dSAndriy Gapon 	{
97*029e367dSAndriy Gapon 		.ep_end = 5,
98*029e367dSAndriy Gapon 		.ep_fifosz_shift = 9,
99*029e367dSAndriy Gapon 		.ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512,
100*029e367dSAndriy Gapon 	},
101*029e367dSAndriy Gapon 	{
102*029e367dSAndriy Gapon 		.ep_end = -1,
103*029e367dSAndriy Gapon 	},
104*029e367dSAndriy Gapon };
105*029e367dSAndriy Gapon 
106*029e367dSAndriy Gapon struct awusbdrd_softc {
107*029e367dSAndriy Gapon 	struct musbotg_softc	sc;
108*029e367dSAndriy Gapon 	struct resource		*res[2];
109*029e367dSAndriy Gapon 	clk_t			clk;
110*029e367dSAndriy Gapon 	hwreset_t		reset;
111*029e367dSAndriy Gapon 	struct bus_space	bs;
112*029e367dSAndriy Gapon 	int			flags;
113*029e367dSAndriy Gapon };
114*029e367dSAndriy Gapon 
115*029e367dSAndriy Gapon static struct resource_spec awusbdrd_spec[] = {
116*029e367dSAndriy Gapon 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
117*029e367dSAndriy Gapon 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
118*029e367dSAndriy Gapon 	{ -1, 0 }
119*029e367dSAndriy Gapon };
120*029e367dSAndriy Gapon 
121*029e367dSAndriy Gapon #define	REMAPFLAG	0x8000
122*029e367dSAndriy Gapon #define	REGDECL(a, b)	[(a)] = ((b) | REMAPFLAG)
123*029e367dSAndriy Gapon 
124*029e367dSAndriy Gapon /* Allwinner USB DRD register mappings */
125*029e367dSAndriy Gapon static const uint16_t awusbdrd_regmap[] = {
126*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(0),	0x0000),
127*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(1),	0x0004),
128*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(2),	0x0008),
129*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(3),	0x000c),
130*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(4),	0x0010),
131*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPFIFO(5),	0x0014),
132*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_POWER,	0x0040),
133*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_DEVCTL,	0x0041),
134*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_EPINDEX,	0x0042),
135*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTTX,	0x0044),
136*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTRX,	0x0046),
137*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTTXE,	0x0048),
138*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTRXE,	0x004a),
139*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTUSB,	0x004c),
140*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_INTUSBE,	0x0050),
141*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_FRAME,	0x0054),
142*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TESTMODE,	0x007c),
143*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXMAXP,	0x0080),
144*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXCSRL,	0x0082),
145*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXCSRH,	0x0083),
146*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXMAXP,	0x0084),
147*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXCSRL,	0x0086),
148*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXCSRH,	0x0087),
149*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXCOUNT,	0x0088),
150*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXTI,		0x008c),
151*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXNAKLIMIT,	0x008d),
152*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXNAKLIMIT,	0x008f),
153*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXTI,		0x008e),
154*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFIFOSZ,	0x0090),
155*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFIFOADD,	0x0092),
156*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFIFOSZ,	0x0094),
157*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFIFOADD,	0x0096),
158*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_FADDR,	0x0098),
159*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(0),	0x0098),
160*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(0),	0x009a),
161*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(0),	0x009b),
162*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(0),	0x009c),
163*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(0),	0x009e),
164*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(0),	0x009f),
165*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(1),	0x0098),
166*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(1),	0x009a),
167*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(1),	0x009b),
168*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(1),	0x009c),
169*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(1),	0x009e),
170*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(1),	0x009f),
171*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(2),	0x0098),
172*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(2),	0x009a),
173*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(2),	0x009b),
174*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(2),	0x009c),
175*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(2),	0x009e),
176*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(2),	0x009f),
177*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(3),	0x0098),
178*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(3),	0x009a),
179*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(3),	0x009b),
180*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(3),	0x009c),
181*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(3),	0x009e),
182*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(3),	0x009f),
183*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(4),	0x0098),
184*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(4),	0x009a),
185*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(4),	0x009b),
186*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(4),	0x009c),
187*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(4),	0x009e),
188*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(4),	0x009f),
189*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXFADDR(5),	0x0098),
190*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHADDR(5),	0x009a),
191*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_TXHUBPORT(5),	0x009b),
192*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXFADDR(5),	0x009c),
193*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHADDR(5),	0x009e),
194*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_RXHUBPORT(5),	0x009f),
195*029e367dSAndriy Gapon 	REGDECL(MUSB2_REG_CONFDATA,	0x00c0),
196*029e367dSAndriy Gapon };
197*029e367dSAndriy Gapon 
198*029e367dSAndriy Gapon static bus_size_t
199*029e367dSAndriy Gapon awusbdrd_reg(bus_size_t o)
200*029e367dSAndriy Gapon {
201*029e367dSAndriy Gapon 	bus_size_t v;
202*029e367dSAndriy Gapon 
203*029e367dSAndriy Gapon 	KASSERT(o < nitems(awusbdrd_regmap),
204*029e367dSAndriy Gapon 	    ("%s: Invalid register %#lx", __func__, o));
205*029e367dSAndriy Gapon 	if (o >= nitems(awusbdrd_regmap))
206*029e367dSAndriy Gapon 		return (o);
207*029e367dSAndriy Gapon 
208*029e367dSAndriy Gapon 	v = awusbdrd_regmap[o];
209*029e367dSAndriy Gapon 
210*029e367dSAndriy Gapon 	KASSERT((v & REMAPFLAG) != 0, ("%s: reg %#lx not in regmap",
211*029e367dSAndriy Gapon 	    __func__, o));
212*029e367dSAndriy Gapon 
213*029e367dSAndriy Gapon 	return (v & ~REMAPFLAG);
214*029e367dSAndriy Gapon }
215*029e367dSAndriy Gapon 
216*029e367dSAndriy Gapon static int
217*029e367dSAndriy Gapon awusbdrd_filt(bus_size_t o)
218*029e367dSAndriy Gapon {
219*029e367dSAndriy Gapon 	switch (o) {
220*029e367dSAndriy Gapon 	case MUSB2_REG_MISC:
221*029e367dSAndriy Gapon 	case MUSB2_REG_RXDBDIS:
222*029e367dSAndriy Gapon 	case MUSB2_REG_TXDBDIS:
223*029e367dSAndriy Gapon 		return (1);
224*029e367dSAndriy Gapon 	default:
225*029e367dSAndriy Gapon 		return (0);
226*029e367dSAndriy Gapon 	}
227*029e367dSAndriy Gapon }
228*029e367dSAndriy Gapon 
229*029e367dSAndriy Gapon static uint8_t
230*029e367dSAndriy Gapon awusbdrd_bs_r_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
231*029e367dSAndriy Gapon {
232*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
233*029e367dSAndriy Gapon 
234*029e367dSAndriy Gapon 	switch (o) {
235*029e367dSAndriy Gapon 	case MUSB2_REG_HWVERS:
236*029e367dSAndriy Gapon 		return (0);	/* no known equivalent */
237*029e367dSAndriy Gapon 	}
238*029e367dSAndriy Gapon 
239*029e367dSAndriy Gapon 	return (bus_space_read_1(bs_parent_space(bs), h, awusbdrd_reg(o)));
240*029e367dSAndriy Gapon }
241*029e367dSAndriy Gapon 
242*029e367dSAndriy Gapon static uint8_t
243*029e367dSAndriy Gapon awusbdrd_bs_r_1_noconf(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
244*029e367dSAndriy Gapon {
245*029e367dSAndriy Gapon 
246*029e367dSAndriy Gapon 	/*
247*029e367dSAndriy Gapon 	 * There is no confdata register on some SoCs, return the same
248*029e367dSAndriy Gapon 	 * magic value as Linux.
249*029e367dSAndriy Gapon 	 */
250*029e367dSAndriy Gapon 	if (o == MUSB2_REG_CONFDATA)
251*029e367dSAndriy Gapon 		return (0xde);
252*029e367dSAndriy Gapon 
253*029e367dSAndriy Gapon 	return (awusbdrd_bs_r_1(t, h, o));
254*029e367dSAndriy Gapon }
255*029e367dSAndriy Gapon 
256*029e367dSAndriy Gapon 
257*029e367dSAndriy Gapon static uint16_t
258*029e367dSAndriy Gapon awusbdrd_bs_r_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
259*029e367dSAndriy Gapon {
260*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
261*029e367dSAndriy Gapon 
262*029e367dSAndriy Gapon 	return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o));
263*029e367dSAndriy Gapon }
264*029e367dSAndriy Gapon 
265*029e367dSAndriy Gapon static void
266*029e367dSAndriy Gapon awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
267*029e367dSAndriy Gapon     uint8_t v)
268*029e367dSAndriy Gapon {
269*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
270*029e367dSAndriy Gapon 
271*029e367dSAndriy Gapon 	if (awusbdrd_filt(o) != 0)
272*029e367dSAndriy Gapon 		return;
273*029e367dSAndriy Gapon 
274*029e367dSAndriy Gapon 	bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v);
275*029e367dSAndriy Gapon }
276*029e367dSAndriy Gapon 
277*029e367dSAndriy Gapon static void
278*029e367dSAndriy Gapon awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
279*029e367dSAndriy Gapon     uint16_t v)
280*029e367dSAndriy Gapon {
281*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
282*029e367dSAndriy Gapon 
283*029e367dSAndriy Gapon 	if (awusbdrd_filt(o) != 0)
284*029e367dSAndriy Gapon 		return;
285*029e367dSAndriy Gapon 
286*029e367dSAndriy Gapon 	bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v);
287*029e367dSAndriy Gapon }
288*029e367dSAndriy Gapon 
289*029e367dSAndriy Gapon static void
290*029e367dSAndriy Gapon awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
291*029e367dSAndriy Gapon     uint8_t *d, bus_size_t c)
292*029e367dSAndriy Gapon {
293*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
294*029e367dSAndriy Gapon 
295*029e367dSAndriy Gapon 	bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
296*029e367dSAndriy Gapon }
297*029e367dSAndriy Gapon 
298*029e367dSAndriy Gapon static void
299*029e367dSAndriy Gapon awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
300*029e367dSAndriy Gapon     uint32_t *d, bus_size_t c)
301*029e367dSAndriy Gapon {
302*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
303*029e367dSAndriy Gapon 
304*029e367dSAndriy Gapon 	bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
305*029e367dSAndriy Gapon }
306*029e367dSAndriy Gapon 
307*029e367dSAndriy Gapon static void
308*029e367dSAndriy Gapon awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
309*029e367dSAndriy Gapon     const uint8_t *d, bus_size_t c)
310*029e367dSAndriy Gapon {
311*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
312*029e367dSAndriy Gapon 
313*029e367dSAndriy Gapon 	if (awusbdrd_filt(o) != 0)
314*029e367dSAndriy Gapon 		return;
315*029e367dSAndriy Gapon 
316*029e367dSAndriy Gapon 	bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
317*029e367dSAndriy Gapon }
318*029e367dSAndriy Gapon 
319*029e367dSAndriy Gapon static void
320*029e367dSAndriy Gapon awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
321*029e367dSAndriy Gapon     const uint32_t *d, bus_size_t c)
322*029e367dSAndriy Gapon {
323*029e367dSAndriy Gapon 	const struct bus_space *bs = t;
324*029e367dSAndriy Gapon 
325*029e367dSAndriy Gapon 	if (awusbdrd_filt(o) != 0)
326*029e367dSAndriy Gapon 		return;
327*029e367dSAndriy Gapon 
328*029e367dSAndriy Gapon 	bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
329*029e367dSAndriy Gapon }
330*029e367dSAndriy Gapon 
331*029e367dSAndriy Gapon static void
332*029e367dSAndriy Gapon awusbdrd_intr(void *arg)
333*029e367dSAndriy Gapon {
334*029e367dSAndriy Gapon 	struct awusbdrd_softc *sc = arg;
335*029e367dSAndriy Gapon 	uint8_t intusb;
336*029e367dSAndriy Gapon 	uint16_t inttx, intrx;
337*029e367dSAndriy Gapon 
338*029e367dSAndriy Gapon 	intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB);
339*029e367dSAndriy Gapon 	inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX);
340*029e367dSAndriy Gapon 	intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX);
341*029e367dSAndriy Gapon 	if (intusb == 0 && inttx == 0 && intrx == 0)
342*029e367dSAndriy Gapon 		return;
343*029e367dSAndriy Gapon 
344*029e367dSAndriy Gapon 	if (intusb)
345*029e367dSAndriy Gapon 		MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb);
346*029e367dSAndriy Gapon 	if (inttx)
347*029e367dSAndriy Gapon 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx);
348*029e367dSAndriy Gapon 	if (intrx)
349*029e367dSAndriy Gapon 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx);
350*029e367dSAndriy Gapon 
351*029e367dSAndriy Gapon 	musbotg_interrupt(arg, intrx, inttx, intusb);
352*029e367dSAndriy Gapon }
353*029e367dSAndriy Gapon 
354*029e367dSAndriy Gapon static int
355*029e367dSAndriy Gapon awusbdrd_probe(device_t dev)
356*029e367dSAndriy Gapon {
357*029e367dSAndriy Gapon 	if (!ofw_bus_status_okay(dev))
358*029e367dSAndriy Gapon 		return (ENXIO);
359*029e367dSAndriy Gapon 
360*029e367dSAndriy Gapon 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
361*029e367dSAndriy Gapon 		return (ENXIO);
362*029e367dSAndriy Gapon 
363*029e367dSAndriy Gapon 	device_set_desc(dev, "Allwinner USB DRD");
364*029e367dSAndriy Gapon 	return (BUS_PROBE_DEFAULT);
365*029e367dSAndriy Gapon }
366*029e367dSAndriy Gapon 
367*029e367dSAndriy Gapon static int
368*029e367dSAndriy Gapon awusbdrd_attach(device_t dev)
369*029e367dSAndriy Gapon {
370*029e367dSAndriy Gapon 	struct awusbdrd_softc *sc;
371*029e367dSAndriy Gapon 	int error;
372*029e367dSAndriy Gapon 
373*029e367dSAndriy Gapon 	sc = device_get_softc(dev);
374*029e367dSAndriy Gapon 	sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
375*029e367dSAndriy Gapon 
376*029e367dSAndriy Gapon 	error = bus_alloc_resources(dev, awusbdrd_spec, sc->res);
377*029e367dSAndriy Gapon 	if (error != 0)
378*029e367dSAndriy Gapon 		return (error);
379*029e367dSAndriy Gapon 
380*029e367dSAndriy Gapon 	/* AHB gate clock is required */
381*029e367dSAndriy Gapon 	error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
382*029e367dSAndriy Gapon 	if (error != 0)
383*029e367dSAndriy Gapon 		goto fail;
384*029e367dSAndriy Gapon 
385*029e367dSAndriy Gapon 	/* AHB reset is only present on some SoCs */
386*029e367dSAndriy Gapon 	(void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset);
387*029e367dSAndriy Gapon 
388*029e367dSAndriy Gapon 	/* Enable clocks */
389*029e367dSAndriy Gapon 	error = clk_enable(sc->clk);
390*029e367dSAndriy Gapon 	if (error != 0) {
391*029e367dSAndriy Gapon 		device_printf(dev, "failed to enable clock: %d\n", error);
392*029e367dSAndriy Gapon 		goto fail;
393*029e367dSAndriy Gapon 	}
394*029e367dSAndriy Gapon 	if (sc->reset != NULL) {
395*029e367dSAndriy Gapon 		error = hwreset_deassert(sc->reset);
396*029e367dSAndriy Gapon 		if (error != 0) {
397*029e367dSAndriy Gapon 			device_printf(dev, "failed to de-assert reset: %d\n",
398*029e367dSAndriy Gapon 			    error);
399*029e367dSAndriy Gapon 			goto fail;
400*029e367dSAndriy Gapon 		}
401*029e367dSAndriy Gapon 	}
402*029e367dSAndriy Gapon 
403*029e367dSAndriy Gapon 	sc->sc.sc_bus.parent = dev;
404*029e367dSAndriy Gapon 	sc->sc.sc_bus.devices = sc->sc.sc_devices;
405*029e367dSAndriy Gapon 	sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES;
406*029e367dSAndriy Gapon 	sc->sc.sc_bus.dma_bits = 32;
407*029e367dSAndriy Gapon 
408*029e367dSAndriy Gapon 	error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev),
409*029e367dSAndriy Gapon 	    NULL);
410*029e367dSAndriy Gapon 	if (error != 0) {
411*029e367dSAndriy Gapon 		error = ENOMEM;
412*029e367dSAndriy Gapon 		goto fail;
413*029e367dSAndriy Gapon 	}
414*029e367dSAndriy Gapon 
415*029e367dSAndriy Gapon #if defined(__arm__)
416*029e367dSAndriy Gapon 	sc->bs.bs_parent = rman_get_bustag(sc->res[0]);
417*029e367dSAndriy Gapon #elif defined(__aarch64__)
418*029e367dSAndriy Gapon 	sc->bs.bs_cookie = rman_get_bustag(sc->res[0]);
419*029e367dSAndriy Gapon #endif
420*029e367dSAndriy Gapon 
421*029e367dSAndriy Gapon 	if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA)
422*029e367dSAndriy Gapon 		sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf;
423*029e367dSAndriy Gapon 	else
424*029e367dSAndriy Gapon 		sc->bs.bs_r_1 = awusbdrd_bs_r_1;
425*029e367dSAndriy Gapon 	sc->bs.bs_r_2 = awusbdrd_bs_r_2;
426*029e367dSAndriy Gapon 	sc->bs.bs_w_1 = awusbdrd_bs_w_1;
427*029e367dSAndriy Gapon 	sc->bs.bs_w_2 = awusbdrd_bs_w_2;
428*029e367dSAndriy Gapon 	sc->bs.bs_rm_1 = awusbdrd_bs_rm_1;
429*029e367dSAndriy Gapon 	sc->bs.bs_rm_4 = awusbdrd_bs_rm_4;
430*029e367dSAndriy Gapon 	sc->bs.bs_wm_1 = awusbdrd_bs_wm_1;
431*029e367dSAndriy Gapon 	sc->bs.bs_wm_4 = awusbdrd_bs_wm_4;
432*029e367dSAndriy Gapon 
433*029e367dSAndriy Gapon 	sc->sc.sc_io_tag = &sc->bs;
434*029e367dSAndriy Gapon 	sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]);
435*029e367dSAndriy Gapon 	sc->sc.sc_io_size = rman_get_size(sc->res[0]);
436*029e367dSAndriy Gapon 
437*029e367dSAndriy Gapon 	sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
438*029e367dSAndriy Gapon 	if (sc->sc.sc_bus.bdev == NULL) {
439*029e367dSAndriy Gapon 		error = ENXIO;
440*029e367dSAndriy Gapon 		goto fail;
441*029e367dSAndriy Gapon 	}
442*029e367dSAndriy Gapon 	device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus);
443*029e367dSAndriy Gapon 	sc->sc.sc_id = 0;
444*029e367dSAndriy Gapon 	sc->sc.sc_platform_data = sc;
445*029e367dSAndriy Gapon 	sc->sc.sc_mode = MUSB2_HOST_MODE;	/* XXX HOST vs DEVICE mode */
446*029e367dSAndriy Gapon 	sc->sc.sc_ep_max = DRD_EP_MAX;
447*029e367dSAndriy Gapon 	sc->sc.sc_ep_cfg = musbotg_ep_allwinner;
448*029e367dSAndriy Gapon 
449*029e367dSAndriy Gapon 	error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO,
450*029e367dSAndriy Gapon 	    NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl);
451*029e367dSAndriy Gapon 	if (error != 0)
452*029e367dSAndriy Gapon 		goto fail;
453*029e367dSAndriy Gapon 
454*029e367dSAndriy Gapon 	/* Enable PIO mode */
455*029e367dSAndriy Gapon 	bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE);
456*029e367dSAndriy Gapon 
457*029e367dSAndriy Gapon #ifdef __arm__
458*029e367dSAndriy Gapon 	/* Map SRAMD area to USB0 (sun4i/sun7i only) */
459*029e367dSAndriy Gapon 	switch (allwinner_soc_family()) {
460*029e367dSAndriy Gapon 	case ALLWINNERSOC_SUN4I:
461*029e367dSAndriy Gapon 	case ALLWINNERSOC_SUN7I:
462*029e367dSAndriy Gapon 		a10_map_to_otg();
463*029e367dSAndriy Gapon 		break;
464*029e367dSAndriy Gapon 	}
465*029e367dSAndriy Gapon #endif
466*029e367dSAndriy Gapon 
467*029e367dSAndriy Gapon 	error = musbotg_init(&sc->sc);
468*029e367dSAndriy Gapon 	if (error != 0)
469*029e367dSAndriy Gapon 		goto fail;
470*029e367dSAndriy Gapon 
471*029e367dSAndriy Gapon 	error = device_probe_and_attach(sc->sc.sc_bus.bdev);
472*029e367dSAndriy Gapon 	if (error != 0)
473*029e367dSAndriy Gapon 		goto fail;
474*029e367dSAndriy Gapon 
475*029e367dSAndriy Gapon 	musbotg_vbus_interrupt(&sc->sc, 1);	/* XXX VBUS */
476*029e367dSAndriy Gapon 
477*029e367dSAndriy Gapon 	return (0);
478*029e367dSAndriy Gapon 
479*029e367dSAndriy Gapon fail:
480*029e367dSAndriy Gapon 	if (sc->reset != NULL)
481*029e367dSAndriy Gapon 		hwreset_release(sc->reset);
482*029e367dSAndriy Gapon 	if (sc->clk != NULL)
483*029e367dSAndriy Gapon 		clk_release(sc->clk);
484*029e367dSAndriy Gapon 	bus_release_resources(dev, awusbdrd_spec, sc->res);
485*029e367dSAndriy Gapon 	return (error);
486*029e367dSAndriy Gapon }
487*029e367dSAndriy Gapon 
488*029e367dSAndriy Gapon static int
489*029e367dSAndriy Gapon awusbdrd_detach(device_t dev)
490*029e367dSAndriy Gapon {
491*029e367dSAndriy Gapon 	struct awusbdrd_softc *sc;
492*029e367dSAndriy Gapon 	device_t bdev;
493*029e367dSAndriy Gapon 	int error;
494*029e367dSAndriy Gapon 
495*029e367dSAndriy Gapon 	sc = device_get_softc(dev);
496*029e367dSAndriy Gapon 
497*029e367dSAndriy Gapon 	if (sc->sc.sc_bus.bdev != NULL) {
498*029e367dSAndriy Gapon 		bdev = sc->sc.sc_bus.bdev;
499*029e367dSAndriy Gapon 		device_detach(bdev);
500*029e367dSAndriy Gapon 		device_delete_child(dev, bdev);
501*029e367dSAndriy Gapon 	}
502*029e367dSAndriy Gapon 
503*029e367dSAndriy Gapon 	musbotg_uninit(&sc->sc);
504*029e367dSAndriy Gapon 	error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl);
505*029e367dSAndriy Gapon 	if (error != 0)
506*029e367dSAndriy Gapon 		return (error);
507*029e367dSAndriy Gapon 
508*029e367dSAndriy Gapon 	usb_bus_mem_free_all(&sc->sc.sc_bus, NULL);
509*029e367dSAndriy Gapon 
510*029e367dSAndriy Gapon 	if (sc->reset != NULL)
511*029e367dSAndriy Gapon 		hwreset_release(sc->reset);
512*029e367dSAndriy Gapon 	if (sc->clk != NULL)
513*029e367dSAndriy Gapon 		clk_release(sc->clk);
514*029e367dSAndriy Gapon 
515*029e367dSAndriy Gapon 	bus_release_resources(dev, awusbdrd_spec, sc->res);
516*029e367dSAndriy Gapon 
517*029e367dSAndriy Gapon 	device_delete_children(dev);
518*029e367dSAndriy Gapon 
519*029e367dSAndriy Gapon 	return (0);
520*029e367dSAndriy Gapon }
521*029e367dSAndriy Gapon 
522*029e367dSAndriy Gapon static device_method_t awusbdrd_methods[] = {
523*029e367dSAndriy Gapon 	/* Device interface */
524*029e367dSAndriy Gapon 	DEVMETHOD(device_probe,		awusbdrd_probe),
525*029e367dSAndriy Gapon 	DEVMETHOD(device_attach,	awusbdrd_attach),
526*029e367dSAndriy Gapon 	DEVMETHOD(device_detach,	awusbdrd_detach),
527*029e367dSAndriy Gapon 	DEVMETHOD(device_suspend,	bus_generic_suspend),
528*029e367dSAndriy Gapon 	DEVMETHOD(device_resume,	bus_generic_resume),
529*029e367dSAndriy Gapon 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
530*029e367dSAndriy Gapon 
531*029e367dSAndriy Gapon 	DEVMETHOD_END
532*029e367dSAndriy Gapon };
533*029e367dSAndriy Gapon 
534*029e367dSAndriy Gapon static driver_t awusbdrd_driver = {
535*029e367dSAndriy Gapon 	.name = "musbotg",
536*029e367dSAndriy Gapon 	.methods = awusbdrd_methods,
537*029e367dSAndriy Gapon 	.size = sizeof(struct awusbdrd_softc),
538*029e367dSAndriy Gapon };
539*029e367dSAndriy Gapon 
540*029e367dSAndriy Gapon static devclass_t awusbdrd_devclass;
541*029e367dSAndriy Gapon 
542*029e367dSAndriy Gapon DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, awusbdrd_devclass, 0, 0);
543*029e367dSAndriy Gapon MODULE_DEPEND(musbotg, usb, 1, 1, 1);
544