1 /* $NetBSD: pxa2x0_ohci.c,v 1.9 2012/10/27 17:17:42 chs Exp $ */ 2 /* $OpenBSD: pxa2x0_ohci.c,v 1.19 2005/04/08 02:32:54 dlg Exp $ */ 3 4 /* 5 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/kernel.h> 24 25 #include <machine/intr.h> 26 #include <sys/bus.h> 27 28 #include <dev/usb/usb.h> 29 #include <dev/usb/usbdi.h> 30 #include <dev/usb/usbdivar.h> 31 #include <dev/usb/usb_mem.h> 32 33 #include <dev/usb/ohcireg.h> 34 #include <dev/usb/ohcivar.h> 35 36 #include <arm/xscale/pxa2x0cpu.h> 37 #include <arm/xscale/pxa2x0reg.h> 38 #include <arm/xscale/pxa2x0var.h> 39 #include <arm/xscale/pxa2x0_gpio.h> 40 41 struct pxaohci_softc { 42 ohci_softc_t sc; 43 44 void *sc_ih; 45 }; 46 47 #if 0 48 static void pxaohci_power(int, void *); 49 #endif 50 static void pxaohci_enable(struct pxaohci_softc *); 51 static void pxaohci_disable(struct pxaohci_softc *); 52 53 #define HREAD4(sc,r) bus_space_read_4((sc)->sc.iot, (sc)->sc.ioh, (r)) 54 #define HWRITE4(sc,r,v) bus_space_write_4((sc)->sc.iot, (sc)->sc.ioh, (r), (v)) 55 56 static int 57 pxaohci_match(device_t parent, struct cfdata *cf, void *aux) 58 { 59 struct pxaip_attach_args *pxa = aux; 60 61 if (CPU_IS_PXA270 && strcmp(pxa->pxa_name, cf->cf_name) == 0) { 62 pxa->pxa_size = PXA2X0_USBHC_SIZE; 63 return 1; 64 } 65 return 0; 66 } 67 68 static void 69 pxaohci_attach(device_t parent, device_t self, void *aux) 70 { 71 struct pxaohci_softc *sc = device_private(self); 72 struct pxaip_attach_args *pxa = aux; 73 usbd_status r; 74 75 #ifdef USB_DEBUG 76 { 77 //extern int ohcidebug; 78 //ohcidebug = 16; 79 } 80 #endif 81 82 sc->sc.iot = pxa->pxa_iot; 83 sc->sc.sc_bus.dmatag = pxa->pxa_dmat; 84 sc->sc.sc_size = 0; 85 sc->sc_ih = NULL; 86 sc->sc.sc_dev = self; 87 sc->sc.sc_bus.hci_private = sc; 88 89 aprint_normal("\n"); 90 aprint_naive("\n"); 91 92 /* Map I/O space */ 93 if (bus_space_map(sc->sc.iot, pxa->pxa_addr, pxa->pxa_size, 0, 94 &sc->sc.ioh)) { 95 aprint_error_dev(sc->sc.sc_dev, "couldn't map memory space\n"); 96 return; 97 } 98 sc->sc.sc_size = pxa->pxa_size; 99 100 /* XXX copied from ohci_pci.c. needed? */ 101 bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, 102 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 103 104 /* start the usb clock */ 105 pxa2x0_clkman_config(CKEN_USBHC, 1); 106 pxaohci_enable(sc); 107 108 /* Disable interrupts, so we don't get any spurious ones. */ 109 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 110 OHCI_MIE); 111 112 sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USBH1, IPL_USB, 113 ohci_intr, &sc->sc); 114 if (sc->sc_ih == NULL) { 115 aprint_error_dev(sc->sc.sc_dev, 116 "unable to establish interrupt\n"); 117 goto free_map; 118 } 119 120 strlcpy(sc->sc.sc_vendor, "PXA27x", sizeof(sc->sc.sc_vendor)); 121 r = ohci_init(&sc->sc); 122 if (r != USBD_NORMAL_COMPLETION) { 123 aprint_error_dev(sc->sc.sc_dev, "init failed, error=%d\n", r); 124 goto free_intr; 125 } 126 127 #if 0 128 sc->sc.sc_powerhook = powerhook_establish(device_xname(sc->sc.sc_bus.bdev), 129 pxaohci_power, sc); 130 if (sc->sc.sc_powerhook == NULL) { 131 aprint_error_dev(sc->sc.sc_dev->sc_bus.bdev, "cannot establish powerhook\n"); 132 } 133 #endif 134 135 sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint); 136 137 return; 138 139 free_intr: 140 pxa2x0_intr_disestablish(sc->sc_ih); 141 sc->sc_ih = NULL; 142 free_map: 143 pxaohci_disable(sc); 144 pxa2x0_clkman_config(CKEN_USBHC, 0); 145 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 146 sc->sc.sc_size = 0; 147 } 148 149 static int 150 pxaohci_detach(device_t self, int flags) 151 { 152 struct pxaohci_softc *sc = device_private(self); 153 int error; 154 155 error = ohci_detach(&sc->sc, flags); 156 if (error) 157 return error; 158 159 #if 0 160 if (sc->sc.sc_powerhook) { 161 powerhook_disestablish(sc->sc.sc_powerhook); 162 sc->sc.sc_powerhook = NULL; 163 } 164 #endif 165 166 if (sc->sc_ih) { 167 pxa2x0_intr_disestablish(sc->sc_ih); 168 sc->sc_ih = NULL; 169 } 170 171 pxaohci_disable(sc); 172 173 /* stop clock */ 174 pxa2x0_clkman_config(CKEN_USBHC, 0); 175 176 if (sc->sc.sc_size) { 177 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 178 sc->sc.sc_size = 0; 179 } 180 181 return 0; 182 } 183 184 #if 0 185 static void 186 pxaohci_power(int why, void *arg) 187 { 188 struct pxaohci_softc *sc = (struct pxaohci_softc *)arg; 189 int s; 190 191 s = splhardusb(); 192 sc->sc.sc_bus.use_polling++; 193 switch (why) { 194 case PWR_STANDBY: 195 case PWR_SUSPEND: 196 #if 0 197 ohci_power(why, &sc->sc); 198 #endif 199 pxa2x0_clkman_config(CKEN_USBHC, 0); 200 break; 201 202 case PWR_RESUME: 203 pxa2x0_clkman_config(CKEN_USBHC, 1); 204 pxaohci_enable(sc); 205 #if 0 206 ohci_power(why, &sc->sc); 207 #endif 208 break; 209 } 210 sc->sc.sc_bus.use_polling--; 211 splx(s); 212 } 213 #endif 214 215 static void 216 pxaohci_enable(struct pxaohci_softc *sc) 217 { 218 uint32_t hr; 219 220 /* Full host reset */ 221 hr = HREAD4(sc, USBHC_HR); 222 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 223 224 DELAY(USBHC_RST_WAIT); 225 226 hr = HREAD4(sc, USBHC_HR); 227 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 228 229 /* Force system bus interface reset */ 230 hr = HREAD4(sc, USBHC_HR); 231 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); 232 233 while (HREAD4(sc, USBHC_HR) & USBHC_HR_FSBIR) 234 DELAY(3); 235 236 /* Enable the ports (physically only one, only enable that one?) */ 237 hr = HREAD4(sc, USBHC_HR); 238 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); 239 hr = HREAD4(sc, USBHC_HR); 240 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & 241 ~(USBHC_HR_SSEP1 | USBHC_HR_SSEP2 | USBHC_HR_SSEP3)); 242 HWRITE4(sc, USBHC_HIE, USBHC_HIE_RWIE | USBHC_HIE_UPRIE); 243 244 hr = HREAD4(sc, USBHC_UHCRHDA); 245 } 246 247 static void 248 pxaohci_disable(struct pxaohci_softc *sc) 249 { 250 uint32_t hr; 251 252 /* Full host reset */ 253 hr = HREAD4(sc, USBHC_HR); 254 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 255 256 DELAY(USBHC_RST_WAIT); 257 258 hr = HREAD4(sc, USBHC_HR); 259 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 260 } 261 262 263 CFATTACH_DECL2_NEW(pxaohci, sizeof(struct pxaohci_softc), 264 pxaohci_match, pxaohci_attach, pxaohci_detach, ohci_activate, NULL, 265 ohci_childdet); 266