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