ohci_atmelarm.c revision 184610
1184610Salfred/*- 2184610Salfred * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3184610Salfred * 4184610Salfred * Redistribution and use in source and binary forms, with or without 5184610Salfred * modification, are permitted provided that the following conditions 6184610Salfred * are met: 7184610Salfred * 1. Redistributions of source code must retain the above copyright 8184610Salfred * notice, this list of conditions and the following disclaimer. 9184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer in the 11184610Salfred * documentation and/or other materials provided with the distribution. 12184610Salfred * 13184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23184610Salfred */ 24184610Salfred 25184610Salfred#include <sys/cdefs.h> 26184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/controller/ohci2_atmelarm.c 184610 2008-11-04 02:31:03Z alfred $"); 27184610Salfred 28184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 29184610Salfred#include <dev/usb2/include/usb2_defs.h> 30184610Salfred#include <dev/usb2/include/usb2_standard.h> 31184610Salfred 32184610Salfred#include <dev/usb2/core/usb2_core.h> 33184610Salfred#include <dev/usb2/core/usb2_busdma.h> 34184610Salfred#include <dev/usb2/core/usb2_process.h> 35184610Salfred#include <dev/usb2/core/usb2_config_td.h> 36184610Salfred#include <dev/usb2/core/usb2_sw_transfer.h> 37184610Salfred#include <dev/usb2/core/usb2_util.h> 38184610Salfred 39184610Salfred#include <dev/usb2/controller/usb2_controller.h> 40184610Salfred#include <dev/usb2/controller/usb2_bus.h> 41184610Salfred#include <dev/usb2/controller/ohci2.h> 42184610Salfred 43184610Salfred#include <sys/rman.h> 44184610Salfred 45184610Salfred#include <arm/at91/at91_pmcvar.h> 46184610Salfred 47184610Salfred#define MEM_RID 0 48184610Salfred 49184610Salfredstatic device_probe_t ohci_atmelarm_probe; 50184610Salfredstatic device_attach_t ohci_atmelarm_attach; 51184610Salfredstatic device_detach_t ohci_atmelarm_detach; 52184610Salfred 53184610Salfredstruct at91_ohci_softc { 54184610Salfred struct ohci_softc sc_ohci; /* must be first */ 55184610Salfred struct at91_pmc_clock *iclk; 56184610Salfred struct at91_pmc_clock *fclk; 57184610Salfred}; 58184610Salfred 59184610Salfredstatic int 60184610Salfredohci_atmelarm_probe(device_t dev) 61184610Salfred{ 62184610Salfred device_set_desc(dev, "AT91 integrated OHCI controller"); 63184610Salfred return (BUS_PROBE_DEFAULT); 64184610Salfred} 65184610Salfred 66184610Salfredstatic int 67184610Salfredohci_atmelarm_attach(device_t dev) 68184610Salfred{ 69184610Salfred struct at91_ohci_softc *sc = device_get_softc(dev); 70184610Salfred int err; 71184610Salfred int rid; 72184610Salfred 73184610Salfred if (sc == NULL) { 74184610Salfred return (ENXIO); 75184610Salfred } 76184610Salfred /* get all DMA memory */ 77184610Salfred 78184610Salfred if (usb2_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, 79184610Salfred USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { 80184610Salfred return ENOMEM; 81184610Salfred } 82184610Salfred sc->iclk = at91_pmc_clock_ref("ohci_clk"); 83184610Salfred sc->fclk = at91_pmc_clock_ref("uhpck"); 84184610Salfred 85184610Salfred sc->sc_ohci.sc_dev = dev; 86184610Salfred 87184610Salfred rid = MEM_RID; 88184610Salfred sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 89184610Salfred &rid, RF_ACTIVE); 90184610Salfred 91184610Salfred if (!(sc->sc_ohci.sc_io_res)) { 92184610Salfred err = ENOMEM; 93184610Salfred goto error; 94184610Salfred } 95184610Salfred sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); 96184610Salfred sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); 97184610Salfred sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); 98184610Salfred 99184610Salfred rid = 0; 100184610Salfred sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 101184610Salfred RF_ACTIVE); 102184610Salfred if (!(sc->sc_ohci.sc_irq_res)) { 103184610Salfred goto error; 104184610Salfred } 105184610Salfred sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 106184610Salfred if (!(sc->sc_ohci.sc_bus.bdev)) { 107184610Salfred goto error; 108184610Salfred } 109184610Salfred device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); 110184610Salfred 111184610Salfred strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); 112184610Salfred 113184610Salfred err = usb2_config_td_setup(&sc->sc_ohci.sc_config_td, sc, 114184610Salfred &sc->sc_ohci.sc_bus.mtx, NULL, 0, 4); 115184610Salfred if (err) { 116184610Salfred device_printf(dev, "could not setup config thread!\n"); 117184610Salfred goto error; 118184610Salfred } 119184610Salfred#if (__FreeBSD_version >= 700031) 120184610Salfred err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 121184610Salfred NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); 122184610Salfred#else 123184610Salfred err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 124184610Salfred (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); 125184610Salfred#endif 126184610Salfred if (err) { 127184610Salfred sc->sc_ohci.sc_intr_hdl = NULL; 128184610Salfred goto error; 129184610Salfred } 130184610Salfred /* 131184610Salfred * turn on the clocks from the AT91's point of view. Keep the unit in reset. 132184610Salfred */ 133184610Salfred at91_pmc_clock_enable(sc->iclk); 134184610Salfred at91_pmc_clock_enable(sc->fclk); 135184610Salfred bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, 136184610Salfred OHCI_CONTROL, 0); 137184610Salfred 138184610Salfred err = ohci_init(&sc->sc_ohci); 139184610Salfred if (!err) { 140184610Salfred err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); 141184610Salfred } 142184610Salfred if (err) { 143184610Salfred goto error; 144184610Salfred } 145184610Salfred return (0); 146184610Salfred 147184610Salfrederror: 148184610Salfred ohci_atmelarm_detach(dev); 149184610Salfred return (ENXIO); 150184610Salfred} 151184610Salfred 152184610Salfredstatic int 153184610Salfredohci_atmelarm_detach(device_t dev) 154184610Salfred{ 155184610Salfred struct at91_ohci_softc *sc = device_get_softc(dev); 156184610Salfred device_t bdev; 157184610Salfred int err; 158184610Salfred 159184610Salfred if (sc->sc_ohci.sc_bus.bdev) { 160184610Salfred bdev = sc->sc_ohci.sc_bus.bdev; 161184610Salfred device_detach(bdev); 162184610Salfred device_delete_child(dev, bdev); 163184610Salfred } 164184610Salfred /* during module unload there are lots of children leftover */ 165184610Salfred device_delete_all_children(dev); 166184610Salfred 167184610Salfred /* 168184610Salfred * Put the controller into reset, then disable clocks and do 169184610Salfred * the MI tear down. We have to disable the clocks/hardware 170184610Salfred * after we do the rest of the teardown. We also disable the 171184610Salfred * clocks in the opposite order we acquire them, but that 172184610Salfred * doesn't seem to be absolutely necessary. We free up the 173184610Salfred * clocks after we disable them, so the system could, in 174184610Salfred * theory, reuse them. 175184610Salfred */ 176184610Salfred bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, 177184610Salfred OHCI_CONTROL, 0); 178184610Salfred 179184610Salfred at91_pmc_clock_disable(sc->fclk); 180184610Salfred at91_pmc_clock_disable(sc->iclk); 181184610Salfred at91_pmc_clock_deref(sc->fclk); 182184610Salfred at91_pmc_clock_deref(sc->iclk); 183184610Salfred 184184610Salfred if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { 185184610Salfred /* 186184610Salfred * only call ohci_detach() after ohci_init() 187184610Salfred */ 188184610Salfred ohci_detach(&sc->sc_ohci); 189184610Salfred 190184610Salfred err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); 191184610Salfred sc->sc_ohci.sc_intr_hdl = NULL; 192184610Salfred } 193184610Salfred if (sc->sc_ohci.sc_irq_res) { 194184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); 195184610Salfred sc->sc_ohci.sc_irq_res = NULL; 196184610Salfred } 197184610Salfred if (sc->sc_ohci.sc_io_res) { 198184610Salfred bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 199184610Salfred sc->sc_ohci.sc_io_res); 200184610Salfred sc->sc_ohci.sc_io_res = NULL; 201184610Salfred } 202184610Salfred usb2_config_td_unsetup(&sc->sc_ohci.sc_config_td); 203184610Salfred 204184610Salfred usb2_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); 205184610Salfred 206184610Salfred return (0); 207184610Salfred} 208184610Salfred 209184610Salfredstatic device_method_t ohci_methods[] = { 210184610Salfred /* Device interface */ 211184610Salfred DEVMETHOD(device_probe, ohci_atmelarm_probe), 212184610Salfred DEVMETHOD(device_attach, ohci_atmelarm_attach), 213184610Salfred DEVMETHOD(device_detach, ohci_atmelarm_detach), 214184610Salfred DEVMETHOD(device_shutdown, bus_generic_shutdown), 215184610Salfred 216184610Salfred /* Bus interface */ 217184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 218184610Salfred 219184610Salfred {0, 0} 220184610Salfred}; 221184610Salfred 222184610Salfredstatic driver_t ohci_driver = { 223184610Salfred "ohci", 224184610Salfred ohci_methods, 225184610Salfred sizeof(struct at91_ohci_softc), 226184610Salfred}; 227184610Salfred 228184610Salfredstatic devclass_t ohci_devclass; 229184610Salfred 230184610SalfredDRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0); 231184610SalfredMODULE_DEPEND(ohci, usb2_controller, 1, 1, 1); 232184610SalfredMODULE_DEPEND(ohci, usb2_core, 1, 1, 1); 233