1 1.7 thorpej /* $NetBSD: rmixl_usbi.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $ */ 2 1.2 matt 3 1.2 matt /*- 4 1.2 matt * Copyright (c) 1998, 1999, 2000, 2002, 2003 The NetBSD Foundation, Inc. 5 1.2 matt * All rights reserved. 6 1.2 matt * 7 1.2 matt * This code is derived from software contributed to The NetBSD Foundation 8 1.2 matt * by Cliff Neighbors 9 1.2 matt * 10 1.2 matt * Redistribution and use in source and binary forms, with or without 11 1.2 matt * modification, are permitted provided that the following conditions 12 1.2 matt * are met: 13 1.2 matt * 1. Redistributions of source code must retain the above copyright 14 1.2 matt * notice, this list of conditions and the following disclaimer. 15 1.2 matt * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 matt * notice, this list of conditions and the following disclaimer in the 17 1.2 matt * documentation and/or other materials provided with the distribution. 18 1.2 matt * 19 1.2 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 matt * POSSIBILITY OF SUCH DAMAGE. 30 1.2 matt */ 31 1.2 matt 32 1.2 matt #include <sys/cdefs.h> 33 1.7 thorpej __KERNEL_RCSID(0, "$NetBSD: rmixl_usbi.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $"); 34 1.2 matt 35 1.2 matt #include "locators.h" 36 1.2 matt 37 1.2 matt #include <sys/param.h> 38 1.2 matt #include <sys/systm.h> 39 1.2 matt #include <sys/device.h> 40 1.2 matt 41 1.5 dyoung #include <sys/bus.h> 42 1.2 matt 43 1.2 matt #include <mips/rmi/rmixlreg.h> 44 1.2 matt #include <mips/rmi/rmixlvar.h> 45 1.2 matt #include <mips/rmi/rmixl_intr.h> 46 1.2 matt #include <mips/rmi/rmixl_obiovar.h> 47 1.2 matt #include <mips/rmi/rmixl_usbivar.h> 48 1.2 matt 49 1.2 matt #include <dev/usb/usb.h> 50 1.2 matt #include <dev/usb/usbdi.h> 51 1.2 matt #include <dev/usb/usbdivar.h> 52 1.2 matt #include <dev/usb/usb_mem.h> 53 1.2 matt 54 1.2 matt /* 55 1.2 matt * USB I/O register byte order is 56 1.2 matt * LITTLE ENDIAN regardless of code model 57 1.2 matt */ 58 1.2 matt #define RMIXL_USBI_GEN_VADDR(o) \ 59 1.2 matt (volatile uint32_t *)MIPS_PHYS_TO_KSEG1( \ 60 1.2 matt rmixl_configuration.rc_io_pbase + RMIXL_IO_DEV_USB_B + (o)) 61 1.2 matt #define RMIXL_USBI_GEN_READ(o) le32toh(*RMIXL_USBI_GEN_VADDR(o)) 62 1.2 matt #define RMIXL_USBI_GEN_WRITE(o,v) *RMIXL_USBI_GEN_VADDR(o) = htole32(v) 63 1.2 matt 64 1.4 matt static const char rmixl_usbi_intrnames[RMIXL_UB_INTERRUPT_MAX+1][16] = { 65 1.2 matt "int 0 (ohci0)", 66 1.2 matt "int 1 (ohci1)", 67 1.2 matt "int 2 (ehci)", 68 1.2 matt "int 3 (device)", 69 1.2 matt "int 4 (phy)", 70 1.2 matt "int 5 (force)" 71 1.2 matt }; 72 1.2 matt 73 1.2 matt static int rmixl_usbi_match(device_t, cfdata_t, void *); 74 1.2 matt static void rmixl_usbi_attach(device_t, device_t, void *); 75 1.2 matt static int rmixl_usbi_print(void *, const char *); 76 1.2 matt static int rmixl_usbi_search(device_t, cfdata_t, const int *, void *); 77 1.2 matt static int rmixl_usbi_intr(void *); 78 1.2 matt 79 1.2 matt #ifdef RMIXL_USBI_DEBUG 80 1.2 matt int rmixl_usbi_rdump(void); 81 1.2 matt rmixl_usbi_softc_t *rmixl_usbi_sc; 82 1.2 matt #endif 83 1.2 matt 84 1.2 matt 85 1.2 matt CFATTACH_DECL_NEW(rmixl_usbi, sizeof (rmixl_usbi_softc_t), 86 1.2 matt rmixl_usbi_match, rmixl_usbi_attach, NULL, NULL); 87 1.2 matt 88 1.2 matt int 89 1.2 matt rmixl_usbi_match(device_t parent, cfdata_t match, void *aux) 90 1.2 matt { 91 1.2 matt struct obio_attach_args *obio = aux; 92 1.2 matt 93 1.2 matt if (obio->obio_addr == RMIXL_IO_DEV_USB_B) 94 1.2 matt return rmixl_probe_4((volatile uint32_t *)RMIXL_IOREG_VADDR(obio->obio_addr)); 95 1.2 matt 96 1.2 matt return 0; 97 1.2 matt } 98 1.2 matt 99 1.2 matt void 100 1.2 matt rmixl_usbi_attach(device_t parent, device_t self, void *aux) 101 1.2 matt { 102 1.2 matt rmixl_usbi_softc_t *sc = device_private(self); 103 1.2 matt struct obio_attach_args *obio = aux; 104 1.2 matt uint32_t r; 105 1.2 matt void *ih; 106 1.2 matt 107 1.2 matt #ifdef RMIXL_USBI_DEBUG 108 1.2 matt rmixl_usbi_sc = sc; 109 1.2 matt #endif 110 1.2 matt sc->sc_dev = self; 111 1.2 matt sc->sc_eb_bst = obio->obio_eb_bst; 112 1.2 matt sc->sc_el_bst = obio->obio_el_bst; 113 1.2 matt sc->sc_addr = obio->obio_addr; 114 1.2 matt sc->sc_size = obio->obio_size; 115 1.2 matt sc->sc_dmat = obio->obio_32bit_dmat; 116 1.2 matt 117 1.2 matt aprint_normal("\n%s", device_xname(self)); 118 1.2 matt 119 1.2 matt /* 120 1.2 matt * fail attach if USB interface is disabled GPIO LOW_PWR_DIS reg 121 1.2 matt */ 122 1.2 matt r = RMIXL_IOREG_READ(RMIXL_IO_DEV_GPIO + RMIXL_GPIO_LOW_PWR_DIS); 123 1.2 matt if ((r & RMIXL_GPIO_LOW_PWR_DIS_USB) != 0) { 124 1.2 matt aprint_error(": USB_DIS set in LOW_PWR_DIS, abort attach\n"); 125 1.2 matt return; 126 1.2 matt } 127 1.2 matt 128 1.2 matt /* 129 1.2 matt * fail attach if USB interface BIST failed 130 1.2 matt */ 131 1.2 matt r = RMIXL_IOREG_READ(RMIXL_IO_DEV_GPIO + RMIXL_GPIO_BIST_EACH_STS); 132 1.4 matt aprint_normal(": BIST status=%s,", 133 1.4 matt (r & __BIT(18)) ? "OK" : "FAIL"); /* XXX USB_BIST */ 134 1.2 matt 135 1.2 matt /* 136 1.2 matt * set BYTESWAP_EN register nonzero when software is little endian 137 1.2 matt */ 138 1.2 matt #if BYTE_ORDER == BIG_ENDIAN 139 1.2 matt r = 0; 140 1.2 matt #else 141 1.2 matt r = 1; 142 1.2 matt #endif 143 1.2 matt RMIXL_USBI_GEN_WRITE(RMIXL_USB_BYTESWAP_EN, r); 144 1.2 matt aprint_normal(" byteswap enable=%d", r); 145 1.2 matt for (int intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) { 146 1.2 matt evcnt_attach_dynamic(&sc->sc_dispatch[intr].count, 147 1.2 matt EVCNT_TYPE_INTR, NULL, "rmixl_usbi", 148 1.2 matt rmixl_usbi_intrnames[intr]); 149 1.2 matt } 150 1.2 matt 151 1.2 matt /* Disable all usb interface interrupts */ 152 1.2 matt RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, 0); 153 1.2 matt 154 1.2 matt /* establish interrupt */ 155 1.2 matt if (obio->obio_intr != OBIOCF_INTR_DEFAULT) { 156 1.2 matt ih = rmixl_intr_establish(obio->obio_intr, obio->obio_tmsk, 157 1.2 matt IPL_USB, RMIXL_TRIG_LEVEL, RMIXL_POLR_HIGH, 158 1.2 matt rmixl_usbi_intr, sc, false); 159 1.2 matt if (ih == NULL) 160 1.2 matt panic("%s: couldn't establish interrupt", 161 1.2 matt device_xname(self)); 162 1.2 matt } 163 1.2 matt 164 1.2 matt aprint_normal("\n"); 165 1.2 matt 166 1.2 matt /* attach any children */ 167 1.6 thorpej config_search(self, NULL, 168 1.7 thorpej CFARGS(.search = rmixl_usbi_search)); 169 1.2 matt } 170 1.2 matt 171 1.2 matt static int 172 1.2 matt rmixl_usbi_print(void *aux, const char *pnp) 173 1.2 matt { 174 1.2 matt struct rmixl_usbi_attach_args *usbi = aux; 175 1.2 matt 176 1.2 matt if (usbi->usbi_addr != RMIXL_USBICF_ADDR_DEFAULT) { 177 1.2 matt aprint_normal(" addr %#"PRIxBUSADDR, usbi->usbi_addr); 178 1.2 matt if (usbi->usbi_size != RMIXL_USBICF_SIZE_DEFAULT) 179 1.2 matt aprint_normal("-%#"PRIxBUSADDR, 180 1.2 matt usbi->usbi_addr + (usbi->usbi_size - 1)); 181 1.2 matt } 182 1.2 matt if (usbi->usbi_intr != RMIXL_USBICF_INTR_DEFAULT) 183 1.2 matt aprint_normal(" intr %d", usbi->usbi_intr); 184 1.2 matt 185 1.2 matt aprint_normal("\n"); 186 1.2 matt 187 1.2 matt return (UNCONF); 188 1.2 matt } 189 1.2 matt 190 1.2 matt static int 191 1.2 matt rmixl_usbi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 192 1.2 matt { 193 1.2 matt struct rmixl_usbi_softc *sc = device_private(parent); 194 1.2 matt struct rmixl_usbi_attach_args usbi; 195 1.2 matt 196 1.2 matt usbi.usbi_eb_bst = sc->sc_eb_bst; 197 1.2 matt usbi.usbi_el_bst = sc->sc_el_bst; 198 1.2 matt usbi.usbi_addr = cf->cf_loc[RMIXL_USBICF_ADDR]; 199 1.2 matt usbi.usbi_size = cf->cf_loc[RMIXL_USBICF_SIZE]; 200 1.2 matt usbi.usbi_intr = cf->cf_loc[RMIXL_USBICF_INTR]; 201 1.2 matt usbi.usbi_dmat = sc->sc_dmat; 202 1.2 matt 203 1.6 thorpej if (config_probe(parent, cf, &usbi)) 204 1.7 thorpej config_attach(parent, cf, &usbi, rmixl_usbi_print, CFARGS_NONE); 205 1.2 matt 206 1.2 matt return 0; 207 1.2 matt } 208 1.2 matt 209 1.2 matt 210 1.2 matt void 211 1.2 matt rmixl_usbi_intr_disestablish(void *uh, void *ih) 212 1.2 matt { 213 1.2 matt rmixl_usbi_softc_t *sc = uh; 214 1.2 matt u_int intr; 215 1.2 matt 216 1.2 matt for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) { 217 1.2 matt if (ih == &sc->sc_dispatch[intr]) { 218 1.2 matt uint32_t r; 219 1.2 matt 220 1.2 matt /* disable this interrupt in the usb interface */ 221 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE); 222 1.2 matt r &= 1 << intr; 223 1.2 matt RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r); 224 1.2 matt 225 1.2 matt /* free the dispatch slot */ 226 1.2 matt sc->sc_dispatch[intr].func = NULL; 227 1.2 matt sc->sc_dispatch[intr].arg = NULL; 228 1.2 matt 229 1.2 matt break; 230 1.2 matt } 231 1.2 matt } 232 1.2 matt } 233 1.2 matt 234 1.2 matt void * 235 1.2 matt rmixl_usbi_intr_establish(void *uh, u_int intr, int (func)(void *), void *arg) 236 1.2 matt { 237 1.2 matt rmixl_usbi_softc_t *sc = uh; 238 1.2 matt uint32_t r; 239 1.2 matt void *ih = NULL; 240 1.2 matt int s; 241 1.2 matt 242 1.2 matt s = splusb(); 243 1.2 matt 244 1.2 matt if (intr > RMIXL_UB_INTERRUPT_MAX) { 245 1.2 matt aprint_error_dev(sc->sc_dev, "invalid intr %d\n", intr); 246 1.2 matt goto out; 247 1.2 matt } 248 1.2 matt 249 1.2 matt if (sc->sc_dispatch[intr].func != NULL) { 250 1.2 matt aprint_error_dev(sc->sc_dev, "intr %dq busy\n", intr); 251 1.2 matt goto out; 252 1.2 matt } 253 1.2 matt 254 1.2 matt sc->sc_dispatch[intr].func = func; 255 1.2 matt sc->sc_dispatch[intr].arg = arg; 256 1.2 matt ih = &sc->sc_dispatch[intr]; 257 1.2 matt 258 1.2 matt /* enable this interrupt in the usb interface */ 259 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE); 260 1.2 matt r |= 1 << intr; 261 1.2 matt RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r); 262 1.2 matt 263 1.2 matt out: 264 1.2 matt splx(s); 265 1.2 matt return ih; 266 1.2 matt } 267 1.2 matt 268 1.2 matt static int 269 1.2 matt rmixl_usbi_intr(void *arg) 270 1.2 matt { 271 1.2 matt rmixl_usbi_softc_t *sc = arg; 272 1.2 matt uint32_t r; 273 1.2 matt int intr; 274 1.2 matt int rv = 0; 275 1.2 matt 276 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS); 277 1.2 matt if (r != 0) { 278 1.2 matt for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) { 279 1.2 matt uint32_t bit = 1 << intr; 280 1.2 matt if ((r & bit) != 0) { 281 1.2 matt int (*f)(void *) = sc->sc_dispatch[intr].func; 282 1.2 matt void *a = sc->sc_dispatch[intr].arg; 283 1.2 matt if (f != NULL) { 284 1.2 matt (void)(*f)(a); 285 1.2 matt sc->sc_dispatch[intr].count.ev_count++; 286 1.2 matt rv = 1; 287 1.2 matt } 288 1.2 matt } 289 1.2 matt } 290 1.2 matt } 291 1.2 matt 292 1.2 matt return rv; 293 1.2 matt } 294 1.2 matt 295 1.2 matt #ifdef RMIXL_USBI_DEBUG 296 1.2 matt int 297 1.2 matt rmixl_usbi_rdump(void) 298 1.2 matt { 299 1.2 matt rmixl_usbi_softc_t *sc = rmixl_usbi_sc; 300 1.2 matt uint32_t r; 301 1.2 matt 302 1.2 matt if (sc == NULL) 303 1.2 matt return -1; 304 1.2 matt 305 1.2 matt printf("\n%s:\n", __func__); 306 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL1); 307 1.2 matt printf(" USB_GEN_CTRL1 %#x\n", r); 308 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL2); 309 1.2 matt printf(" USB_GEN_CTRL2 %#x\n", r); 310 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL3); 311 1.2 matt printf(" USB_GEN_CTRL3 %#x\n", r); 312 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_IOBM_TIMER); 313 1.2 matt printf(" USB_IOBM_TIMER %#x\n", r); 314 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_VBUS_TIMER); 315 1.2 matt printf(" USB_VBUS_TIMER %#x\n", r); 316 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_BYTESWAP_EN); 317 1.2 matt printf(" USB_BYTESWAP_EN %#x\n", r); 318 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_BASE); 319 1.2 matt printf(" USB_COHERENT_MEM_BASE %#x\n", r); 320 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_LIMIT); 321 1.2 matt printf(" USB_COHERENT_MEM_LIMIT %#x\n", r); 322 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_BASE); 323 1.2 matt printf(" USB_L2ALLOC_MEM_BASE %#x\n", r); 324 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_LIMIT); 325 1.2 matt printf(" USB_L2ALLOC_MEM_LIMIT %#x\n", r); 326 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_BASE); 327 1.2 matt printf(" USB_READEX_MEM_BASE %#x\n", r); 328 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_LIMIT); 329 1.2 matt printf(" USB_READEX_MEM_LIMIT %#x\n", r); 330 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_PHY_STATUS); 331 1.2 matt printf(" USB_PHY_STATUS %#x\n", r); 332 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS); 333 1.2 matt printf(" USB_INTERRUPT_STATUS %#x\n", r); 334 1.2 matt r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE); 335 1.2 matt printf(" USB_INTERRUPT_ENABLE %#x\n", r); 336 1.2 matt 337 1.2 matt return 0; 338 1.2 matt } 339 1.2 matt #endif 340