1 /* $NetBSD: pxa2x0_ohci.c,v 1.5 2009/01/29 14:46:06 nonaka 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 <machine/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 60 if (CPU_IS_PXA270) 61 return 1; 62 return 0; 63 } 64 65 static void 66 pxaohci_attach(device_t parent, device_t self, void *aux) 67 { 68 struct pxaohci_softc *sc = device_private(self); 69 struct pxaip_attach_args *pxa = aux; 70 usbd_status r; 71 72 #ifdef USB_DEBUG 73 { 74 //extern int ohcidebug; 75 //ohcidebug = 16; 76 } 77 #endif 78 79 sc->sc.iot = pxa->pxa_iot; 80 sc->sc.sc_bus.dmatag = pxa->pxa_dmat; 81 sc->sc.sc_size = 0; 82 sc->sc_ih = NULL; 83 sc->sc.sc_dev = self; 84 sc->sc.sc_bus.hci_private = sc; 85 86 aprint_normal("\n"); 87 aprint_naive("\n"); 88 89 /* Map I/O space */ 90 if (bus_space_map(sc->sc.iot, PXA2X0_USBHC_BASE, PXA2X0_USBHC_SIZE, 0, 91 &sc->sc.ioh)) { 92 aprint_error_dev(sc->sc.sc_dev, "couldn't map memory space\n"); 93 return; 94 } 95 sc->sc.sc_size = PXA2X0_USBHC_SIZE; 96 97 /* XXX copied from ohci_pci.c. needed? */ 98 bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, 99 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 100 101 /* start the usb clock */ 102 pxa2x0_clkman_config(CKEN_USBHC, 1); 103 pxaohci_enable(sc); 104 105 /* Disable interrupts, so we don't get any spurious ones. */ 106 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 107 OHCI_MIE); 108 109 sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USBH1, IPL_USB, 110 ohci_intr, &sc->sc); 111 if (sc->sc_ih == NULL) { 112 aprint_error_dev(sc->sc.sc_dev, 113 "unable to establish interrupt\n"); 114 goto free_map; 115 } 116 117 strlcpy(sc->sc.sc_vendor, "PXA27x", sizeof(sc->sc.sc_vendor)); 118 r = ohci_init(&sc->sc); 119 if (r != USBD_NORMAL_COMPLETION) { 120 aprint_error_dev(sc->sc.sc_dev, "init failed, error=%d\n", r); 121 goto free_intr; 122 } 123 124 #if 0 125 sc->sc.sc_powerhook = powerhook_establish(sc->sc.sc_bus.bdev.dv_xname, 126 pxaohci_power, sc); 127 if (sc->sc.sc_powerhook == NULL) { 128 aprint_error("%s: cannot establish powerhook\n", 129 sc->sc.sc_dev->sc_bus.bdev.dv_xname); 130 } 131 #endif 132 133 sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint); 134 135 return; 136 137 free_intr: 138 pxa2x0_intr_disestablish(sc->sc_ih); 139 sc->sc_ih = NULL; 140 free_map: 141 pxaohci_disable(sc); 142 pxa2x0_clkman_config(CKEN_USBHC, 0); 143 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 144 sc->sc.sc_size = 0; 145 } 146 147 static int 148 pxaohci_detach(device_t self, int flags) 149 { 150 struct pxaohci_softc *sc = device_private(self); 151 int error; 152 153 error = ohci_detach(&sc->sc, flags); 154 if (error) 155 return error; 156 157 #if 0 158 if (sc->sc.sc_powerhook) { 159 powerhook_disestablish(sc->sc.sc_powerhook); 160 sc->sc.sc_powerhook = NULL; 161 } 162 #endif 163 164 if (sc->sc_ih) { 165 pxa2x0_intr_disestablish(sc->sc_ih); 166 sc->sc_ih = NULL; 167 } 168 169 pxaohci_disable(sc); 170 171 /* stop clock */ 172 pxa2x0_clkman_config(CKEN_USBHC, 0); 173 174 if (sc->sc.sc_size) { 175 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 176 sc->sc.sc_size = 0; 177 } 178 179 return 0; 180 } 181 182 #if 0 183 static void 184 pxaohci_power(int why, void *arg) 185 { 186 struct pxaohci_softc *sc = (struct pxaohci_softc *)arg; 187 int s; 188 189 s = splhardusb(); 190 sc->sc.sc_bus.use_polling++; 191 switch (why) { 192 case PWR_STANDBY: 193 case PWR_SUSPEND: 194 #if 0 195 ohci_power(why, &sc->sc); 196 #endif 197 pxa2x0_clkman_config(CKEN_USBHC, 0); 198 break; 199 200 case PWR_RESUME: 201 pxa2x0_clkman_config(CKEN_USBHC, 1); 202 pxaohci_enable(sc); 203 #if 0 204 ohci_power(why, &sc->sc); 205 #endif 206 break; 207 } 208 sc->sc.sc_bus.use_polling--; 209 splx(s); 210 } 211 #endif 212 213 static void 214 pxaohci_enable(struct pxaohci_softc *sc) 215 { 216 uint32_t hr; 217 218 /* Full host reset */ 219 hr = HREAD4(sc, USBHC_HR); 220 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 221 222 DELAY(USBHC_RST_WAIT); 223 224 hr = HREAD4(sc, USBHC_HR); 225 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 226 227 /* Force system bus interface reset */ 228 hr = HREAD4(sc, USBHC_HR); 229 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); 230 231 while (HREAD4(sc, USBHC_HR) & USBHC_HR_FSBIR) 232 DELAY(3); 233 234 /* Enable the ports (physically only one, only enable that one?) */ 235 hr = HREAD4(sc, USBHC_HR); 236 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); 237 hr = HREAD4(sc, USBHC_HR); 238 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2)); 239 } 240 241 static void 242 pxaohci_disable(struct pxaohci_softc *sc) 243 { 244 uint32_t hr; 245 246 /* Full host reset */ 247 hr = HREAD4(sc, USBHC_HR); 248 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 249 250 DELAY(USBHC_RST_WAIT); 251 252 hr = HREAD4(sc, USBHC_HR); 253 HWRITE4(sc, USBHC_HR, (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 254 } 255 256 257 CFATTACH_DECL2_NEW(pxaohci, sizeof(struct pxaohci_softc), 258 pxaohci_match, pxaohci_attach, pxaohci_detach, ohci_activate, NULL, 259 ohci_childdet); 260 261 262