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