1 /* $OpenBSD: omohci.c,v 1.3 2014/05/19 13:11:31 mpi 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 <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 #include <armv7/omap/prcmvar.h> 36 37 #define HOSTUEADDR 0x0E0 38 #define HOSTUESTATUS 0x0E4 39 #define HOSTTIMEOUTCTRL 0x0E8 40 #define HOSTREVISION 0x0EC 41 #define WHM_REVID_REGISTER 0x0F4 42 #define WHM_TEST_OBSV 0x0F8 43 #define WHM_TEST_CTL 0x0FC 44 #define HHC_TEST_CFG 0x100 45 #define HHC_TEST_CTL 0x104 46 #define HHC_TEST_OBSV 0x108 47 #define REVDEV 0x200 /* 16 bit */ 48 #define EP_NUM 0x204 /* 16 bit */ 49 #define DATA 0x208 /* 16 bit */ 50 #define CTRL 0x20C /* 16 bit */ 51 #define STAT_FLG 0x210 /* 16 bit */ 52 #define RXFSTAT 0x214 /* 16 bit */ 53 #define SYSCON1 0x218 /* 16 bit */ 54 #define SYSCON2 0x21C /* 16 bit */ 55 #define DEVSTAT 0x220 /* 16 bit */ 56 #define SOFREG 0x224 /* 16 bit */ 57 #define IRQ_EN 0x228 /* 16 bit */ 58 #define DMA_IRQ_EN 0x22C /* 16 bit */ 59 #define IRQ_SRC 0x230 /* 16 bit */ 60 #define EPN_STAT 0x234 /* 16 bit */ 61 #define DMAN_STAT 0x238 /* 16 bit */ 62 #define RXDMA_CFG 0x240 /* 16 bit */ 63 #define TXDMA_CFG 0x244 /* 16 bit */ 64 65 #define TXDMA0 0x250 66 #define TXDMA1 0x254 67 #define TXDMA2 0x258 68 #define RXDMA0 0x260 69 #define RXDMA1 0x264 70 #define RXDMA2 0x268 71 72 #define EP0 0x280 73 #define EP_RX(x) 0x280 + (x * 4) 74 #define EP_TX(x) 0x2C0 + (x * 4) 75 76 #define OTG_REV 0x300 77 #define OTG_SYSCON_1 0x304 78 #define OTG_SYSCON_2 0x308 79 #define OTG_SYSCON2_OTG_EN 0x80000000 80 #define OTG_SYSCON2_UHOST_EN 0x00000100 81 #define OTG_SYSCON2_MODE_DISABLED 0x00000000 82 #define OTG_SYSCON2_MODE_CLIENT 0x00000001 83 #define OTG_SYSCON2_MODE_HOST 0x00000004 84 #define OTG_CTRL 0x30C 85 #if 0 86 #define OTG_IRQ_EN 0x310 /* 16 bit */ 87 #define OTG_IRQ_SRC 0x314 /* 16 bit */ 88 #define OTG_OUTCTRL 0x318 /* 16 bit */ 89 #define OTG_TEST 0x320 /* 16 bit */ 90 #endif 91 #define OTG_VC 0x3FC 92 93 94 int omohci_match(struct device *, void *, void *); 95 void omohci_attach(struct device *, struct device *, void *); 96 int omohci_detach(struct device *, int); 97 int omohci_activate(struct device *, int); 98 99 struct omohci_softc { 100 struct ohci_softc sc; 101 void *sc_ihc0; 102 void *sc_ihc1; 103 void *sc_ihc2; 104 void *sc_ih0; 105 void *sc_ih1; 106 void *sc_ihotg; 107 }; 108 109 void omohci_enable(struct omohci_softc *); 110 void omohci_disable(struct omohci_softc *); 111 112 struct cfattach omohci_ca = { 113 sizeof (struct omohci_softc), omohci_match, omohci_attach, 114 omohci_detach, omohci_detach 115 }; 116 117 int 118 omohci_match(struct device *parent, void *match, void *aux) 119 { 120 #if 0 121 if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X) 122 return (0); 123 #endif 124 125 return (1); 126 } 127 128 void 129 omohci_attach(struct device *parent, struct device *self, void *aux) 130 { 131 struct omohci_softc *sc = (struct omohci_softc *)self; 132 struct ahb_attach_args *aa = aux; 133 usbd_status r; 134 135 sc->sc.iot = aa->aa_iot; 136 sc->sc.sc_bus.dmatag = aa->aa_dmat; 137 sc->sc_ih0 = NULL; 138 sc->sc_ih1 = NULL; 139 sc->sc_ihc0 = NULL; 140 sc->sc_ihc1 = NULL; 141 sc->sc_ihc2 = NULL; 142 sc->sc_ihotg = NULL; 143 sc->sc.sc_size = 0; 144 145 /* Map I/O space */ 146 if (bus_space_map(sc->sc.iot, aa->aa_addr, aa->aa_size, 0, 147 &sc->sc.ioh)) { 148 printf(": cannot map mem space\n"); 149 return; 150 } 151 sc->sc.sc_size = aa->aa_size; 152 153 /* XXX copied from ohci_pci.c. needed? */ 154 bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, 155 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 156 157 #if 0 158 /* start the usb clock */ 159 pxa2x0_clkman_config(CKEN_USBHC, 1); 160 #endif 161 omohci_enable(sc); 162 163 /* Disable interrupts, so we don't get any spurious ones. */ 164 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 165 OHCI_MIE); 166 167 sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB, 168 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 169 sc->sc_ihc1 = arm_intr_establish(aa->aa_intr+1, IPL_USB, 170 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 171 sc->sc_ihc2 = arm_intr_establish(aa->aa_intr+2, IPL_USB, 172 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 173 sc->sc_ih0 = arm_intr_establish(aa->aa_intr+3, IPL_USB, 174 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 175 sc->sc_ih1 = arm_intr_establish(aa->aa_intr+4, IPL_USB, 176 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 177 sc->sc_ihotg = arm_intr_establish(aa->aa_intr+5, IPL_USB, 178 ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 179 if (sc->sc_ih0 == NULL || 180 sc->sc_ih1 == NULL || 181 sc->sc_ihc0 == NULL || 182 sc->sc_ihc1 == NULL || 183 sc->sc_ihc2 == NULL || 184 sc->sc_ihotg == NULL) { 185 printf(": unable to establish interrupt\n"); 186 omohci_disable(sc); 187 #if 0 188 pxa2x0_clkman_config(CKEN_USBHC, 0); 189 #endif 190 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 191 sc->sc.sc_size = 0; 192 return; 193 } 194 195 prcm_enablemodule(PRCM_USB); 196 197 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OTG_SYSCON_2, 198 OTG_SYSCON2_UHOST_EN | OTG_SYSCON2_MODE_HOST); 199 200 strlcpy(sc->sc.sc_vendor, "OMAP24xx", sizeof(sc->sc.sc_vendor)); 201 r = ohci_init(&sc->sc); 202 if (r != USBD_NORMAL_COMPLETION) { 203 printf("%s: init failed, error=%d\n", 204 sc->sc.sc_bus.bdev.dv_xname, r); 205 arm_intr_disestablish(sc->sc_ih0); 206 arm_intr_disestablish(sc->sc_ih1); 207 arm_intr_disestablish(sc->sc_ihc0); 208 arm_intr_disestablish(sc->sc_ihc1); 209 arm_intr_disestablish(sc->sc_ihc2); 210 arm_intr_disestablish(sc->sc_ihotg); 211 sc->sc_ih0 = NULL; 212 sc->sc_ih1 = NULL; 213 sc->sc_ihc0 = NULL; 214 sc->sc_ihc1 = NULL; 215 sc->sc_ihc2 = NULL; 216 sc->sc_ihotg = NULL; 217 omohci_disable(sc); 218 #if 0 219 pxa2x0_clkman_config(CKEN_USBHC, 0); 220 #endif 221 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 222 sc->sc.sc_size = 0; 223 return; 224 } 225 226 config_found(self, &sc->sc.sc_bus, usbctlprint); 227 } 228 229 int 230 omohci_detach(struct device *self, int flags) 231 { 232 struct omohci_softc *sc = (struct omohci_softc *)self; 233 int rv; 234 235 rv = ohci_detach(self, flags); 236 if (rv) 237 return (rv); 238 239 if (sc->sc_ih0 != NULL) { 240 arm_intr_disestablish(sc->sc_ih0); 241 arm_intr_disestablish(sc->sc_ih1); 242 arm_intr_disestablish(sc->sc_ihc0); 243 arm_intr_disestablish(sc->sc_ihc1); 244 arm_intr_disestablish(sc->sc_ihc2); 245 arm_intr_disestablish(sc->sc_ihotg); 246 sc->sc_ih0 = NULL; 247 sc->sc_ih1 = NULL; 248 sc->sc_ihc0 = NULL; 249 sc->sc_ihc1 = NULL; 250 sc->sc_ihc2 = NULL; 251 sc->sc_ihotg = NULL; 252 } 253 254 omohci_disable(sc); 255 256 /* stop clock */ 257 #if 0 258 pxa2x0_clkman_config(CKEN_USBHC, 0); 259 #endif 260 261 if (sc->sc.sc_size) { 262 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 263 sc->sc.sc_size = 0; 264 } 265 266 return (0); 267 } 268 269 270 int 271 omohci_activate(struct device *self, int act) 272 { 273 struct omohci_softc *sc = (struct omohci_softc *)self; 274 275 switch (act) { 276 case DVACT_SUSPEND: 277 sc->sc.sc_bus.use_polling++; 278 ohci_power(why, &sc->sc); 279 #if 0 280 pxa2x0_clkman_config(CKEN_USBHC, 0); 281 #endif 282 sc->sc.sc_bus.use_polling--; 283 break; 284 285 case DVACT_RESUME: 286 sc->sc.sc_bus.use_polling++; 287 #if 0 288 pxa2x0_clkman_config(CKEN_USBHC, 1); 289 #endif 290 omohci_enable(sc); 291 ohci_power(why, &sc->sc); 292 sc->sc.sc_bus.use_polling--; 293 break; 294 } 295 return 0; 296 } 297 298 void 299 omohci_enable(struct omohci_softc *sc) 300 { 301 #if 0 302 u_int32_t hr; 303 304 /* Full host reset */ 305 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 306 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 307 (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 308 309 DELAY(USBHC_RST_WAIT); 310 311 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 312 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 313 (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 314 315 /* Force system bus interface reset */ 316 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 317 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 318 (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); 319 320 while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \ 321 USBHC_HR_FSBIR) 322 DELAY(3); 323 324 /* Enable the ports (physically only one, only enable that one?) */ 325 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 326 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 327 (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); 328 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 329 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 330 (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2)); 331 #endif 332 } 333 334 void 335 omohci_disable(struct omohci_softc *sc) 336 { 337 #if 0 338 u_int32_t hr; 339 340 /* Full host reset */ 341 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 342 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 343 (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 344 345 DELAY(USBHC_RST_WAIT); 346 347 hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 348 bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 349 (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 350 #endif 351 } 352