1*ea05d060Sderaadt /* $OpenBSD: omohci.c,v 1.5 2024/08/20 16:24:50 deraadt Exp $ */ 28eda2d14Spatrick 38eda2d14Spatrick /* 48eda2d14Spatrick * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 58eda2d14Spatrick * 68eda2d14Spatrick * Permission to use, copy, modify, and distribute this software for any 78eda2d14Spatrick * purpose with or without fee is hereby granted, provided that the above 88eda2d14Spatrick * copyright notice and this permission notice appear in all copies. 98eda2d14Spatrick * 108eda2d14Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 118eda2d14Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 128eda2d14Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 138eda2d14Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 148eda2d14Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 158eda2d14Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 168eda2d14Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 178eda2d14Spatrick */ 188eda2d14Spatrick 198eda2d14Spatrick #include <sys/param.h> 208eda2d14Spatrick #include <sys/systm.h> 218eda2d14Spatrick #include <sys/device.h> 228eda2d14Spatrick #include <sys/kernel.h> 238eda2d14Spatrick #include <sys/timeout.h> 248eda2d14Spatrick 258eda2d14Spatrick #include <machine/intr.h> 268eda2d14Spatrick #include <machine/bus.h> 278eda2d14Spatrick 288eda2d14Spatrick #include <dev/usb/usb.h> 298eda2d14Spatrick #include <dev/usb/usbdi.h> 308eda2d14Spatrick #include <dev/usb/usbdivar.h> 318eda2d14Spatrick #include <dev/usb/usb_mem.h> 328eda2d14Spatrick 338eda2d14Spatrick #include <dev/usb/ohcireg.h> 348eda2d14Spatrick #include <dev/usb/ohcivar.h> 358eda2d14Spatrick #include <armv7/omap/prcmvar.h> 368eda2d14Spatrick 378eda2d14Spatrick #define HOSTUEADDR 0x0E0 388eda2d14Spatrick #define HOSTUESTATUS 0x0E4 398eda2d14Spatrick #define HOSTTIMEOUTCTRL 0x0E8 408eda2d14Spatrick #define HOSTREVISION 0x0EC 418eda2d14Spatrick #define WHM_REVID_REGISTER 0x0F4 428eda2d14Spatrick #define WHM_TEST_OBSV 0x0F8 438eda2d14Spatrick #define WHM_TEST_CTL 0x0FC 448eda2d14Spatrick #define HHC_TEST_CFG 0x100 458eda2d14Spatrick #define HHC_TEST_CTL 0x104 468eda2d14Spatrick #define HHC_TEST_OBSV 0x108 478eda2d14Spatrick #define REVDEV 0x200 /* 16 bit */ 488eda2d14Spatrick #define EP_NUM 0x204 /* 16 bit */ 498eda2d14Spatrick #define DATA 0x208 /* 16 bit */ 508eda2d14Spatrick #define CTRL 0x20C /* 16 bit */ 518eda2d14Spatrick #define STAT_FLG 0x210 /* 16 bit */ 528eda2d14Spatrick #define RXFSTAT 0x214 /* 16 bit */ 538eda2d14Spatrick #define SYSCON1 0x218 /* 16 bit */ 548eda2d14Spatrick #define SYSCON2 0x21C /* 16 bit */ 558eda2d14Spatrick #define DEVSTAT 0x220 /* 16 bit */ 568eda2d14Spatrick #define SOFREG 0x224 /* 16 bit */ 578eda2d14Spatrick #define IRQ_EN 0x228 /* 16 bit */ 588eda2d14Spatrick #define DMA_IRQ_EN 0x22C /* 16 bit */ 598eda2d14Spatrick #define IRQ_SRC 0x230 /* 16 bit */ 608eda2d14Spatrick #define EPN_STAT 0x234 /* 16 bit */ 618eda2d14Spatrick #define DMAN_STAT 0x238 /* 16 bit */ 628eda2d14Spatrick #define RXDMA_CFG 0x240 /* 16 bit */ 638eda2d14Spatrick #define TXDMA_CFG 0x244 /* 16 bit */ 648eda2d14Spatrick 658eda2d14Spatrick #define TXDMA0 0x250 668eda2d14Spatrick #define TXDMA1 0x254 678eda2d14Spatrick #define TXDMA2 0x258 688eda2d14Spatrick #define RXDMA0 0x260 698eda2d14Spatrick #define RXDMA1 0x264 708eda2d14Spatrick #define RXDMA2 0x268 718eda2d14Spatrick 728eda2d14Spatrick #define EP0 0x280 738eda2d14Spatrick #define EP_RX(x) 0x280 + (x * 4) 748eda2d14Spatrick #define EP_TX(x) 0x2C0 + (x * 4) 758eda2d14Spatrick 768eda2d14Spatrick #define OTG_REV 0x300 778eda2d14Spatrick #define OTG_SYSCON_1 0x304 788eda2d14Spatrick #define OTG_SYSCON_2 0x308 798eda2d14Spatrick #define OTG_SYSCON2_OTG_EN 0x80000000 808eda2d14Spatrick #define OTG_SYSCON2_UHOST_EN 0x00000100 818eda2d14Spatrick #define OTG_SYSCON2_MODE_DISABLED 0x00000000 828eda2d14Spatrick #define OTG_SYSCON2_MODE_CLIENT 0x00000001 838eda2d14Spatrick #define OTG_SYSCON2_MODE_HOST 0x00000004 848eda2d14Spatrick #define OTG_CTRL 0x30C 858eda2d14Spatrick #if 0 868eda2d14Spatrick #define OTG_IRQ_EN 0x310 /* 16 bit */ 878eda2d14Spatrick #define OTG_IRQ_SRC 0x314 /* 16 bit */ 888eda2d14Spatrick #define OTG_OUTCTRL 0x318 /* 16 bit */ 898eda2d14Spatrick #define OTG_TEST 0x320 /* 16 bit */ 908eda2d14Spatrick #endif 918eda2d14Spatrick #define OTG_VC 0x3FC 928eda2d14Spatrick 938eda2d14Spatrick 948eda2d14Spatrick int omohci_match(struct device *, void *, void *); 958eda2d14Spatrick void omohci_attach(struct device *, struct device *, void *); 968eda2d14Spatrick int omohci_detach(struct device *, int); 978eda2d14Spatrick int omohci_activate(struct device *, int); 988eda2d14Spatrick 998eda2d14Spatrick struct omohci_softc { 1008eda2d14Spatrick struct ohci_softc sc; 1018eda2d14Spatrick void *sc_ihc0; 1028eda2d14Spatrick void *sc_ihc1; 1038eda2d14Spatrick void *sc_ihc2; 1048eda2d14Spatrick void *sc_ih0; 1058eda2d14Spatrick void *sc_ih1; 1068eda2d14Spatrick void *sc_ihotg; 1078eda2d14Spatrick }; 1088eda2d14Spatrick 1098eda2d14Spatrick void omohci_enable(struct omohci_softc *); 1108eda2d14Spatrick void omohci_disable(struct omohci_softc *); 1118eda2d14Spatrick 1129fdf0c62Smpi const struct cfattach omohci_ca = { 1138eda2d14Spatrick sizeof (struct omohci_softc), omohci_match, omohci_attach, 1148eda2d14Spatrick omohci_detach, omohci_detach 1158eda2d14Spatrick }; 1168eda2d14Spatrick 1178eda2d14Spatrick int 1188eda2d14Spatrick omohci_match(struct device *parent, void *match, void *aux) 1198eda2d14Spatrick { 1208eda2d14Spatrick #if 0 1218eda2d14Spatrick if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X) 1228eda2d14Spatrick return (0); 1238eda2d14Spatrick #endif 1248eda2d14Spatrick 1258eda2d14Spatrick return (1); 1268eda2d14Spatrick } 1278eda2d14Spatrick 1288eda2d14Spatrick void 1298eda2d14Spatrick omohci_attach(struct device *parent, struct device *self, void *aux) 1308eda2d14Spatrick { 1318eda2d14Spatrick struct omohci_softc *sc = (struct omohci_softc *)self; 1328eda2d14Spatrick struct ahb_attach_args *aa = aux; 1338eda2d14Spatrick usbd_status r; 1348eda2d14Spatrick 1358eda2d14Spatrick sc->sc.iot = aa->aa_iot; 1368eda2d14Spatrick sc->sc.sc_bus.dmatag = aa->aa_dmat; 1378eda2d14Spatrick sc->sc_ih0 = NULL; 1388eda2d14Spatrick sc->sc_ih1 = NULL; 1398eda2d14Spatrick sc->sc_ihc0 = NULL; 1408eda2d14Spatrick sc->sc_ihc1 = NULL; 1418eda2d14Spatrick sc->sc_ihc2 = NULL; 1428eda2d14Spatrick sc->sc_ihotg = NULL; 1438eda2d14Spatrick sc->sc.sc_size = 0; 1448eda2d14Spatrick 1458eda2d14Spatrick /* Map I/O space */ 1468eda2d14Spatrick if (bus_space_map(sc->sc.iot, aa->aa_addr, aa->aa_size, 0, 1478eda2d14Spatrick &sc->sc.ioh)) { 1488eda2d14Spatrick printf(": cannot map mem space\n"); 1498eda2d14Spatrick return; 1508eda2d14Spatrick } 1518eda2d14Spatrick sc->sc.sc_size = aa->aa_size; 1528eda2d14Spatrick 1538eda2d14Spatrick /* XXX copied from ohci_pci.c. needed? */ 1548eda2d14Spatrick bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, 1558eda2d14Spatrick BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 1568eda2d14Spatrick 1578eda2d14Spatrick #if 0 1588eda2d14Spatrick /* start the usb clock */ 1598eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 1); 1608eda2d14Spatrick #endif 1618eda2d14Spatrick omohci_enable(sc); 1628eda2d14Spatrick 1638eda2d14Spatrick /* Disable interrupts, so we don't get any spurious ones. */ 1648eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 1658eda2d14Spatrick OHCI_MIE); 1668eda2d14Spatrick 1678eda2d14Spatrick sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB, 1688eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1698eda2d14Spatrick sc->sc_ihc1 = arm_intr_establish(aa->aa_intr+1, IPL_USB, 1708eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1718eda2d14Spatrick sc->sc_ihc2 = arm_intr_establish(aa->aa_intr+2, IPL_USB, 1728eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1738eda2d14Spatrick sc->sc_ih0 = arm_intr_establish(aa->aa_intr+3, IPL_USB, 1748eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1758eda2d14Spatrick sc->sc_ih1 = arm_intr_establish(aa->aa_intr+4, IPL_USB, 1768eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1778eda2d14Spatrick sc->sc_ihotg = arm_intr_establish(aa->aa_intr+5, IPL_USB, 1788eda2d14Spatrick ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); 1798eda2d14Spatrick if (sc->sc_ih0 == NULL || 1808eda2d14Spatrick sc->sc_ih1 == NULL || 1818eda2d14Spatrick sc->sc_ihc0 == NULL || 1828eda2d14Spatrick sc->sc_ihc1 == NULL || 1838eda2d14Spatrick sc->sc_ihc2 == NULL || 1848eda2d14Spatrick sc->sc_ihotg == NULL) { 1858eda2d14Spatrick printf(": unable to establish interrupt\n"); 1868eda2d14Spatrick omohci_disable(sc); 1878eda2d14Spatrick #if 0 1888eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 0); 1898eda2d14Spatrick #endif 1908eda2d14Spatrick bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 1918eda2d14Spatrick sc->sc.sc_size = 0; 1928eda2d14Spatrick return; 1938eda2d14Spatrick } 1948eda2d14Spatrick 1958eda2d14Spatrick prcm_enablemodule(PRCM_USB); 1968eda2d14Spatrick 1978eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, OTG_SYSCON_2, 1988eda2d14Spatrick OTG_SYSCON2_UHOST_EN | OTG_SYSCON2_MODE_HOST); 1998eda2d14Spatrick 2008eda2d14Spatrick strlcpy(sc->sc.sc_vendor, "OMAP24xx", sizeof(sc->sc.sc_vendor)); 2018eda2d14Spatrick r = ohci_init(&sc->sc); 2028eda2d14Spatrick if (r != USBD_NORMAL_COMPLETION) { 2038eda2d14Spatrick printf("%s: init failed, error=%d\n", 2048eda2d14Spatrick sc->sc.sc_bus.bdev.dv_xname, r); 2058eda2d14Spatrick arm_intr_disestablish(sc->sc_ih0); 2068eda2d14Spatrick arm_intr_disestablish(sc->sc_ih1); 2078eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc0); 2088eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc1); 2098eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc2); 2108eda2d14Spatrick arm_intr_disestablish(sc->sc_ihotg); 2118eda2d14Spatrick sc->sc_ih0 = NULL; 2128eda2d14Spatrick sc->sc_ih1 = NULL; 2138eda2d14Spatrick sc->sc_ihc0 = NULL; 2148eda2d14Spatrick sc->sc_ihc1 = NULL; 2158eda2d14Spatrick sc->sc_ihc2 = NULL; 2168eda2d14Spatrick sc->sc_ihotg = NULL; 2178eda2d14Spatrick omohci_disable(sc); 2188eda2d14Spatrick #if 0 2198eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 0); 2208eda2d14Spatrick #endif 2218eda2d14Spatrick bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 2228eda2d14Spatrick sc->sc.sc_size = 0; 2238eda2d14Spatrick return; 2248eda2d14Spatrick } 2258eda2d14Spatrick 226ad21ef77Smpi config_found(self, &sc->sc.sc_bus, usbctlprint); 2278eda2d14Spatrick } 2288eda2d14Spatrick 2298eda2d14Spatrick int 2308eda2d14Spatrick omohci_detach(struct device *self, int flags) 2318eda2d14Spatrick { 2328eda2d14Spatrick struct omohci_softc *sc = (struct omohci_softc *)self; 2338eda2d14Spatrick int rv; 2348eda2d14Spatrick 235ad21ef77Smpi rv = ohci_detach(self, flags); 2368eda2d14Spatrick if (rv) 2378eda2d14Spatrick return (rv); 2388eda2d14Spatrick 2398eda2d14Spatrick if (sc->sc_ih0 != NULL) { 2408eda2d14Spatrick arm_intr_disestablish(sc->sc_ih0); 2418eda2d14Spatrick arm_intr_disestablish(sc->sc_ih1); 2428eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc0); 2438eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc1); 2448eda2d14Spatrick arm_intr_disestablish(sc->sc_ihc2); 2458eda2d14Spatrick arm_intr_disestablish(sc->sc_ihotg); 2468eda2d14Spatrick sc->sc_ih0 = NULL; 2478eda2d14Spatrick sc->sc_ih1 = NULL; 2488eda2d14Spatrick sc->sc_ihc0 = NULL; 2498eda2d14Spatrick sc->sc_ihc1 = NULL; 2508eda2d14Spatrick sc->sc_ihc2 = NULL; 2518eda2d14Spatrick sc->sc_ihotg = NULL; 2528eda2d14Spatrick } 2538eda2d14Spatrick 2548eda2d14Spatrick omohci_disable(sc); 2558eda2d14Spatrick 2568eda2d14Spatrick /* stop clock */ 2578eda2d14Spatrick #if 0 2588eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 0); 2598eda2d14Spatrick #endif 2608eda2d14Spatrick 2618eda2d14Spatrick if (sc->sc.sc_size) { 2628eda2d14Spatrick bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 2638eda2d14Spatrick sc->sc.sc_size = 0; 2648eda2d14Spatrick } 2658eda2d14Spatrick 2668eda2d14Spatrick return (0); 2678eda2d14Spatrick } 2688eda2d14Spatrick 2698eda2d14Spatrick 2708eda2d14Spatrick int 2718eda2d14Spatrick omohci_activate(struct device *self, int act) 2728eda2d14Spatrick { 2738eda2d14Spatrick struct omohci_softc *sc = (struct omohci_softc *)self; 274*ea05d060Sderaadt int rv; 2758eda2d14Spatrick 2768eda2d14Spatrick switch (act) { 2778eda2d14Spatrick case DVACT_SUSPEND: 2788eda2d14Spatrick sc->sc.sc_bus.use_polling++; 2798eda2d14Spatrick ohci_power(why, &sc->sc); 2808eda2d14Spatrick #if 0 2818eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 0); 2828eda2d14Spatrick #endif 2838eda2d14Spatrick sc->sc.sc_bus.use_polling--; 284*ea05d060Sderaadt rv = config_activate_children(self, act); 2858eda2d14Spatrick break; 2868eda2d14Spatrick 2878eda2d14Spatrick case DVACT_RESUME: 288*ea05d060Sderaadt rv = config_activate_children(self, act); 2898eda2d14Spatrick sc->sc.sc_bus.use_polling++; 2908eda2d14Spatrick #if 0 2918eda2d14Spatrick pxa2x0_clkman_config(CKEN_USBHC, 1); 2928eda2d14Spatrick #endif 2938eda2d14Spatrick omohci_enable(sc); 2948eda2d14Spatrick ohci_power(why, &sc->sc); 2958eda2d14Spatrick sc->sc.sc_bus.use_polling--; 2968eda2d14Spatrick break; 297*ea05d060Sderaadt default: 298*ea05d060Sderaadt rv = config_activate_children(self, act); 299*ea05d060Sderaadt break; 3008eda2d14Spatrick } 301*ea05d060Sderaadt return rv; 3028eda2d14Spatrick } 3038eda2d14Spatrick 3048eda2d14Spatrick void 3058eda2d14Spatrick omohci_enable(struct omohci_softc *sc) 3068eda2d14Spatrick { 3078eda2d14Spatrick #if 0 3088eda2d14Spatrick u_int32_t hr; 3098eda2d14Spatrick 3108eda2d14Spatrick /* Full host reset */ 3118eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3128eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3138eda2d14Spatrick (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 3148eda2d14Spatrick 3158eda2d14Spatrick DELAY(USBHC_RST_WAIT); 3168eda2d14Spatrick 3178eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3188eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3198eda2d14Spatrick (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 3208eda2d14Spatrick 3218eda2d14Spatrick /* Force system bus interface reset */ 3228eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3238eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3248eda2d14Spatrick (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); 3258eda2d14Spatrick 3268eda2d14Spatrick while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \ 3278eda2d14Spatrick USBHC_HR_FSBIR) 3288eda2d14Spatrick DELAY(3); 3298eda2d14Spatrick 3308eda2d14Spatrick /* Enable the ports (physically only one, only enable that one?) */ 3318eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3328eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3338eda2d14Spatrick (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); 3348eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3358eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3368eda2d14Spatrick (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2)); 3378eda2d14Spatrick #endif 3388eda2d14Spatrick } 3398eda2d14Spatrick 3408eda2d14Spatrick void 3418eda2d14Spatrick omohci_disable(struct omohci_softc *sc) 3428eda2d14Spatrick { 3438eda2d14Spatrick #if 0 3448eda2d14Spatrick u_int32_t hr; 3458eda2d14Spatrick 3468eda2d14Spatrick /* Full host reset */ 3478eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3488eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3498eda2d14Spatrick (hr & USBHC_HR_MASK) | USBHC_HR_FHR); 3508eda2d14Spatrick 3518eda2d14Spatrick DELAY(USBHC_RST_WAIT); 3528eda2d14Spatrick 3538eda2d14Spatrick hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); 3548eda2d14Spatrick bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, 3558eda2d14Spatrick (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); 3568eda2d14Spatrick #endif 3578eda2d14Spatrick } 358