1029e367dSAndriy Gapon /*- 2029e367dSAndriy Gapon * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 3029e367dSAndriy Gapon * Copyright (c) 2018 Andrew Turner <andrew@FreeBSD.org> 4029e367dSAndriy Gapon * All rights reserved. 5029e367dSAndriy Gapon * 6029e367dSAndriy Gapon * This software was developed by SRI International and the University of 7029e367dSAndriy Gapon * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 8029e367dSAndriy Gapon * ("CTSRD"), as part of the DARPA CRASH research programme. 9029e367dSAndriy Gapon * 10029e367dSAndriy Gapon * Redistribution and use in source and binary forms, with or without 11029e367dSAndriy Gapon * modification, are permitted provided that the following conditions 12029e367dSAndriy Gapon * are met: 13029e367dSAndriy Gapon * 1. Redistributions of source code must retain the above copyright 14029e367dSAndriy Gapon * notice, this list of conditions and the following disclaimer. 15029e367dSAndriy Gapon * 2. Redistributions in binary form must reproduce the above copyright 16029e367dSAndriy Gapon * notice, this list of conditions and the following disclaimer in the 17029e367dSAndriy Gapon * documentation and/or other materials provided with the distribution. 18029e367dSAndriy Gapon * 19029e367dSAndriy Gapon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20029e367dSAndriy Gapon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21029e367dSAndriy Gapon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22029e367dSAndriy Gapon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23029e367dSAndriy Gapon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24029e367dSAndriy Gapon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25029e367dSAndriy Gapon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26029e367dSAndriy Gapon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27029e367dSAndriy Gapon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28029e367dSAndriy Gapon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29029e367dSAndriy Gapon * SUCH DAMAGE. 30029e367dSAndriy Gapon * 31029e367dSAndriy Gapon * $FreeBSD$ 32029e367dSAndriy Gapon */ 33029e367dSAndriy Gapon 34029e367dSAndriy Gapon /* 35029e367dSAndriy Gapon * Allwinner USB Dual-Role Device (DRD) controller 36029e367dSAndriy Gapon */ 37029e367dSAndriy Gapon 38029e367dSAndriy Gapon #include <sys/cdefs.h> 39029e367dSAndriy Gapon __FBSDID("$FreeBSD$"); 40029e367dSAndriy Gapon 41029e367dSAndriy Gapon #include <sys/param.h> 42029e367dSAndriy Gapon #include <sys/systm.h> 43029e367dSAndriy Gapon #include <sys/bus.h> 44029e367dSAndriy Gapon #include <sys/rman.h> 45029e367dSAndriy Gapon #include <sys/kernel.h> 46029e367dSAndriy Gapon #include <sys/condvar.h> 47029e367dSAndriy Gapon #include <sys/module.h> 48*26d78633SMitchell Horne 49029e367dSAndriy Gapon #include <machine/bus.h> 50029e367dSAndriy Gapon 51029e367dSAndriy Gapon #include <dev/ofw/ofw_bus.h> 52029e367dSAndriy Gapon #include <dev/ofw/ofw_bus_subr.h> 53029e367dSAndriy Gapon 54029e367dSAndriy Gapon #include <dev/usb/usb.h> 55029e367dSAndriy Gapon #include <dev/usb/usbdi.h> 56029e367dSAndriy Gapon 57029e367dSAndriy Gapon #include <dev/usb/usb_core.h> 58029e367dSAndriy Gapon #include <dev/usb/usb_busdma.h> 59029e367dSAndriy Gapon #include <dev/usb/usb_process.h> 60029e367dSAndriy Gapon #include <dev/usb/usb_util.h> 61029e367dSAndriy Gapon 62029e367dSAndriy Gapon #include <dev/usb/usb_controller.h> 63029e367dSAndriy Gapon #include <dev/usb/usb_bus.h> 64029e367dSAndriy Gapon #include <dev/usb/controller/musb_otg.h> 65029e367dSAndriy Gapon 66029e367dSAndriy Gapon #include <dev/extres/clk/clk.h> 67029e367dSAndriy Gapon #include <dev/extres/hwreset/hwreset.h> 681668d773SAndriy Gapon #include <dev/extres/phy/phy.h> 691668d773SAndriy Gapon #include <dev/extres/phy/phy_usb.h> 70029e367dSAndriy Gapon 71029e367dSAndriy Gapon #ifdef __arm__ 72029e367dSAndriy Gapon #include <arm/allwinner/aw_machdep.h> 73029e367dSAndriy Gapon #include <arm/allwinner/a10_sramc.h> 74029e367dSAndriy Gapon #endif 75029e367dSAndriy Gapon 76029e367dSAndriy Gapon #define DRD_EP_MAX 5 77f2066952SAndriy Gapon #define DRD_EP_MAX_H3 4 78029e367dSAndriy Gapon 79029e367dSAndriy Gapon #define MUSB2_REG_AWIN_VEND0 0x0043 80029e367dSAndriy Gapon #define VEND0_PIO_MODE 0 81029e367dSAndriy Gapon 82029e367dSAndriy Gapon #if defined(__arm__) 83029e367dSAndriy Gapon #define bs_parent_space(bs) ((bs)->bs_parent) 84029e367dSAndriy Gapon typedef bus_space_tag_t awusb_bs_tag; 85029e367dSAndriy Gapon #elif defined(__aarch64__) 86029e367dSAndriy Gapon #define bs_parent_space(bs) (bs) 87029e367dSAndriy Gapon typedef void * awusb_bs_tag; 88029e367dSAndriy Gapon #endif 89029e367dSAndriy Gapon 90029e367dSAndriy Gapon #define AWUSB_OKAY 0x01 91029e367dSAndriy Gapon #define AWUSB_NO_CONFDATA 0x02 92029e367dSAndriy Gapon static struct ofw_compat_data compat_data[] = { 93029e367dSAndriy Gapon { "allwinner,sun4i-a10-musb", AWUSB_OKAY }, 94029e367dSAndriy Gapon { "allwinner,sun6i-a31-musb", AWUSB_OKAY }, 95029e367dSAndriy Gapon { "allwinner,sun8i-a33-musb", AWUSB_OKAY | AWUSB_NO_CONFDATA }, 96f2066952SAndriy Gapon { "allwinner,sun8i-h3-musb", AWUSB_OKAY | AWUSB_NO_CONFDATA }, 97029e367dSAndriy Gapon { NULL, 0 } 98029e367dSAndriy Gapon }; 99029e367dSAndriy Gapon 100029e367dSAndriy Gapon static const struct musb_otg_ep_cfg musbotg_ep_allwinner[] = { 101029e367dSAndriy Gapon { 102f2066952SAndriy Gapon .ep_end = DRD_EP_MAX, 103f2066952SAndriy Gapon .ep_fifosz_shift = 9, 104f2066952SAndriy Gapon .ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512, 105f2066952SAndriy Gapon }, 106f2066952SAndriy Gapon { 107f2066952SAndriy Gapon .ep_end = -1, 108f2066952SAndriy Gapon }, 109f2066952SAndriy Gapon }; 110f2066952SAndriy Gapon 111f2066952SAndriy Gapon static const struct musb_otg_ep_cfg musbotg_ep_allwinner_h3[] = { 112f2066952SAndriy Gapon { 113f2066952SAndriy Gapon .ep_end = DRD_EP_MAX_H3, 114029e367dSAndriy Gapon .ep_fifosz_shift = 9, 115029e367dSAndriy Gapon .ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512, 116029e367dSAndriy Gapon }, 117029e367dSAndriy Gapon { 118029e367dSAndriy Gapon .ep_end = -1, 119029e367dSAndriy Gapon }, 120029e367dSAndriy Gapon }; 121029e367dSAndriy Gapon 122029e367dSAndriy Gapon struct awusbdrd_softc { 123029e367dSAndriy Gapon struct musbotg_softc sc; 124029e367dSAndriy Gapon struct resource *res[2]; 125029e367dSAndriy Gapon clk_t clk; 126029e367dSAndriy Gapon hwreset_t reset; 1271668d773SAndriy Gapon phy_t phy; 128029e367dSAndriy Gapon struct bus_space bs; 129029e367dSAndriy Gapon int flags; 130029e367dSAndriy Gapon }; 131029e367dSAndriy Gapon 132029e367dSAndriy Gapon static struct resource_spec awusbdrd_spec[] = { 133029e367dSAndriy Gapon { SYS_RES_MEMORY, 0, RF_ACTIVE }, 134029e367dSAndriy Gapon { SYS_RES_IRQ, 0, RF_ACTIVE }, 135029e367dSAndriy Gapon { -1, 0 } 136029e367dSAndriy Gapon }; 137029e367dSAndriy Gapon 138029e367dSAndriy Gapon #define REMAPFLAG 0x8000 139029e367dSAndriy Gapon #define REGDECL(a, b) [(a)] = ((b) | REMAPFLAG) 140029e367dSAndriy Gapon 141029e367dSAndriy Gapon /* Allwinner USB DRD register mappings */ 142029e367dSAndriy Gapon static const uint16_t awusbdrd_regmap[] = { 143029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(0), 0x0000), 144029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(1), 0x0004), 145029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(2), 0x0008), 146029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(3), 0x000c), 147029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(4), 0x0010), 148029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPFIFO(5), 0x0014), 149029e367dSAndriy Gapon REGDECL(MUSB2_REG_POWER, 0x0040), 150029e367dSAndriy Gapon REGDECL(MUSB2_REG_DEVCTL, 0x0041), 151029e367dSAndriy Gapon REGDECL(MUSB2_REG_EPINDEX, 0x0042), 152029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTTX, 0x0044), 153029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTRX, 0x0046), 154029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTTXE, 0x0048), 155029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTRXE, 0x004a), 156029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTUSB, 0x004c), 157029e367dSAndriy Gapon REGDECL(MUSB2_REG_INTUSBE, 0x0050), 158029e367dSAndriy Gapon REGDECL(MUSB2_REG_FRAME, 0x0054), 159029e367dSAndriy Gapon REGDECL(MUSB2_REG_TESTMODE, 0x007c), 160029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXMAXP, 0x0080), 161029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXCSRL, 0x0082), 162029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXCSRH, 0x0083), 163029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXMAXP, 0x0084), 164029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXCSRL, 0x0086), 165029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXCSRH, 0x0087), 166029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXCOUNT, 0x0088), 167029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXTI, 0x008c), 168029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXNAKLIMIT, 0x008d), 169029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXNAKLIMIT, 0x008f), 170029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXTI, 0x008e), 171029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFIFOSZ, 0x0090), 172029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFIFOADD, 0x0092), 173029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFIFOSZ, 0x0094), 174029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFIFOADD, 0x0096), 175029e367dSAndriy Gapon REGDECL(MUSB2_REG_FADDR, 0x0098), 176029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(0), 0x0098), 177029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(0), 0x009a), 178029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(0), 0x009b), 179029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(0), 0x009c), 180029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(0), 0x009e), 181029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(0), 0x009f), 182029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(1), 0x0098), 183029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(1), 0x009a), 184029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(1), 0x009b), 185029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(1), 0x009c), 186029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(1), 0x009e), 187029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(1), 0x009f), 188029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(2), 0x0098), 189029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(2), 0x009a), 190029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(2), 0x009b), 191029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(2), 0x009c), 192029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(2), 0x009e), 193029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(2), 0x009f), 194029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(3), 0x0098), 195029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(3), 0x009a), 196029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(3), 0x009b), 197029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(3), 0x009c), 198029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(3), 0x009e), 199029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(3), 0x009f), 200029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(4), 0x0098), 201029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(4), 0x009a), 202029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(4), 0x009b), 203029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(4), 0x009c), 204029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(4), 0x009e), 205029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(4), 0x009f), 206029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXFADDR(5), 0x0098), 207029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHADDR(5), 0x009a), 208029e367dSAndriy Gapon REGDECL(MUSB2_REG_TXHUBPORT(5), 0x009b), 209029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXFADDR(5), 0x009c), 210029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHADDR(5), 0x009e), 211029e367dSAndriy Gapon REGDECL(MUSB2_REG_RXHUBPORT(5), 0x009f), 212029e367dSAndriy Gapon REGDECL(MUSB2_REG_CONFDATA, 0x00c0), 213029e367dSAndriy Gapon }; 214029e367dSAndriy Gapon 215029e367dSAndriy Gapon static bus_size_t 216029e367dSAndriy Gapon awusbdrd_reg(bus_size_t o) 217029e367dSAndriy Gapon { 218029e367dSAndriy Gapon bus_size_t v; 219029e367dSAndriy Gapon 220029e367dSAndriy Gapon KASSERT(o < nitems(awusbdrd_regmap), 221029e367dSAndriy Gapon ("%s: Invalid register %#lx", __func__, o)); 222029e367dSAndriy Gapon if (o >= nitems(awusbdrd_regmap)) 223029e367dSAndriy Gapon return (o); 224029e367dSAndriy Gapon 225029e367dSAndriy Gapon v = awusbdrd_regmap[o]; 226029e367dSAndriy Gapon 227029e367dSAndriy Gapon KASSERT((v & REMAPFLAG) != 0, ("%s: reg %#lx not in regmap", 228029e367dSAndriy Gapon __func__, o)); 229029e367dSAndriy Gapon 230029e367dSAndriy Gapon return (v & ~REMAPFLAG); 231029e367dSAndriy Gapon } 232029e367dSAndriy Gapon 233029e367dSAndriy Gapon static int 234029e367dSAndriy Gapon awusbdrd_filt(bus_size_t o) 235029e367dSAndriy Gapon { 236029e367dSAndriy Gapon switch (o) { 237029e367dSAndriy Gapon case MUSB2_REG_MISC: 238029e367dSAndriy Gapon case MUSB2_REG_RXDBDIS: 239029e367dSAndriy Gapon case MUSB2_REG_TXDBDIS: 240029e367dSAndriy Gapon return (1); 241029e367dSAndriy Gapon default: 242029e367dSAndriy Gapon return (0); 243029e367dSAndriy Gapon } 244029e367dSAndriy Gapon } 245029e367dSAndriy Gapon 246029e367dSAndriy Gapon static uint8_t 247029e367dSAndriy Gapon awusbdrd_bs_r_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o) 248029e367dSAndriy Gapon { 249*26d78633SMitchell Horne struct bus_space *bs = t; 250029e367dSAndriy Gapon 251029e367dSAndriy Gapon switch (o) { 252029e367dSAndriy Gapon case MUSB2_REG_HWVERS: 253029e367dSAndriy Gapon return (0); /* no known equivalent */ 254029e367dSAndriy Gapon } 255029e367dSAndriy Gapon 256029e367dSAndriy Gapon return (bus_space_read_1(bs_parent_space(bs), h, awusbdrd_reg(o))); 257029e367dSAndriy Gapon } 258029e367dSAndriy Gapon 259029e367dSAndriy Gapon static uint8_t 260029e367dSAndriy Gapon awusbdrd_bs_r_1_noconf(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o) 261029e367dSAndriy Gapon { 262029e367dSAndriy Gapon 263029e367dSAndriy Gapon /* 264029e367dSAndriy Gapon * There is no confdata register on some SoCs, return the same 265029e367dSAndriy Gapon * magic value as Linux. 266029e367dSAndriy Gapon */ 267029e367dSAndriy Gapon if (o == MUSB2_REG_CONFDATA) 268029e367dSAndriy Gapon return (0xde); 269029e367dSAndriy Gapon 270029e367dSAndriy Gapon return (awusbdrd_bs_r_1(t, h, o)); 271029e367dSAndriy Gapon } 272029e367dSAndriy Gapon 273029e367dSAndriy Gapon 274029e367dSAndriy Gapon static uint16_t 275029e367dSAndriy Gapon awusbdrd_bs_r_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o) 276029e367dSAndriy Gapon { 277*26d78633SMitchell Horne struct bus_space *bs = t; 278029e367dSAndriy Gapon 279d7abf6e7SAndriy Gapon if (awusbdrd_filt(o) != 0) 280d7abf6e7SAndriy Gapon return (0); 281029e367dSAndriy Gapon return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o)); 282029e367dSAndriy Gapon } 283029e367dSAndriy Gapon 284029e367dSAndriy Gapon static void 285029e367dSAndriy Gapon awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 286029e367dSAndriy Gapon uint8_t v) 287029e367dSAndriy Gapon { 288*26d78633SMitchell Horne struct bus_space *bs = t; 289029e367dSAndriy Gapon 290029e367dSAndriy Gapon if (awusbdrd_filt(o) != 0) 291029e367dSAndriy Gapon return; 292029e367dSAndriy Gapon 293029e367dSAndriy Gapon bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v); 294029e367dSAndriy Gapon } 295029e367dSAndriy Gapon 296029e367dSAndriy Gapon static void 297029e367dSAndriy Gapon awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 298029e367dSAndriy Gapon uint16_t v) 299029e367dSAndriy Gapon { 300*26d78633SMitchell Horne struct bus_space *bs = t; 301029e367dSAndriy Gapon 302029e367dSAndriy Gapon if (awusbdrd_filt(o) != 0) 303029e367dSAndriy Gapon return; 304029e367dSAndriy Gapon 305029e367dSAndriy Gapon bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v); 306029e367dSAndriy Gapon } 307029e367dSAndriy Gapon 308029e367dSAndriy Gapon static void 309029e367dSAndriy Gapon awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 310029e367dSAndriy Gapon uint8_t *d, bus_size_t c) 311029e367dSAndriy Gapon { 312*26d78633SMitchell Horne struct bus_space *bs = t; 313029e367dSAndriy Gapon 314029e367dSAndriy Gapon bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c); 315029e367dSAndriy Gapon } 316029e367dSAndriy Gapon 317029e367dSAndriy Gapon static void 318029e367dSAndriy Gapon awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 319029e367dSAndriy Gapon uint32_t *d, bus_size_t c) 320029e367dSAndriy Gapon { 321*26d78633SMitchell Horne struct bus_space *bs = t; 322029e367dSAndriy Gapon 323029e367dSAndriy Gapon bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c); 324029e367dSAndriy Gapon } 325029e367dSAndriy Gapon 326029e367dSAndriy Gapon static void 327029e367dSAndriy Gapon awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 328029e367dSAndriy Gapon const uint8_t *d, bus_size_t c) 329029e367dSAndriy Gapon { 330*26d78633SMitchell Horne struct bus_space *bs = t; 331029e367dSAndriy Gapon 332029e367dSAndriy Gapon if (awusbdrd_filt(o) != 0) 333029e367dSAndriy Gapon return; 334029e367dSAndriy Gapon 335029e367dSAndriy Gapon bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c); 336029e367dSAndriy Gapon } 337029e367dSAndriy Gapon 338029e367dSAndriy Gapon static void 339029e367dSAndriy Gapon awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o, 340029e367dSAndriy Gapon const uint32_t *d, bus_size_t c) 341029e367dSAndriy Gapon { 342*26d78633SMitchell Horne struct bus_space *bs = t; 343029e367dSAndriy Gapon 344029e367dSAndriy Gapon if (awusbdrd_filt(o) != 0) 345029e367dSAndriy Gapon return; 346029e367dSAndriy Gapon 347029e367dSAndriy Gapon bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c); 348029e367dSAndriy Gapon } 349029e367dSAndriy Gapon 350029e367dSAndriy Gapon static void 351029e367dSAndriy Gapon awusbdrd_intr(void *arg) 352029e367dSAndriy Gapon { 353029e367dSAndriy Gapon struct awusbdrd_softc *sc = arg; 354029e367dSAndriy Gapon uint8_t intusb; 355029e367dSAndriy Gapon uint16_t inttx, intrx; 356029e367dSAndriy Gapon 357029e367dSAndriy Gapon intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB); 358029e367dSAndriy Gapon inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX); 359029e367dSAndriy Gapon intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX); 360029e367dSAndriy Gapon if (intusb == 0 && inttx == 0 && intrx == 0) 361029e367dSAndriy Gapon return; 362029e367dSAndriy Gapon 363029e367dSAndriy Gapon if (intusb) 364029e367dSAndriy Gapon MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb); 365029e367dSAndriy Gapon if (inttx) 366029e367dSAndriy Gapon MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx); 367029e367dSAndriy Gapon if (intrx) 368029e367dSAndriy Gapon MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx); 369029e367dSAndriy Gapon 370029e367dSAndriy Gapon musbotg_interrupt(arg, intrx, inttx, intusb); 371029e367dSAndriy Gapon } 372029e367dSAndriy Gapon 373029e367dSAndriy Gapon static int 374029e367dSAndriy Gapon awusbdrd_probe(device_t dev) 375029e367dSAndriy Gapon { 376029e367dSAndriy Gapon if (!ofw_bus_status_okay(dev)) 377029e367dSAndriy Gapon return (ENXIO); 378029e367dSAndriy Gapon 379029e367dSAndriy Gapon if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 380029e367dSAndriy Gapon return (ENXIO); 381029e367dSAndriy Gapon 382029e367dSAndriy Gapon device_set_desc(dev, "Allwinner USB DRD"); 383029e367dSAndriy Gapon return (BUS_PROBE_DEFAULT); 384029e367dSAndriy Gapon } 385029e367dSAndriy Gapon 386029e367dSAndriy Gapon static int 387029e367dSAndriy Gapon awusbdrd_attach(device_t dev) 388029e367dSAndriy Gapon { 3891668d773SAndriy Gapon char usb_mode[24]; 390029e367dSAndriy Gapon struct awusbdrd_softc *sc; 3911668d773SAndriy Gapon uint8_t musb_mode; 3921668d773SAndriy Gapon int phy_mode; 393029e367dSAndriy Gapon int error; 394029e367dSAndriy Gapon 395029e367dSAndriy Gapon sc = device_get_softc(dev); 396029e367dSAndriy Gapon sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 397029e367dSAndriy Gapon 398029e367dSAndriy Gapon error = bus_alloc_resources(dev, awusbdrd_spec, sc->res); 399029e367dSAndriy Gapon if (error != 0) 400029e367dSAndriy Gapon return (error); 401029e367dSAndriy Gapon 4021668d773SAndriy Gapon musb_mode = MUSB2_HOST_MODE; /* default */ 4031668d773SAndriy Gapon phy_mode = PHY_USB_MODE_HOST; 4041668d773SAndriy Gapon if (OF_getprop(ofw_bus_get_node(dev), "dr_mode", 4051668d773SAndriy Gapon &usb_mode, sizeof(usb_mode)) > 0) { 4061668d773SAndriy Gapon usb_mode[sizeof(usb_mode) - 1] = 0; 4071668d773SAndriy Gapon if (strcasecmp(usb_mode, "host") == 0) { 4081668d773SAndriy Gapon musb_mode = MUSB2_HOST_MODE; 4091668d773SAndriy Gapon phy_mode = PHY_USB_MODE_HOST; 4101668d773SAndriy Gapon } else if (strcasecmp(usb_mode, "peripheral") == 0) { 4111668d773SAndriy Gapon musb_mode = MUSB2_DEVICE_MODE; 4121668d773SAndriy Gapon phy_mode = PHY_USB_MODE_DEVICE; 4131668d773SAndriy Gapon } else if (strcasecmp(usb_mode, "otg") == 0) { 4141668d773SAndriy Gapon /* 4151668d773SAndriy Gapon * XXX phy has PHY_USB_MODE_OTG, but MUSB does not have 4161668d773SAndriy Gapon * it. It's not clear how to propagate mode changes 4171668d773SAndriy Gapon * from phy layer (that detects them) to MUSB. 4181668d773SAndriy Gapon */ 4191668d773SAndriy Gapon musb_mode = MUSB2_DEVICE_MODE; 4201668d773SAndriy Gapon phy_mode = PHY_USB_MODE_DEVICE; 4211668d773SAndriy Gapon } else { 4221668d773SAndriy Gapon device_printf(dev, "Invalid FDT dr_mode: %s\n", 4231668d773SAndriy Gapon usb_mode); 4241668d773SAndriy Gapon } 4251668d773SAndriy Gapon } 4261668d773SAndriy Gapon 427029e367dSAndriy Gapon /* AHB gate clock is required */ 428029e367dSAndriy Gapon error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); 429029e367dSAndriy Gapon if (error != 0) 430029e367dSAndriy Gapon goto fail; 431029e367dSAndriy Gapon 432029e367dSAndriy Gapon /* AHB reset is only present on some SoCs */ 433029e367dSAndriy Gapon (void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset); 434029e367dSAndriy Gapon 435029e367dSAndriy Gapon /* Enable clocks */ 436029e367dSAndriy Gapon error = clk_enable(sc->clk); 437029e367dSAndriy Gapon if (error != 0) { 438029e367dSAndriy Gapon device_printf(dev, "failed to enable clock: %d\n", error); 439029e367dSAndriy Gapon goto fail; 440029e367dSAndriy Gapon } 441029e367dSAndriy Gapon if (sc->reset != NULL) { 442029e367dSAndriy Gapon error = hwreset_deassert(sc->reset); 443029e367dSAndriy Gapon if (error != 0) { 444029e367dSAndriy Gapon device_printf(dev, "failed to de-assert reset: %d\n", 445029e367dSAndriy Gapon error); 446029e367dSAndriy Gapon goto fail; 447029e367dSAndriy Gapon } 448029e367dSAndriy Gapon } 449029e367dSAndriy Gapon 4501668d773SAndriy Gapon /* XXX not sure if this is universally needed. */ 4511668d773SAndriy Gapon (void)phy_get_by_ofw_name(dev, 0, "usb", &sc->phy); 4521668d773SAndriy Gapon if (sc->phy != NULL) { 4531668d773SAndriy Gapon device_printf(dev, "setting phy mode %d\n", phy_mode); 4541668d773SAndriy Gapon if (musb_mode == MUSB2_HOST_MODE) { 4551668d773SAndriy Gapon error = phy_enable(sc->phy); 4561668d773SAndriy Gapon if (error != 0) { 4571668d773SAndriy Gapon device_printf(dev, "Could not enable phy\n"); 4581668d773SAndriy Gapon goto fail; 4591668d773SAndriy Gapon } 4601668d773SAndriy Gapon } 4611668d773SAndriy Gapon error = phy_usb_set_mode(sc->phy, phy_mode); 4621668d773SAndriy Gapon if (error != 0) { 4631668d773SAndriy Gapon device_printf(dev, "Could not set phy mode\n"); 4641668d773SAndriy Gapon goto fail; 4651668d773SAndriy Gapon } 4661668d773SAndriy Gapon } 4671668d773SAndriy Gapon 468029e367dSAndriy Gapon sc->sc.sc_bus.parent = dev; 469029e367dSAndriy Gapon sc->sc.sc_bus.devices = sc->sc.sc_devices; 470029e367dSAndriy Gapon sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES; 471029e367dSAndriy Gapon sc->sc.sc_bus.dma_bits = 32; 472029e367dSAndriy Gapon 473029e367dSAndriy Gapon error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev), 474029e367dSAndriy Gapon NULL); 475029e367dSAndriy Gapon if (error != 0) { 476029e367dSAndriy Gapon error = ENOMEM; 477029e367dSAndriy Gapon goto fail; 478029e367dSAndriy Gapon } 479029e367dSAndriy Gapon 480029e367dSAndriy Gapon #if defined(__arm__) 481029e367dSAndriy Gapon sc->bs.bs_parent = rman_get_bustag(sc->res[0]); 482029e367dSAndriy Gapon #elif defined(__aarch64__) 483029e367dSAndriy Gapon sc->bs.bs_cookie = rman_get_bustag(sc->res[0]); 484029e367dSAndriy Gapon #endif 485029e367dSAndriy Gapon 486029e367dSAndriy Gapon if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA) 487029e367dSAndriy Gapon sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf; 488029e367dSAndriy Gapon else 489029e367dSAndriy Gapon sc->bs.bs_r_1 = awusbdrd_bs_r_1; 490029e367dSAndriy Gapon sc->bs.bs_r_2 = awusbdrd_bs_r_2; 491029e367dSAndriy Gapon sc->bs.bs_w_1 = awusbdrd_bs_w_1; 492029e367dSAndriy Gapon sc->bs.bs_w_2 = awusbdrd_bs_w_2; 493029e367dSAndriy Gapon sc->bs.bs_rm_1 = awusbdrd_bs_rm_1; 494029e367dSAndriy Gapon sc->bs.bs_rm_4 = awusbdrd_bs_rm_4; 495029e367dSAndriy Gapon sc->bs.bs_wm_1 = awusbdrd_bs_wm_1; 496029e367dSAndriy Gapon sc->bs.bs_wm_4 = awusbdrd_bs_wm_4; 497029e367dSAndriy Gapon 498029e367dSAndriy Gapon sc->sc.sc_io_tag = &sc->bs; 499029e367dSAndriy Gapon sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]); 500029e367dSAndriy Gapon sc->sc.sc_io_size = rman_get_size(sc->res[0]); 501029e367dSAndriy Gapon 502029e367dSAndriy Gapon sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", -1); 503029e367dSAndriy Gapon if (sc->sc.sc_bus.bdev == NULL) { 504029e367dSAndriy Gapon error = ENXIO; 505029e367dSAndriy Gapon goto fail; 506029e367dSAndriy Gapon } 507029e367dSAndriy Gapon device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus); 508029e367dSAndriy Gapon sc->sc.sc_id = 0; 509029e367dSAndriy Gapon sc->sc.sc_platform_data = sc; 5101668d773SAndriy Gapon sc->sc.sc_mode = musb_mode; 511f2066952SAndriy Gapon if (ofw_bus_is_compatible(dev, "allwinner,sun8i-h3-musb")) { 512f2066952SAndriy Gapon sc->sc.sc_ep_cfg = musbotg_ep_allwinner_h3; 513f2066952SAndriy Gapon sc->sc.sc_ep_max = DRD_EP_MAX_H3; 514f2066952SAndriy Gapon } else { 515029e367dSAndriy Gapon sc->sc.sc_ep_cfg = musbotg_ep_allwinner; 516f2066952SAndriy Gapon sc->sc.sc_ep_max = DRD_EP_MAX; 517f2066952SAndriy Gapon } 518029e367dSAndriy Gapon 519029e367dSAndriy Gapon error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO, 520029e367dSAndriy Gapon NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl); 521029e367dSAndriy Gapon if (error != 0) 522029e367dSAndriy Gapon goto fail; 523029e367dSAndriy Gapon 524029e367dSAndriy Gapon /* Enable PIO mode */ 525029e367dSAndriy Gapon bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE); 526029e367dSAndriy Gapon 527029e367dSAndriy Gapon #ifdef __arm__ 528029e367dSAndriy Gapon /* Map SRAMD area to USB0 (sun4i/sun7i only) */ 529029e367dSAndriy Gapon switch (allwinner_soc_family()) { 530029e367dSAndriy Gapon case ALLWINNERSOC_SUN4I: 531029e367dSAndriy Gapon case ALLWINNERSOC_SUN7I: 532029e367dSAndriy Gapon a10_map_to_otg(); 533029e367dSAndriy Gapon break; 534029e367dSAndriy Gapon } 535029e367dSAndriy Gapon #endif 536029e367dSAndriy Gapon 537029e367dSAndriy Gapon error = musbotg_init(&sc->sc); 538029e367dSAndriy Gapon if (error != 0) 539029e367dSAndriy Gapon goto fail; 540029e367dSAndriy Gapon 541029e367dSAndriy Gapon error = device_probe_and_attach(sc->sc.sc_bus.bdev); 542029e367dSAndriy Gapon if (error != 0) 543029e367dSAndriy Gapon goto fail; 544029e367dSAndriy Gapon 545029e367dSAndriy Gapon musbotg_vbus_interrupt(&sc->sc, 1); /* XXX VBUS */ 546029e367dSAndriy Gapon 547029e367dSAndriy Gapon return (0); 548029e367dSAndriy Gapon 549029e367dSAndriy Gapon fail: 5501668d773SAndriy Gapon if (sc->phy != NULL) { 5511668d773SAndriy Gapon if (musb_mode == MUSB2_HOST_MODE) 5521668d773SAndriy Gapon (void)phy_disable(sc->phy); 5531668d773SAndriy Gapon phy_release(sc->phy); 5541668d773SAndriy Gapon } 5551668d773SAndriy Gapon if (sc->reset != NULL) { 5561668d773SAndriy Gapon hwreset_assert(sc->reset); 557029e367dSAndriy Gapon hwreset_release(sc->reset); 5581668d773SAndriy Gapon } 559029e367dSAndriy Gapon if (sc->clk != NULL) 560029e367dSAndriy Gapon clk_release(sc->clk); 561029e367dSAndriy Gapon bus_release_resources(dev, awusbdrd_spec, sc->res); 562029e367dSAndriy Gapon return (error); 563029e367dSAndriy Gapon } 564029e367dSAndriy Gapon 565029e367dSAndriy Gapon static int 566029e367dSAndriy Gapon awusbdrd_detach(device_t dev) 567029e367dSAndriy Gapon { 568029e367dSAndriy Gapon struct awusbdrd_softc *sc; 569029e367dSAndriy Gapon device_t bdev; 570029e367dSAndriy Gapon int error; 571029e367dSAndriy Gapon 572029e367dSAndriy Gapon sc = device_get_softc(dev); 573029e367dSAndriy Gapon 574029e367dSAndriy Gapon if (sc->sc.sc_bus.bdev != NULL) { 575029e367dSAndriy Gapon bdev = sc->sc.sc_bus.bdev; 576029e367dSAndriy Gapon device_detach(bdev); 577029e367dSAndriy Gapon device_delete_child(dev, bdev); 578029e367dSAndriy Gapon } 579029e367dSAndriy Gapon 580029e367dSAndriy Gapon musbotg_uninit(&sc->sc); 581029e367dSAndriy Gapon error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl); 582029e367dSAndriy Gapon if (error != 0) 583029e367dSAndriy Gapon return (error); 584029e367dSAndriy Gapon 585029e367dSAndriy Gapon usb_bus_mem_free_all(&sc->sc.sc_bus, NULL); 586029e367dSAndriy Gapon 5871668d773SAndriy Gapon if (sc->phy != NULL) { 5881668d773SAndriy Gapon if (sc->sc.sc_mode == MUSB2_HOST_MODE) 5891668d773SAndriy Gapon phy_disable(sc->phy); 5901668d773SAndriy Gapon phy_release(sc->phy); 5911668d773SAndriy Gapon } 5921668d773SAndriy Gapon if (sc->reset != NULL) { 5931668d773SAndriy Gapon if (hwreset_assert(sc->reset) != 0) 5941668d773SAndriy Gapon device_printf(dev, "failed to assert reset\n"); 595029e367dSAndriy Gapon hwreset_release(sc->reset); 5961668d773SAndriy Gapon } 597029e367dSAndriy Gapon if (sc->clk != NULL) 598029e367dSAndriy Gapon clk_release(sc->clk); 599029e367dSAndriy Gapon 600029e367dSAndriy Gapon bus_release_resources(dev, awusbdrd_spec, sc->res); 601029e367dSAndriy Gapon 602029e367dSAndriy Gapon device_delete_children(dev); 603029e367dSAndriy Gapon 604029e367dSAndriy Gapon return (0); 605029e367dSAndriy Gapon } 606029e367dSAndriy Gapon 607029e367dSAndriy Gapon static device_method_t awusbdrd_methods[] = { 608029e367dSAndriy Gapon /* Device interface */ 609029e367dSAndriy Gapon DEVMETHOD(device_probe, awusbdrd_probe), 610029e367dSAndriy Gapon DEVMETHOD(device_attach, awusbdrd_attach), 611029e367dSAndriy Gapon DEVMETHOD(device_detach, awusbdrd_detach), 612029e367dSAndriy Gapon DEVMETHOD(device_suspend, bus_generic_suspend), 613029e367dSAndriy Gapon DEVMETHOD(device_resume, bus_generic_resume), 614029e367dSAndriy Gapon DEVMETHOD(device_shutdown, bus_generic_shutdown), 615029e367dSAndriy Gapon 616029e367dSAndriy Gapon DEVMETHOD_END 617029e367dSAndriy Gapon }; 618029e367dSAndriy Gapon 619029e367dSAndriy Gapon static driver_t awusbdrd_driver = { 620029e367dSAndriy Gapon .name = "musbotg", 621029e367dSAndriy Gapon .methods = awusbdrd_methods, 622029e367dSAndriy Gapon .size = sizeof(struct awusbdrd_softc), 623029e367dSAndriy Gapon }; 624029e367dSAndriy Gapon 625bc9372d7SJohn Baldwin DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, 0, 0); 626029e367dSAndriy Gapon MODULE_DEPEND(musbotg, usb, 1, 1, 1); 627