1*6e54367aSthorpej /* $NetBSD: sunxi_musb.c,v 1.10 2021/01/27 03:10:20 thorpej Exp $ */
297a2d7bdSjmcneill
397a2d7bdSjmcneill /*-
497a2d7bdSjmcneill * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
597a2d7bdSjmcneill * All rights reserved.
697a2d7bdSjmcneill *
797a2d7bdSjmcneill * Redistribution and use in source and binary forms, with or without
897a2d7bdSjmcneill * modification, are permitted provided that the following conditions
997a2d7bdSjmcneill * are met:
1097a2d7bdSjmcneill * 1. Redistributions of source code must retain the above copyright
1197a2d7bdSjmcneill * notice, this list of conditions and the following disclaimer.
1297a2d7bdSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
1397a2d7bdSjmcneill * notice, this list of conditions and the following disclaimer in the
1497a2d7bdSjmcneill * documentation and/or other materials provided with the distribution.
1597a2d7bdSjmcneill *
1697a2d7bdSjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1797a2d7bdSjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1897a2d7bdSjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1997a2d7bdSjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2097a2d7bdSjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2197a2d7bdSjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2297a2d7bdSjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2397a2d7bdSjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2497a2d7bdSjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2597a2d7bdSjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2697a2d7bdSjmcneill * SUCH DAMAGE.
2797a2d7bdSjmcneill */
2897a2d7bdSjmcneill
2997a2d7bdSjmcneill #include <sys/cdefs.h>
30*6e54367aSthorpej __KERNEL_RCSID(0, "$NetBSD: sunxi_musb.c,v 1.10 2021/01/27 03:10:20 thorpej Exp $");
3197a2d7bdSjmcneill
3297a2d7bdSjmcneill #include <sys/param.h>
3397a2d7bdSjmcneill #include <sys/bus.h>
3497a2d7bdSjmcneill #include <sys/device.h>
3597a2d7bdSjmcneill #include <sys/intr.h>
3697a2d7bdSjmcneill #include <sys/systm.h>
3797a2d7bdSjmcneill #include <sys/kernel.h>
3897a2d7bdSjmcneill #include <sys/pool.h>
3997a2d7bdSjmcneill
4097a2d7bdSjmcneill #include <dev/usb/usb.h>
4197a2d7bdSjmcneill #include <dev/usb/usbdi.h>
4297a2d7bdSjmcneill #include <dev/usb/usbdivar.h>
4397a2d7bdSjmcneill #include <dev/usb/motgvar.h>
44cb3c403dSjmcneill #include <dev/usb/motgreg.h>
4597a2d7bdSjmcneill
4697a2d7bdSjmcneill #include <dev/fdt/fdtvar.h>
4797a2d7bdSjmcneill
48cb3c403dSjmcneill #include <machine/bus_defs.h>
49cb3c403dSjmcneill
5097a2d7bdSjmcneill #define MUSB2_REG_AWIN_VEND0 0x43
5197a2d7bdSjmcneill
5297a2d7bdSjmcneill static int sunxi_musb_match(device_t, cfdata_t, void *);
5397a2d7bdSjmcneill static void sunxi_musb_attach(device_t, device_t, void *);
5497a2d7bdSjmcneill
55cb3c403dSjmcneill struct sunxi_musb_softc {
56cb3c403dSjmcneill struct motg_softc sc_otg;
57cb3c403dSjmcneill struct bus_space sc_bs;
58cb3c403dSjmcneill };
59cb3c403dSjmcneill
60cb3c403dSjmcneill CFATTACH_DECL_NEW(sunxi_musb, sizeof(struct sunxi_musb_softc),
6197a2d7bdSjmcneill sunxi_musb_match, sunxi_musb_attach, NULL, NULL);
6297a2d7bdSjmcneill
63646c0f59Sthorpej static const struct device_compatible_entry compat_data[] = {
64646c0f59Sthorpej { .compat = "allwinner,sun4i-a10-musb", .value = 5 },
65646c0f59Sthorpej { .compat = "allwinner,sun6i-a13-musb", .value = 5 },
66646c0f59Sthorpej { .compat = "allwinner,sun8i-h3-musb", .value = 4 },
67646c0f59Sthorpej { .compat = "allwinner,sun8i-a33-musb", .value = 5 },
68ec189949Sthorpej DEVICE_COMPAT_EOL
6997a2d7bdSjmcneill };
7097a2d7bdSjmcneill
71cb3c403dSjmcneill #define REMAPFLAG 0x8000
72cb3c403dSjmcneill #define REGDECL(a, b) [(a)] = ((b) | REMAPFLAG)
73cb3c403dSjmcneill
74cb3c403dSjmcneill /* Allwinner USB DRD register mappings */
75cb3c403dSjmcneill static const uint16_t sunxi_musb_regmap[] = {
76cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(0), 0x0000),
77cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(1), 0x0004),
78cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(2), 0x0008),
79cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(3), 0x000c),
80cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(4), 0x0010),
81cb3c403dSjmcneill REGDECL(MUSB2_REG_EPFIFO(5), 0x0014),
82cb3c403dSjmcneill REGDECL(MUSB2_REG_POWER, 0x0040),
83cb3c403dSjmcneill REGDECL(MUSB2_REG_DEVCTL, 0x0041),
84cb3c403dSjmcneill REGDECL(MUSB2_REG_EPINDEX, 0x0042),
85cb3c403dSjmcneill REGDECL(MUSB2_REG_AWIN_VEND0, 0x0043),
86cb3c403dSjmcneill REGDECL(MUSB2_REG_INTTX, 0x0044),
87cb3c403dSjmcneill REGDECL(MUSB2_REG_INTRX, 0x0046),
88cb3c403dSjmcneill REGDECL(MUSB2_REG_INTTXE, 0x0048),
89cb3c403dSjmcneill REGDECL(MUSB2_REG_INTRXE, 0x004a),
90cb3c403dSjmcneill REGDECL(MUSB2_REG_INTUSB, 0x004c),
91cb3c403dSjmcneill REGDECL(MUSB2_REG_INTUSBE, 0x0050),
92cb3c403dSjmcneill REGDECL(MUSB2_REG_FRAME, 0x0054),
93cb3c403dSjmcneill REGDECL(MUSB2_REG_TESTMODE, 0x007c),
94cb3c403dSjmcneill REGDECL(MUSB2_REG_TXMAXP, 0x0080),
95cb3c403dSjmcneill REGDECL(MUSB2_REG_TXCSRL, 0x0082),
96cb3c403dSjmcneill REGDECL(MUSB2_REG_TXCSRH, 0x0083),
97cb3c403dSjmcneill REGDECL(MUSB2_REG_RXMAXP, 0x0084),
98cb3c403dSjmcneill REGDECL(MUSB2_REG_RXCSRL, 0x0086),
99cb3c403dSjmcneill REGDECL(MUSB2_REG_RXCSRH, 0x0087),
100cb3c403dSjmcneill REGDECL(MUSB2_REG_RXCOUNT, 0x0088),
101cb3c403dSjmcneill REGDECL(MUSB2_REG_TXTI, 0x008c),
102cb3c403dSjmcneill REGDECL(MUSB2_REG_TXNAKLIMIT, 0x008d),
103cb3c403dSjmcneill REGDECL(MUSB2_REG_RXNAKLIMIT, 0x008d),
104cb3c403dSjmcneill REGDECL(MUSB2_REG_RXTI, 0x008e),
105cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFIFOSZ, 0x0090),
106cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFIFOADD, 0x0092),
107cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFIFOSZ, 0x0094),
108cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFIFOADD, 0x0096),
109cb3c403dSjmcneill REGDECL(MUSB2_REG_FADDR, 0x0098),
110cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(0), 0x0098),
111cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(0), 0x009a),
112cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(0), 0x009b),
113cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(0), 0x009c),
114cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(0), 0x009e),
115cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(0), 0x009f),
116cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(1), 0x0098),
117cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(1), 0x009a),
118cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(1), 0x009b),
119cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(1), 0x009c),
120cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(1), 0x009e),
121cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(1), 0x009f),
122cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(2), 0x0098),
123cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(2), 0x009a),
124cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(2), 0x009b),
125cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(2), 0x009c),
126cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(2), 0x009e),
127cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(2), 0x009f),
128cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(3), 0x0098),
129cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(3), 0x009a),
130cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(3), 0x009b),
131cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(3), 0x009c),
132cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(3), 0x009e),
133cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(3), 0x009f),
134cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(4), 0x0098),
135cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(4), 0x009a),
136cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(4), 0x009b),
137cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(4), 0x009c),
138cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(4), 0x009e),
139cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(4), 0x009f),
140cb3c403dSjmcneill REGDECL(MUSB2_REG_TXFADDR(5), 0x0098),
141cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHADDR(5), 0x009a),
142cb3c403dSjmcneill REGDECL(MUSB2_REG_TXHUBPORT(5), 0x009b),
143cb3c403dSjmcneill REGDECL(MUSB2_REG_RXFADDR(5), 0x009c),
144cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHADDR(5), 0x009e),
145cb3c403dSjmcneill REGDECL(MUSB2_REG_RXHUBPORT(5), 0x009f),
146cb3c403dSjmcneill REGDECL(MUSB2_REG_CONFDATA, 0x00c0),
147cb3c403dSjmcneill };
148cb3c403dSjmcneill
149cb3c403dSjmcneill static bus_size_t
sunxi_musb_reg(bus_size_t o)150cb3c403dSjmcneill sunxi_musb_reg(bus_size_t o)
151cb3c403dSjmcneill {
152cb3c403dSjmcneill bus_size_t v;
153cb3c403dSjmcneill
154cb3c403dSjmcneill if (o >= __arraycount(sunxi_musb_regmap))
155cb3c403dSjmcneill return o;
156cb3c403dSjmcneill
157cb3c403dSjmcneill v = sunxi_musb_regmap[o];
158cb3c403dSjmcneill KASSERTMSG((v & REMAPFLAG) != 0, "%s: reg %#lx not in regmap",
159cb3c403dSjmcneill __func__, o);
160cb3c403dSjmcneill
161cb3c403dSjmcneill return v & ~REMAPFLAG;
162cb3c403dSjmcneill }
163cb3c403dSjmcneill
164cb3c403dSjmcneill static int
sunxi_musb_filt(bus_size_t o)165cb3c403dSjmcneill sunxi_musb_filt(bus_size_t o)
166cb3c403dSjmcneill {
167cb3c403dSjmcneill switch (o) {
168cb3c403dSjmcneill case MUSB2_REG_MISC:
169cb3c403dSjmcneill case MUSB2_REG_RXDBDIS:
170cb3c403dSjmcneill case MUSB2_REG_TXDBDIS:
171cb3c403dSjmcneill return 1;
172cb3c403dSjmcneill default:
173cb3c403dSjmcneill return 0;
174cb3c403dSjmcneill }
175cb3c403dSjmcneill }
176cb3c403dSjmcneill
177cb3c403dSjmcneill static uint8_t
sunxi_musb_bs_r_1(void * t,bus_space_handle_t h,bus_size_t o)178cb3c403dSjmcneill sunxi_musb_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
179cb3c403dSjmcneill {
180cb3c403dSjmcneill switch (o) {
181cb3c403dSjmcneill case MUSB2_REG_HWVERS:
182cb3c403dSjmcneill return 0; /* no known equivalent */
183cb3c403dSjmcneill }
184cb3c403dSjmcneill
1859876db7aSjmcneill return bus_space_read_1((bus_space_tag_t)t, h, sunxi_musb_reg(o));
186cb3c403dSjmcneill }
187cb3c403dSjmcneill
188cb3c403dSjmcneill static uint16_t
sunxi_musb_bs_r_2(void * t,bus_space_handle_t h,bus_size_t o)189cb3c403dSjmcneill sunxi_musb_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
190cb3c403dSjmcneill {
1919876db7aSjmcneill return bus_space_read_2((bus_space_tag_t)t, h, sunxi_musb_reg(o));
192cb3c403dSjmcneill }
193cb3c403dSjmcneill
194cb3c403dSjmcneill static void
sunxi_musb_bs_w_1(void * t,bus_space_handle_t h,bus_size_t o,uint8_t v)195cb3c403dSjmcneill sunxi_musb_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o,
196cb3c403dSjmcneill uint8_t v)
197cb3c403dSjmcneill {
198cb3c403dSjmcneill if (sunxi_musb_filt(o) != 0)
199cb3c403dSjmcneill return;
200cb3c403dSjmcneill
2019876db7aSjmcneill bus_space_write_1((bus_space_tag_t)t, h, sunxi_musb_reg(o), v);
202cb3c403dSjmcneill }
203cb3c403dSjmcneill
204cb3c403dSjmcneill static void
sunxi_musb_bs_w_2(void * t,bus_space_handle_t h,bus_size_t o,uint16_t v)205cb3c403dSjmcneill sunxi_musb_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o,
206cb3c403dSjmcneill uint16_t v)
207cb3c403dSjmcneill {
208cb3c403dSjmcneill if (sunxi_musb_filt(o) != 0)
209cb3c403dSjmcneill return;
210cb3c403dSjmcneill
2119876db7aSjmcneill bus_space_write_2((bus_space_tag_t)t, h, sunxi_musb_reg(o), v);
212cb3c403dSjmcneill }
213cb3c403dSjmcneill
214cb3c403dSjmcneill static void
sunxi_musb_bs_rm_1(void * t,bus_space_handle_t h,bus_size_t o,uint8_t * d,bus_size_t c)215cb3c403dSjmcneill sunxi_musb_bs_rm_1(void *t, bus_space_handle_t h, bus_size_t o,
216cb3c403dSjmcneill uint8_t *d, bus_size_t c)
217cb3c403dSjmcneill {
2189876db7aSjmcneill bus_space_read_multi_1((bus_space_tag_t)t, h, sunxi_musb_reg(o), d, c);
219cb3c403dSjmcneill }
220cb3c403dSjmcneill
221cb3c403dSjmcneill static void
sunxi_musb_bs_rm_4(void * t,bus_space_handle_t h,bus_size_t o,uint32_t * d,bus_size_t c)222cb3c403dSjmcneill sunxi_musb_bs_rm_4(void *t, bus_space_handle_t h, bus_size_t o,
223cb3c403dSjmcneill uint32_t *d, bus_size_t c)
224cb3c403dSjmcneill {
2259876db7aSjmcneill bus_space_read_multi_4((bus_space_tag_t)t, h, sunxi_musb_reg(o), d, c);
226cb3c403dSjmcneill }
227cb3c403dSjmcneill
228cb3c403dSjmcneill static void
sunxi_musb_bs_wm_1(void * t,bus_space_handle_t h,bus_size_t o,const uint8_t * d,bus_size_t c)229cb3c403dSjmcneill sunxi_musb_bs_wm_1(void *t, bus_space_handle_t h, bus_size_t o,
230cb3c403dSjmcneill const uint8_t *d, bus_size_t c)
231cb3c403dSjmcneill {
232cb3c403dSjmcneill if (sunxi_musb_filt(o) != 0)
233cb3c403dSjmcneill return;
234cb3c403dSjmcneill
2359876db7aSjmcneill bus_space_write_multi_1((bus_space_tag_t)t, h, sunxi_musb_reg(o), d, c);
236cb3c403dSjmcneill }
237cb3c403dSjmcneill
238cb3c403dSjmcneill static void
sunxi_musb_bs_wm_4(void * t,bus_space_handle_t h,bus_size_t o,const uint32_t * d,bus_size_t c)239cb3c403dSjmcneill sunxi_musb_bs_wm_4(void *t, bus_space_handle_t h, bus_size_t o,
240cb3c403dSjmcneill const uint32_t *d, bus_size_t c)
241cb3c403dSjmcneill {
242cb3c403dSjmcneill if (sunxi_musb_filt(o) != 0)
243cb3c403dSjmcneill return;
244cb3c403dSjmcneill
2459876db7aSjmcneill bus_space_write_multi_4((bus_space_tag_t)t, h, sunxi_musb_reg(o), d, c);
246cb3c403dSjmcneill }
247cb3c403dSjmcneill
248cb3c403dSjmcneill static void
sunxi_musb_bs_barrier(void * t,bus_space_handle_t h,bus_size_t o,bus_size_t l,int f)249cb3c403dSjmcneill sunxi_musb_bs_barrier(void *t, bus_space_handle_t h, bus_size_t o,
250cb3c403dSjmcneill bus_size_t l, int f)
251cb3c403dSjmcneill {
2529876db7aSjmcneill bus_space_barrier((bus_space_tag_t)t, h, o, l, f);
253cb3c403dSjmcneill }
254cb3c403dSjmcneill
25597a2d7bdSjmcneill static int
sunxi_musb_intr(void * priv)25697a2d7bdSjmcneill sunxi_musb_intr(void *priv)
25797a2d7bdSjmcneill {
25897a2d7bdSjmcneill struct motg_softc * const sc = priv;
25997a2d7bdSjmcneill uint16_t inttx, intrx;
26097a2d7bdSjmcneill uint8_t intusb;
26197a2d7bdSjmcneill
26297a2d7bdSjmcneill mutex_enter(&sc->sc_intr_lock);
26397a2d7bdSjmcneill
26497a2d7bdSjmcneill intusb = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTUSB);
26597a2d7bdSjmcneill inttx = bus_space_read_2(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTTX);
26697a2d7bdSjmcneill intrx = bus_space_read_2(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTRX);
26797a2d7bdSjmcneill if (!intusb && !inttx && !intrx) {
26897a2d7bdSjmcneill mutex_exit(&sc->sc_intr_lock);
26997a2d7bdSjmcneill return 0;
27097a2d7bdSjmcneill }
27197a2d7bdSjmcneill
27297a2d7bdSjmcneill if (intusb)
27397a2d7bdSjmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTUSB, intusb);
27497a2d7bdSjmcneill if (inttx)
27597a2d7bdSjmcneill bus_space_write_2(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTTX, inttx);
27697a2d7bdSjmcneill if (intrx)
27797a2d7bdSjmcneill bus_space_write_2(sc->sc_iot, sc->sc_ioh, MUSB2_REG_INTRX, intrx);
27897a2d7bdSjmcneill
27997a2d7bdSjmcneill motg_intr(sc, intrx, inttx, intusb);
28097a2d7bdSjmcneill
28197a2d7bdSjmcneill mutex_exit(&sc->sc_intr_lock);
28297a2d7bdSjmcneill
28397a2d7bdSjmcneill return 1;
28497a2d7bdSjmcneill }
28597a2d7bdSjmcneill
28697a2d7bdSjmcneill static void
sunxi_musb_poll(void * priv)28797a2d7bdSjmcneill sunxi_musb_poll(void *priv)
28897a2d7bdSjmcneill {
28997a2d7bdSjmcneill sunxi_musb_intr(priv);
29097a2d7bdSjmcneill }
29197a2d7bdSjmcneill
29297a2d7bdSjmcneill static int
sunxi_musb_match(device_t parent,cfdata_t cf,void * aux)29397a2d7bdSjmcneill sunxi_musb_match(device_t parent, cfdata_t cf, void *aux)
29497a2d7bdSjmcneill {
29597a2d7bdSjmcneill struct fdt_attach_args * const faa = aux;
29697a2d7bdSjmcneill
297*6e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
29897a2d7bdSjmcneill }
29997a2d7bdSjmcneill
30097a2d7bdSjmcneill static void
sunxi_musb_attach(device_t parent,device_t self,void * aux)30197a2d7bdSjmcneill sunxi_musb_attach(device_t parent, device_t self, void *aux)
30297a2d7bdSjmcneill {
303cb3c403dSjmcneill struct sunxi_musb_softc * const msc = device_private(self);
304cb3c403dSjmcneill struct motg_softc * const sc = &msc->sc_otg;
30597a2d7bdSjmcneill struct fdt_attach_args * const faa = aux;
30697a2d7bdSjmcneill const int phandle = faa->faa_phandle;
30797a2d7bdSjmcneill struct fdtbus_reset *rst;
30897a2d7bdSjmcneill struct fdtbus_phy *phy;
30997a2d7bdSjmcneill struct clk *clk;
31097a2d7bdSjmcneill char intrstr[128];
31197a2d7bdSjmcneill const char *dr_mode;
31297a2d7bdSjmcneill bus_addr_t addr;
31397a2d7bdSjmcneill bus_size_t size;
31497a2d7bdSjmcneill void *ih;
31597a2d7bdSjmcneill u_int n;
31697a2d7bdSjmcneill
31797a2d7bdSjmcneill /* Only "host" mode is supported */
31897a2d7bdSjmcneill dr_mode = fdtbus_get_string(phandle, "dr_mode");
31997a2d7bdSjmcneill if (dr_mode == NULL || strcmp(dr_mode, "host") != 0) {
32097a2d7bdSjmcneill aprint_normal(": '%s' mode not supported\n", dr_mode);
32197a2d7bdSjmcneill return;
32297a2d7bdSjmcneill }
32397a2d7bdSjmcneill
32497a2d7bdSjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
32597a2d7bdSjmcneill aprint_error(": couldn't get registers\n");
32697a2d7bdSjmcneill return;
32797a2d7bdSjmcneill }
32897a2d7bdSjmcneill
32997a2d7bdSjmcneill /* Enable clocks */
33097a2d7bdSjmcneill for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++)
33197a2d7bdSjmcneill if (clk_enable(clk) != 0) {
33297a2d7bdSjmcneill aprint_error(": couldn't enable clock #%d\n", n);
33397a2d7bdSjmcneill return;
33497a2d7bdSjmcneill }
33597a2d7bdSjmcneill /* De-assert resets */
33697a2d7bdSjmcneill for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++)
33797a2d7bdSjmcneill if (fdtbus_reset_deassert(rst) != 0) {
33897a2d7bdSjmcneill aprint_error(": couldn't de-assert reset #%d\n", n);
33997a2d7bdSjmcneill return;
34097a2d7bdSjmcneill }
34197a2d7bdSjmcneill
34297a2d7bdSjmcneill /* Enable optional phy */
34397a2d7bdSjmcneill phy = fdtbus_phy_get(phandle, "usb");
34497a2d7bdSjmcneill if (phy && fdtbus_phy_enable(phy, true) != 0) {
34597a2d7bdSjmcneill aprint_error(": couldn't enable phy\n");
34697a2d7bdSjmcneill return;
34797a2d7bdSjmcneill }
34897a2d7bdSjmcneill
349cb3c403dSjmcneill /* Create custom bus space tag for remapping registers */
350cb3c403dSjmcneill msc->sc_bs.bs_cookie = faa->faa_bst;
351cb3c403dSjmcneill msc->sc_bs.bs_r_1 = sunxi_musb_bs_r_1;
352cb3c403dSjmcneill msc->sc_bs.bs_r_2 = sunxi_musb_bs_r_2;
353cb3c403dSjmcneill msc->sc_bs.bs_w_1 = sunxi_musb_bs_w_1;
354cb3c403dSjmcneill msc->sc_bs.bs_w_2 = sunxi_musb_bs_w_2;
355cb3c403dSjmcneill msc->sc_bs.bs_rm_1 = sunxi_musb_bs_rm_1;
356cb3c403dSjmcneill msc->sc_bs.bs_rm_4 = sunxi_musb_bs_rm_4;
357cb3c403dSjmcneill msc->sc_bs.bs_wm_1 = sunxi_musb_bs_wm_1;
358cb3c403dSjmcneill msc->sc_bs.bs_wm_4 = sunxi_musb_bs_wm_4;
359cb3c403dSjmcneill msc->sc_bs.bs_barrier = sunxi_musb_bs_barrier;
360cb3c403dSjmcneill
36197a2d7bdSjmcneill sc->sc_dev = self;
36297a2d7bdSjmcneill sc->sc_bus.ub_hcpriv = sc;
36397a2d7bdSjmcneill sc->sc_bus.ub_dmatag = faa->faa_dmat;
36497a2d7bdSjmcneill sc->sc_size = size;
365cb3c403dSjmcneill sc->sc_iot = &msc->sc_bs;
366cb3c403dSjmcneill if (bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_ioh) != 0) {
36797a2d7bdSjmcneill aprint_error(": couldn't map registers\n");
36897a2d7bdSjmcneill return;
36997a2d7bdSjmcneill }
37097a2d7bdSjmcneill sc->sc_intr_poll = sunxi_musb_poll;
37197a2d7bdSjmcneill sc->sc_intr_poll_arg = sc;
37297a2d7bdSjmcneill sc->sc_mode = MOTG_MODE_HOST;
373*6e54367aSthorpej sc->sc_ep_max = of_compatible_lookup(phandle, compat_data)->value;
37497a2d7bdSjmcneill sc->sc_ep_fifosize = 512;
37597a2d7bdSjmcneill
37697a2d7bdSjmcneill aprint_naive("\n");
37797a2d7bdSjmcneill aprint_normal(": USB OTG\n");
37897a2d7bdSjmcneill
37997a2d7bdSjmcneill if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
38097a2d7bdSjmcneill aprint_error_dev(self, "failed to decode interrupt\n");
38197a2d7bdSjmcneill return;
38297a2d7bdSjmcneill }
38397a2d7bdSjmcneill
384076a1169Sjmcneill ih = fdtbus_intr_establish_xname(phandle, 0, IPL_USB, FDT_INTR_MPSAFE,
385076a1169Sjmcneill sunxi_musb_intr, sc, device_xname(self));
38697a2d7bdSjmcneill if (ih == NULL) {
38797a2d7bdSjmcneill aprint_error_dev(self, "couldn't establish interrupt on %s\n",
38897a2d7bdSjmcneill intrstr);
38997a2d7bdSjmcneill return;
39097a2d7bdSjmcneill }
39197a2d7bdSjmcneill aprint_normal_dev(self, "interrupting on %s\n", intrstr);
39297a2d7bdSjmcneill
39397a2d7bdSjmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, MUSB2_REG_AWIN_VEND0, 0);
39497a2d7bdSjmcneill
39597a2d7bdSjmcneill motg_init(sc);
39697a2d7bdSjmcneill }
397