1*c49504beSRafal Jaworowski /*- 2*c49504beSRafal Jaworowski * Copyright (c) 2010-2012 Semihalf 3*c49504beSRafal Jaworowski * All rights reserved. 4*c49504beSRafal Jaworowski * 5*c49504beSRafal Jaworowski * Redistribution and use in source and binary forms, with or without 6*c49504beSRafal Jaworowski * modification, are permitted provided that the following conditions 7*c49504beSRafal Jaworowski * are met: 8*c49504beSRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 9*c49504beSRafal Jaworowski * notice, this list of conditions and the following disclaimer. 10*c49504beSRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 11*c49504beSRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 12*c49504beSRafal Jaworowski * documentation and/or other materials provided with the distribution. 13*c49504beSRafal Jaworowski * 14*c49504beSRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*c49504beSRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*c49504beSRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*c49504beSRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*c49504beSRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*c49504beSRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*c49504beSRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*c49504beSRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*c49504beSRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*c49504beSRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*c49504beSRafal Jaworowski * SUCH DAMAGE. 25*c49504beSRafal Jaworowski */ 26*c49504beSRafal Jaworowski 27*c49504beSRafal Jaworowski #include <sys/cdefs.h> 28*c49504beSRafal Jaworowski __FBSDID("$FreeBSD$"); 29*c49504beSRafal Jaworowski 30*c49504beSRafal Jaworowski #include "opt_bus.h" 31*c49504beSRafal Jaworowski 32*c49504beSRafal Jaworowski #include <sys/param.h> 33*c49504beSRafal Jaworowski #include <sys/systm.h> 34*c49504beSRafal Jaworowski #include <sys/kernel.h> 35*c49504beSRafal Jaworowski #include <sys/module.h> 36*c49504beSRafal Jaworowski #include <sys/bus.h> 37*c49504beSRafal Jaworowski #include <sys/queue.h> 38*c49504beSRafal Jaworowski #include <sys/lock.h> 39*c49504beSRafal Jaworowski #include <sys/lockmgr.h> 40*c49504beSRafal Jaworowski #include <sys/condvar.h> 41*c49504beSRafal Jaworowski #include <sys/rman.h> 42*c49504beSRafal Jaworowski 43*c49504beSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 44*c49504beSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 45*c49504beSRafal Jaworowski 46*c49504beSRafal Jaworowski #include <dev/usb/usb.h> 47*c49504beSRafal Jaworowski #include <dev/usb/usbdi.h> 48*c49504beSRafal Jaworowski #include <dev/usb/usb_core.h> 49*c49504beSRafal Jaworowski #include <dev/usb/usb_busdma.h> 50*c49504beSRafal Jaworowski #include <dev/usb/usb_process.h> 51*c49504beSRafal Jaworowski #include <dev/usb/usb_util.h> 52*c49504beSRafal Jaworowski #include <dev/usb/usb_controller.h> 53*c49504beSRafal Jaworowski #include <dev/usb/usb_bus.h> 54*c49504beSRafal Jaworowski #include <dev/usb/controller/ehci.h> 55*c49504beSRafal Jaworowski #include <dev/usb/controller/ehcireg.h> 56*c49504beSRafal Jaworowski 57*c49504beSRafal Jaworowski #include <machine/bus.h> 58*c49504beSRafal Jaworowski #include <machine/clock.h> 59*c49504beSRafal Jaworowski #include <machine/resource.h> 60*c49504beSRafal Jaworowski 61*c49504beSRafal Jaworowski #include <powerpc/include/tlb.h> 62*c49504beSRafal Jaworowski 63*c49504beSRafal Jaworowski #include "opt_platform.h" 64*c49504beSRafal Jaworowski 65*c49504beSRafal Jaworowski /* 66*c49504beSRafal Jaworowski * Register the driver 67*c49504beSRafal Jaworowski */ 68*c49504beSRafal Jaworowski /* Forward declarations */ 69*c49504beSRafal Jaworowski static int fsl_ehci_attach(device_t self); 70*c49504beSRafal Jaworowski static int fsl_ehci_detach(device_t self); 71*c49504beSRafal Jaworowski static int fsl_ehci_probe(device_t self); 72*c49504beSRafal Jaworowski 73*c49504beSRafal Jaworowski static device_method_t ehci_methods[] = { 74*c49504beSRafal Jaworowski /* Device interface */ 75*c49504beSRafal Jaworowski DEVMETHOD(device_probe, fsl_ehci_probe), 76*c49504beSRafal Jaworowski DEVMETHOD(device_attach, fsl_ehci_attach), 77*c49504beSRafal Jaworowski DEVMETHOD(device_detach, fsl_ehci_detach), 78*c49504beSRafal Jaworowski DEVMETHOD(device_suspend, bus_generic_suspend), 79*c49504beSRafal Jaworowski DEVMETHOD(device_resume, bus_generic_resume), 80*c49504beSRafal Jaworowski DEVMETHOD(device_shutdown, bus_generic_shutdown), 81*c49504beSRafal Jaworowski 82*c49504beSRafal Jaworowski /* Bus interface */ 83*c49504beSRafal Jaworowski DEVMETHOD(bus_print_child, bus_generic_print_child), 84*c49504beSRafal Jaworowski 85*c49504beSRafal Jaworowski { 0, 0 } 86*c49504beSRafal Jaworowski }; 87*c49504beSRafal Jaworowski 88*c49504beSRafal Jaworowski /* kobj_class definition */ 89*c49504beSRafal Jaworowski static driver_t ehci_driver = { 90*c49504beSRafal Jaworowski "ehci", 91*c49504beSRafal Jaworowski ehci_methods, 92*c49504beSRafal Jaworowski sizeof(struct ehci_softc) 93*c49504beSRafal Jaworowski }; 94*c49504beSRafal Jaworowski 95*c49504beSRafal Jaworowski static devclass_t ehci_devclass; 96*c49504beSRafal Jaworowski 97*c49504beSRafal Jaworowski DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 98*c49504beSRafal Jaworowski MODULE_DEPEND(ehci, usb, 1, 1, 1); 99*c49504beSRafal Jaworowski 100*c49504beSRafal Jaworowski /* 101*c49504beSRafal Jaworowski * Private defines 102*c49504beSRafal Jaworowski */ 103*c49504beSRafal Jaworowski #define FSL_EHCI_REG_OFF 0x100 104*c49504beSRafal Jaworowski #define FSL_EHCI_REG_SIZE 0x300 105*c49504beSRafal Jaworowski 106*c49504beSRafal Jaworowski /* 107*c49504beSRafal Jaworowski * Internal interface registers' offsets. 108*c49504beSRafal Jaworowski * Offsets from 0x000 ehci dev space, big-endian access. 109*c49504beSRafal Jaworowski */ 110*c49504beSRafal Jaworowski enum internal_reg { 111*c49504beSRafal Jaworowski SNOOP1 = 0x400, 112*c49504beSRafal Jaworowski SNOOP2 = 0x404, 113*c49504beSRafal Jaworowski AGE_CNT_THRESH = 0x408, 114*c49504beSRafal Jaworowski SI_CTRL = 0x410, 115*c49504beSRafal Jaworowski CONTROL = 0x500 116*c49504beSRafal Jaworowski }; 117*c49504beSRafal Jaworowski 118*c49504beSRafal Jaworowski /* CONTROL register bit flags */ 119*c49504beSRafal Jaworowski enum control_flags { 120*c49504beSRafal Jaworowski USB_EN = 0x00000004, 121*c49504beSRafal Jaworowski UTMI_PHY_EN = 0x00000200, 122*c49504beSRafal Jaworowski ULPI_INT_EN = 0x00000001 123*c49504beSRafal Jaworowski }; 124*c49504beSRafal Jaworowski 125*c49504beSRafal Jaworowski /* SI_CTRL register bit flags */ 126*c49504beSRafal Jaworowski enum si_ctrl_flags { 127*c49504beSRafal Jaworowski FETCH_32 = 1, 128*c49504beSRafal Jaworowski FETCH_64 = 0 129*c49504beSRafal Jaworowski }; 130*c49504beSRafal Jaworowski 131*c49504beSRafal Jaworowski #define SNOOP_RANGE_2GB 0x1E 132*c49504beSRafal Jaworowski 133*c49504beSRafal Jaworowski /* 134*c49504beSRafal Jaworowski * Operational registers' offsets. 135*c49504beSRafal Jaworowski * Offsets from USBCMD register, little-endian access. 136*c49504beSRafal Jaworowski */ 137*c49504beSRafal Jaworowski enum special_op_reg { 138*c49504beSRafal Jaworowski USBMODE = 0x0A8, 139*c49504beSRafal Jaworowski PORTSC = 0x084, 140*c49504beSRafal Jaworowski ULPI_VIEWPORT = 0x70 141*c49504beSRafal Jaworowski }; 142*c49504beSRafal Jaworowski 143*c49504beSRafal Jaworowski /* USBMODE register bit flags */ 144*c49504beSRafal Jaworowski enum usbmode_flags { 145*c49504beSRafal Jaworowski HOST_MODE = 0x3, 146*c49504beSRafal Jaworowski DEVICE_MODE = 0x2 147*c49504beSRafal Jaworowski }; 148*c49504beSRafal Jaworowski 149*c49504beSRafal Jaworowski #define PORT_POWER_MASK 0x00001000 150*c49504beSRafal Jaworowski 151*c49504beSRafal Jaworowski /* 152*c49504beSRafal Jaworowski * Private methods 153*c49504beSRafal Jaworowski */ 154*c49504beSRafal Jaworowski 155*c49504beSRafal Jaworowski static void 156*c49504beSRafal Jaworowski set_to_host_mode(ehci_softc_t *sc) 157*c49504beSRafal Jaworowski { 158*c49504beSRafal Jaworowski int tmp; 159*c49504beSRafal Jaworowski 160*c49504beSRafal Jaworowski tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE); 161*c49504beSRafal Jaworowski bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE, tmp | HOST_MODE); 162*c49504beSRafal Jaworowski } 163*c49504beSRafal Jaworowski 164*c49504beSRafal Jaworowski static void 165*c49504beSRafal Jaworowski enable_usb(device_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) 166*c49504beSRafal Jaworowski { 167*c49504beSRafal Jaworowski int tmp; 168*c49504beSRafal Jaworowski phandle_t node; 169*c49504beSRafal Jaworowski char *phy_type; 170*c49504beSRafal Jaworowski 171*c49504beSRafal Jaworowski phy_type = NULL; 172*c49504beSRafal Jaworowski tmp = bus_space_read_4(iot, ioh, CONTROL) | USB_EN; 173*c49504beSRafal Jaworowski 174*c49504beSRafal Jaworowski node = ofw_bus_get_node(dev); 175*c49504beSRafal Jaworowski if ((node != 0) && 176*c49504beSRafal Jaworowski (OF_getprop_alloc(node, "phy_type", 1, (void **)&phy_type) > 0)) { 177*c49504beSRafal Jaworowski if (strncasecmp(phy_type, "utmi", strlen("utmi")) == 0) 178*c49504beSRafal Jaworowski tmp |= UTMI_PHY_EN; 179*c49504beSRafal Jaworowski free(phy_type, M_OFWPROP); 180*c49504beSRafal Jaworowski } 181*c49504beSRafal Jaworowski bus_space_write_4(iot, ioh, CONTROL, tmp); 182*c49504beSRafal Jaworowski } 183*c49504beSRafal Jaworowski 184*c49504beSRafal Jaworowski static void 185*c49504beSRafal Jaworowski set_32b_prefetch(bus_space_tag_t iot, bus_space_handle_t ioh) 186*c49504beSRafal Jaworowski { 187*c49504beSRafal Jaworowski 188*c49504beSRafal Jaworowski bus_space_write_4(iot, ioh, SI_CTRL, FETCH_32); 189*c49504beSRafal Jaworowski } 190*c49504beSRafal Jaworowski 191*c49504beSRafal Jaworowski static void 192*c49504beSRafal Jaworowski set_snooping(bus_space_tag_t iot, bus_space_handle_t ioh) 193*c49504beSRafal Jaworowski { 194*c49504beSRafal Jaworowski 195*c49504beSRafal Jaworowski bus_space_write_4(iot, ioh, SNOOP1, SNOOP_RANGE_2GB); 196*c49504beSRafal Jaworowski bus_space_write_4(iot, ioh, SNOOP2, 0x80000000 | SNOOP_RANGE_2GB); 197*c49504beSRafal Jaworowski } 198*c49504beSRafal Jaworowski 199*c49504beSRafal Jaworowski static void 200*c49504beSRafal Jaworowski clear_port_power(ehci_softc_t *sc) 201*c49504beSRafal Jaworowski { 202*c49504beSRafal Jaworowski int tmp; 203*c49504beSRafal Jaworowski 204*c49504beSRafal Jaworowski tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC); 205*c49504beSRafal Jaworowski bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC, tmp & ~PORT_POWER_MASK); 206*c49504beSRafal Jaworowski } 207*c49504beSRafal Jaworowski 208*c49504beSRafal Jaworowski /* 209*c49504beSRafal Jaworowski * Public methods 210*c49504beSRafal Jaworowski */ 211*c49504beSRafal Jaworowski static int 212*c49504beSRafal Jaworowski fsl_ehci_probe(device_t dev) 213*c49504beSRafal Jaworowski { 214*c49504beSRafal Jaworowski 215*c49504beSRafal Jaworowski if (((ofw_bus_is_compatible(dev, "fsl-usb2-dr")) == 0) && 216*c49504beSRafal Jaworowski ((ofw_bus_is_compatible(dev, "fsl-usb2-mph")) == 0)) 217*c49504beSRafal Jaworowski return (ENXIO); 218*c49504beSRafal Jaworowski 219*c49504beSRafal Jaworowski device_set_desc(dev, "Freescale integrated EHCI controller"); 220*c49504beSRafal Jaworowski 221*c49504beSRafal Jaworowski return (BUS_PROBE_DEFAULT); 222*c49504beSRafal Jaworowski } 223*c49504beSRafal Jaworowski 224*c49504beSRafal Jaworowski static int 225*c49504beSRafal Jaworowski fsl_ehci_attach(device_t self) 226*c49504beSRafal Jaworowski { 227*c49504beSRafal Jaworowski ehci_softc_t *sc; 228*c49504beSRafal Jaworowski int rid; 229*c49504beSRafal Jaworowski int err; 230*c49504beSRafal Jaworowski bus_space_handle_t ioh; 231*c49504beSRafal Jaworowski bus_space_tag_t iot; 232*c49504beSRafal Jaworowski 233*c49504beSRafal Jaworowski sc = device_get_softc(self); 234*c49504beSRafal Jaworowski rid = 0; 235*c49504beSRafal Jaworowski 236*c49504beSRafal Jaworowski sc->sc_bus.parent = self; 237*c49504beSRafal Jaworowski sc->sc_bus.devices = sc->sc_devices; 238*c49504beSRafal Jaworowski sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 239*c49504beSRafal Jaworowski 240*c49504beSRafal Jaworowski if (usb_bus_mem_alloc_all(&sc->sc_bus, 241*c49504beSRafal Jaworowski USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) 242*c49504beSRafal Jaworowski return (ENOMEM); 243*c49504beSRafal Jaworowski 244*c49504beSRafal Jaworowski /* Allocate io resource for EHCI */ 245*c49504beSRafal Jaworowski sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 246*c49504beSRafal Jaworowski RF_ACTIVE); 247*c49504beSRafal Jaworowski if (sc->sc_io_res == NULL) { 248*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 249*c49504beSRafal Jaworowski if (err) { 250*c49504beSRafal Jaworowski device_printf(self, 251*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 252*c49504beSRafal Jaworowski err); 253*c49504beSRafal Jaworowski } 254*c49504beSRafal Jaworowski return (ENXIO); 255*c49504beSRafal Jaworowski } 256*c49504beSRafal Jaworowski iot = rman_get_bustag(sc->sc_io_res); 257*c49504beSRafal Jaworowski 258*c49504beSRafal Jaworowski /* 259*c49504beSRafal Jaworowski * Set handle to USB related registers subregion used by generic 260*c49504beSRafal Jaworowski * EHCI driver 261*c49504beSRafal Jaworowski */ 262*c49504beSRafal Jaworowski ioh = rman_get_bushandle(sc->sc_io_res); 263*c49504beSRafal Jaworowski 264*c49504beSRafal Jaworowski err = bus_space_subregion(iot, ioh, FSL_EHCI_REG_OFF, FSL_EHCI_REG_SIZE, 265*c49504beSRafal Jaworowski &sc->sc_io_hdl); 266*c49504beSRafal Jaworowski if (err != 0) { 267*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 268*c49504beSRafal Jaworowski if (err) { 269*c49504beSRafal Jaworowski device_printf(self, 270*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 271*c49504beSRafal Jaworowski err); 272*c49504beSRafal Jaworowski } 273*c49504beSRafal Jaworowski return (ENXIO); 274*c49504beSRafal Jaworowski } 275*c49504beSRafal Jaworowski 276*c49504beSRafal Jaworowski /* Set little-endian tag for use by the generic EHCI driver */ 277*c49504beSRafal Jaworowski sc->sc_io_tag = &bs_le_tag; 278*c49504beSRafal Jaworowski 279*c49504beSRafal Jaworowski /* Allocate irq */ 280*c49504beSRafal Jaworowski sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 281*c49504beSRafal Jaworowski RF_ACTIVE); 282*c49504beSRafal Jaworowski if (sc->sc_irq_res == NULL) { 283*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 284*c49504beSRafal Jaworowski if (err) { 285*c49504beSRafal Jaworowski device_printf(self, 286*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 287*c49504beSRafal Jaworowski err); 288*c49504beSRafal Jaworowski } 289*c49504beSRafal Jaworowski return (ENXIO); 290*c49504beSRafal Jaworowski } 291*c49504beSRafal Jaworowski 292*c49504beSRafal Jaworowski /* Setup interrupt handler */ 293*c49504beSRafal Jaworowski err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO, 294*c49504beSRafal Jaworowski NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 295*c49504beSRafal Jaworowski if (err) { 296*c49504beSRafal Jaworowski device_printf(self, "Could not setup irq, %d\n", err); 297*c49504beSRafal Jaworowski sc->sc_intr_hdl = NULL; 298*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 299*c49504beSRafal Jaworowski if (err) { 300*c49504beSRafal Jaworowski device_printf(self, 301*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 302*c49504beSRafal Jaworowski err); 303*c49504beSRafal Jaworowski } 304*c49504beSRafal Jaworowski return (ENXIO); 305*c49504beSRafal Jaworowski } 306*c49504beSRafal Jaworowski 307*c49504beSRafal Jaworowski /* Add USB device */ 308*c49504beSRafal Jaworowski sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 309*c49504beSRafal Jaworowski if (!sc->sc_bus.bdev) { 310*c49504beSRafal Jaworowski device_printf(self, "Could not add USB device\n"); 311*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 312*c49504beSRafal Jaworowski if (err) { 313*c49504beSRafal Jaworowski device_printf(self, 314*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 315*c49504beSRafal Jaworowski err); 316*c49504beSRafal Jaworowski } 317*c49504beSRafal Jaworowski return (ENOMEM); 318*c49504beSRafal Jaworowski } 319*c49504beSRafal Jaworowski device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 320*c49504beSRafal Jaworowski 321*c49504beSRafal Jaworowski sc->sc_id_vendor = 0x1234; 322*c49504beSRafal Jaworowski strlcpy(sc->sc_vendor, "Freescale", sizeof(sc->sc_vendor)); 323*c49504beSRafal Jaworowski 324*c49504beSRafal Jaworowski /* Enable USB */ 325*c49504beSRafal Jaworowski err = ehci_reset(sc); 326*c49504beSRafal Jaworowski if (err) { 327*c49504beSRafal Jaworowski device_printf(self, "Could not reset the controller\n"); 328*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 329*c49504beSRafal Jaworowski if (err) { 330*c49504beSRafal Jaworowski device_printf(self, 331*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 332*c49504beSRafal Jaworowski err); 333*c49504beSRafal Jaworowski } 334*c49504beSRafal Jaworowski return (ENXIO); 335*c49504beSRafal Jaworowski } 336*c49504beSRafal Jaworowski 337*c49504beSRafal Jaworowski enable_usb(self, iot, ioh); 338*c49504beSRafal Jaworowski set_snooping(iot, ioh); 339*c49504beSRafal Jaworowski set_to_host_mode(sc); 340*c49504beSRafal Jaworowski set_32b_prefetch(iot, ioh); 341*c49504beSRafal Jaworowski 342*c49504beSRafal Jaworowski /* 343*c49504beSRafal Jaworowski * If usb subsystem is enabled in U-Boot, port power has to be turned 344*c49504beSRafal Jaworowski * off to allow proper discovery of devices during boot up. 345*c49504beSRafal Jaworowski */ 346*c49504beSRafal Jaworowski clear_port_power(sc); 347*c49504beSRafal Jaworowski 348*c49504beSRafal Jaworowski /* Set flags */ 349*c49504beSRafal Jaworowski sc->sc_flags |= EHCI_SCFLG_DONTRESET | EHCI_SCFLG_NORESTERM; 350*c49504beSRafal Jaworowski 351*c49504beSRafal Jaworowski err = ehci_init(sc); 352*c49504beSRafal Jaworowski if (!err) { 353*c49504beSRafal Jaworowski sc->sc_flags |= EHCI_SCFLG_DONEINIT; 354*c49504beSRafal Jaworowski err = device_probe_and_attach(sc->sc_bus.bdev); 355*c49504beSRafal Jaworowski } 356*c49504beSRafal Jaworowski 357*c49504beSRafal Jaworowski if (err) { 358*c49504beSRafal Jaworowski device_printf(self, "USB init failed err=%d\n", err); 359*c49504beSRafal Jaworowski err = fsl_ehci_detach(self); 360*c49504beSRafal Jaworowski if (err) { 361*c49504beSRafal Jaworowski device_printf(self, 362*c49504beSRafal Jaworowski "Detach of the driver failed with error %d\n", 363*c49504beSRafal Jaworowski err); 364*c49504beSRafal Jaworowski } 365*c49504beSRafal Jaworowski return (EIO); 366*c49504beSRafal Jaworowski } 367*c49504beSRafal Jaworowski 368*c49504beSRafal Jaworowski return (0); 369*c49504beSRafal Jaworowski } 370*c49504beSRafal Jaworowski 371*c49504beSRafal Jaworowski static int 372*c49504beSRafal Jaworowski fsl_ehci_detach(device_t self) 373*c49504beSRafal Jaworowski { 374*c49504beSRafal Jaworowski 375*c49504beSRafal Jaworowski int err; 376*c49504beSRafal Jaworowski ehci_softc_t *sc; 377*c49504beSRafal Jaworowski 378*c49504beSRafal Jaworowski sc = device_get_softc(self); 379*c49504beSRafal Jaworowski /* 380*c49504beSRafal Jaworowski * only call ehci_detach() after ehci_init() 381*c49504beSRafal Jaworowski */ 382*c49504beSRafal Jaworowski if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { 383*c49504beSRafal Jaworowski ehci_detach(sc); 384*c49504beSRafal Jaworowski sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; 385*c49504beSRafal Jaworowski } 386*c49504beSRafal Jaworowski 387*c49504beSRafal Jaworowski /* Disable interrupts that might have been switched on in ehci_init */ 388*c49504beSRafal Jaworowski if (sc->sc_io_tag && sc->sc_io_hdl) 389*c49504beSRafal Jaworowski bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, EHCI_USBINTR, 0); 390*c49504beSRafal Jaworowski 391*c49504beSRafal Jaworowski if (sc->sc_irq_res && sc->sc_intr_hdl) { 392*c49504beSRafal Jaworowski err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 393*c49504beSRafal Jaworowski if (err) { 394*c49504beSRafal Jaworowski device_printf(self, "Could not tear down irq, %d\n", 395*c49504beSRafal Jaworowski err); 396*c49504beSRafal Jaworowski return (err); 397*c49504beSRafal Jaworowski } 398*c49504beSRafal Jaworowski sc->sc_intr_hdl = NULL; 399*c49504beSRafal Jaworowski } 400*c49504beSRafal Jaworowski 401*c49504beSRafal Jaworowski if (sc->sc_bus.bdev) { 402*c49504beSRafal Jaworowski device_delete_child(self, sc->sc_bus.bdev); 403*c49504beSRafal Jaworowski sc->sc_bus.bdev = NULL; 404*c49504beSRafal Jaworowski } 405*c49504beSRafal Jaworowski 406*c49504beSRafal Jaworowski /* During module unload there are lots of children leftover */ 407*c49504beSRafal Jaworowski device_delete_children(self); 408*c49504beSRafal Jaworowski 409*c49504beSRafal Jaworowski if (sc->sc_irq_res) { 410*c49504beSRafal Jaworowski bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 411*c49504beSRafal Jaworowski sc->sc_irq_res = NULL; 412*c49504beSRafal Jaworowski } 413*c49504beSRafal Jaworowski 414*c49504beSRafal Jaworowski if (sc->sc_io_res) { 415*c49504beSRafal Jaworowski bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); 416*c49504beSRafal Jaworowski sc->sc_io_res = NULL; 417*c49504beSRafal Jaworowski sc->sc_io_tag = 0; 418*c49504beSRafal Jaworowski sc->sc_io_hdl = 0; 419*c49504beSRafal Jaworowski } 420*c49504beSRafal Jaworowski 421*c49504beSRafal Jaworowski return (0); 422*c49504beSRafal Jaworowski } 423*c49504beSRafal Jaworowski 424