at91_ohci.c revision 186439
1193323Sed/*- 2193323Sed * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3193323Sed * 4193323Sed * Redistribution and use in source and binary forms, with or without 5193323Sed * modification, are permitted provided that the following conditions 6193323Sed * are met: 7193323Sed * 1. Redistributions of source code must retain the above copyright 8193323Sed * notice, this list of conditions and the following disclaimer. 9193323Sed * 2. Redistributions in binary form must reproduce the above copyright 10193323Sed * notice, this list of conditions and the following disclaimer in the 11221345Sdim * documentation and/or other materials provided with the distribution. 12193323Sed * 13221345Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14193323Sed * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15193323Sed * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16193323Sed * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17193323Sed * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18249423Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19207618Srdivacky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20193323Sed * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21193323Sed * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22193323Sed * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23193323Sed */ 24234353Sdim 25193323Sed#include <sys/cdefs.h> 26210299Sed__FBSDID("$FreeBSD: head/sys/dev/usb2/controller/ohci2_atmelarm.c 186439 2008-12-23 17:36:25Z thompsa $"); 27193323Sed 28234353Sdim#include <dev/usb2/include/usb2_mfunc.h> 29193323Sed#include <dev/usb2/include/usb2_defs.h> 30193323Sed#include <dev/usb2/include/usb2_standard.h> 31193323Sed 32207618Srdivacky#include <dev/usb2/core/usb2_core.h> 33193323Sed#include <dev/usb2/core/usb2_busdma.h> 34193323Sed#include <dev/usb2/core/usb2_process.h> 35243830Sdim#include <dev/usb2/core/usb2_config_td.h> 36193323Sed#include <dev/usb2/core/usb2_sw_transfer.h> 37239462Sdim#include <dev/usb2/core/usb2_util.h> 38193323Sed 39193323Sed#include <dev/usb2/controller/usb2_controller.h> 40193323Sed#include <dev/usb2/controller/usb2_bus.h> 41210299Sed#include <dev/usb2/controller/ohci2.h> 42234353Sdim 43234353Sdim#include <sys/rman.h> 44193323Sed 45193323Sed#include <arm/at91/at91_pmcvar.h> 46193323Sed 47193323Sed#define MEM_RID 0 48193323Sed 49193323Sedstatic device_probe_t ohci_atmelarm_probe; 50193323Sedstatic device_attach_t ohci_atmelarm_attach; 51210299Sedstatic device_detach_t ohci_atmelarm_detach; 52193323Sed 53193323Sedstruct at91_ohci_softc { 54193323Sed struct ohci_softc sc_ohci; /* must be first */ 55193323Sed struct at91_pmc_clock *iclk; 56193323Sed struct at91_pmc_clock *fclk; 57243830Sdim}; 58193323Sed 59193323Sedstatic int 60210299Sedohci_atmelarm_probe(device_t dev) 61239462Sdim{ 62226633Sdim device_set_desc(dev, "AT91 integrated OHCI controller"); 63226633Sdim return (BUS_PROBE_DEFAULT); 64226633Sdim} 65226633Sdim 66226633Sdimstatic int 67210299Sedohci_atmelarm_attach(device_t dev) 68193323Sed{ 69226633Sdim struct at91_ohci_softc *sc = device_get_softc(dev); 70226633Sdim int err; 71226633Sdim int rid; 72226633Sdim 73226633Sdim if (sc == NULL) { 74193323Sed return (ENXIO); 75210299Sed } 76210299Sed /* get all DMA memory */ 77210299Sed 78210299Sed sc->sc_ohci.sc_bus.parent = dev; 79210299Sed if (usb2_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, 80210299Sed USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { 81226633Sdim return ENOMEM; 82226633Sdim } 83226633Sdim sc->iclk = at91_pmc_clock_ref("ohci_clk"); 84226633Sdim sc->fclk = at91_pmc_clock_ref("uhpck"); 85210299Sed 86193323Sed sc->sc_ohci.sc_dev = dev; 87193323Sed 88193323Sed rid = MEM_RID; 89210299Sed sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 90193323Sed &rid, RF_ACTIVE); 91193323Sed 92193323Sed if (!(sc->sc_ohci.sc_io_res)) { 93249423Sdim err = ENOMEM; 94249423Sdim goto error; 95249423Sdim } 96249423Sdim sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); 97249423Sdim sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); 98193323Sed sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); 99193323Sed 100193323Sed rid = 0; 101193323Sed sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 102193323Sed RF_ACTIVE); 103207618Srdivacky if (!(sc->sc_ohci.sc_irq_res)) { 104193323Sed goto error; 105198090Srdivacky } 106193323Sed sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 107193323Sed if (!(sc->sc_ohci.sc_bus.bdev)) { 108193323Sed goto error; 109193323Sed } 110207618Srdivacky device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); 111193323Sed 112193323Sed strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); 113193323Sed 114207618Srdivacky err = usb2_config_td_setup(&sc->sc_ohci.sc_config_td, sc, 115193323Sed &sc->sc_ohci.sc_bus.bus_mtx, NULL, 0, 4); 116193323Sed if (err) { 117193323Sed device_printf(dev, "could not setup config thread!\n"); 118193323Sed goto error; 119207618Srdivacky } 120193323Sed#if (__FreeBSD_version >= 700031) 121193323Sed err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 122193323Sed NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); 123193323Sed#else 124208599Srdivacky err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 125193323Sed (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); 126251662Sdim#endif 127251662Sdim if (err) { 128251662Sdim sc->sc_ohci.sc_intr_hdl = NULL; 129251662Sdim goto error; 130251662Sdim } 131251662Sdim /* 132251662Sdim * turn on the clocks from the AT91's point of view. Keep the unit in reset. 133251662Sdim */ 134251662Sdim at91_pmc_clock_enable(sc->iclk); 135251662Sdim at91_pmc_clock_enable(sc->fclk); 136251662Sdim bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, 137251662Sdim OHCI_CONTROL, 0); 138251662Sdim 139251662Sdim err = ohci_init(&sc->sc_ohci); 140251662Sdim if (!err) { 141251662Sdim err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); 142218893Sdim } 143218893Sdim if (err) { 144218893Sdim goto error; 145251662Sdim } 146251662Sdim return (0); 147251662Sdim 148218893Sdimerror: 149218893Sdim ohci_atmelarm_detach(dev); 150221345Sdim return (ENXIO); 151218893Sdim} 152210299Sed 153210299Sedstatic int 154210299Sedohci_atmelarm_detach(device_t dev) 155249423Sdim{ 156249423Sdim struct at91_ohci_softc *sc = device_get_softc(dev); 157249423Sdim device_t bdev; 158249423Sdim int err; 159210299Sed 160210299Sed if (sc->sc_ohci.sc_bus.bdev) { 161210299Sed bdev = sc->sc_ohci.sc_bus.bdev; 162210299Sed device_detach(bdev); 163210299Sed device_delete_child(dev, bdev); 164210299Sed } 165210299Sed /* during module unload there are lots of children leftover */ 166210299Sed device_delete_all_children(dev); 167210299Sed 168210299Sed /* 169210299Sed * Put the controller into reset, then disable clocks and do 170210299Sed * the MI tear down. We have to disable the clocks/hardware 171193323Sed * after we do the rest of the teardown. We also disable the 172193323Sed * clocks in the opposite order we acquire them, but that 173193323Sed * doesn't seem to be absolutely necessary. We free up the 174239462Sdim * clocks after we disable them, so the system could, in 175239462Sdim * theory, reuse them. 176193323Sed */ 177200581Srdivacky bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, 178200581Srdivacky OHCI_CONTROL, 0); 179200581Srdivacky 180200581Srdivacky at91_pmc_clock_disable(sc->fclk); 181200581Srdivacky at91_pmc_clock_disable(sc->iclk); 182200581Srdivacky at91_pmc_clock_deref(sc->fclk); 183207618Srdivacky at91_pmc_clock_deref(sc->iclk); 184249423Sdim 185249423Sdim if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { 186249423Sdim /* 187249423Sdim * only call ohci_detach() after ohci_init() 188249423Sdim */ 189200581Srdivacky ohci_detach(&sc->sc_ohci); 190193323Sed 191193323Sed err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); 192193323Sed sc->sc_ohci.sc_intr_hdl = NULL; 193198090Srdivacky } 194198090Srdivacky if (sc->sc_ohci.sc_irq_res) { 195202375Srdivacky bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); 196193323Sed sc->sc_ohci.sc_irq_res = NULL; 197193323Sed } 198193323Sed if (sc->sc_ohci.sc_io_res) { 199193323Sed bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 200193323Sed sc->sc_ohci.sc_io_res); 201198090Srdivacky sc->sc_ohci.sc_io_res = NULL; 202198090Srdivacky } 203208599Srdivacky usb2_config_td_unsetup(&sc->sc_ohci.sc_config_td); 204208599Srdivacky 205193323Sed usb2_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); 206193323Sed 207193323Sed return (0); 208193323Sed} 209193323Sed 210198090Srdivackystatic device_method_t ohci_methods[] = { 211198090Srdivacky /* Device interface */ 212202375Srdivacky DEVMETHOD(device_probe, ohci_atmelarm_probe), 213208599Srdivacky DEVMETHOD(device_attach, ohci_atmelarm_attach), 214208599Srdivacky DEVMETHOD(device_detach, ohci_atmelarm_detach), 215193323Sed DEVMETHOD(device_shutdown, bus_generic_shutdown), 216193323Sed 217193323Sed /* Bus interface */ 218193323Sed DEVMETHOD(bus_print_child, bus_generic_print_child), 219193323Sed 220198090Srdivacky {0, 0} 221198090Srdivacky}; 222202375Srdivacky 223208599Srdivackystatic driver_t ohci_driver = { 224208599Srdivacky "ohci", 225193323Sed ohci_methods, 226193323Sed sizeof(struct at91_ohci_softc), 227193323Sed}; 228193323Sed 229193323Sedstatic devclass_t ohci_devclass; 230198090Srdivacky 231198090SrdivackyDRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0); 232202375SrdivackyMODULE_DEPEND(ohci, usb2_controller, 1, 1, 1); 233208599SrdivackyMODULE_DEPEND(ohci, usb2_core, 1, 1, 1); 234208599Srdivacky