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