The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/atheros/ar71xx_ehci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2008 Sam Leffler.  All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23  */
   24 
   25 /*
   26  * AR71XX attachment driver for the USB Enhanced Host Controller.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/11.1/sys/mips/atheros/ar71xx_ehci.c 308401 2016-11-07 08:36:06Z hselasky $");
   31 
   32 #include "opt_bus.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/rman.h>
   38 #include <sys/condvar.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 
   42 #include <machine/bus.h>
   43 
   44 #include <dev/usb/usb.h>
   45 #include <dev/usb/usbdi.h>
   46 
   47 #include <dev/usb/usb_core.h>
   48 #include <dev/usb/usb_busdma.h>
   49 #include <dev/usb/usb_process.h>
   50 #include <dev/usb/usb_util.h>
   51 
   52 #include <dev/usb/usb_controller.h>
   53 #include <dev/usb/usb_bus.h>
   54 #include <dev/usb/controller/ehci.h>
   55 #include <dev/usb/controller/ehcireg.h>
   56 
   57 #include <mips/atheros/ar71xx_setup.h>
   58 #include <mips/atheros/ar71xxreg.h> /* for stuff in ar71xx_cpudef.h */
   59 #include <mips/atheros/ar71xx_cpudef.h>
   60 #include <mips/atheros/ar71xx_bus_space_reversed.h>
   61 
   62 #define EHCI_HC_DEVSTR          "AR71XX Integrated USB 2.0 controller"
   63 
   64 #define EHCI_USBMODE            0x68    /* USB Device mode register */
   65 #define EHCI_UM_CM              0x00000003      /* R/WO Controller Mode */
   66 #define EHCI_UM_CM_HOST         0x3     /* Host Controller */
   67 
   68 struct ar71xx_ehci_softc {
   69         ehci_softc_t            base;   /* storage for EHCI code */
   70 };
   71 
   72 static device_attach_t ar71xx_ehci_attach;
   73 static device_detach_t ar71xx_ehci_detach;
   74 
   75 bs_r_1_proto(reversed);
   76 bs_w_1_proto(reversed);
   77 
   78 static void
   79 ar71xx_ehci_post_reset(struct ehci_softc *ehci_softc)
   80 {
   81         uint32_t usbmode;
   82 
   83         /* Force HOST mode */
   84         usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
   85         usbmode &= ~EHCI_UM_CM;
   86         usbmode |= EHCI_UM_CM_HOST;
   87         EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
   88 }
   89 
   90 static int
   91 ar71xx_ehci_probe(device_t self)
   92 {
   93 
   94         device_set_desc(self, EHCI_HC_DEVSTR);
   95 
   96         return (BUS_PROBE_NOWILDCARD);
   97 }
   98 
   99 static void
  100 ar71xx_ehci_intr(void *arg)
  101 {
  102 
  103         /* XXX TODO: should really see if this was our interrupt.. */
  104         ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB);
  105         ehci_interrupt(arg);
  106 }
  107 
  108 static int
  109 ar71xx_ehci_attach(device_t self)
  110 {
  111         struct ar71xx_ehci_softc *isc = device_get_softc(self);
  112         ehci_softc_t *sc = &isc->base;
  113         int err;
  114         int rid;
  115 
  116         /* initialise some bus fields */
  117         sc->sc_bus.parent = self;
  118         sc->sc_bus.devices = sc->sc_devices;
  119         sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
  120         sc->sc_bus.dma_bits = 32;
  121 
  122         /* get all DMA memory */
  123         if (usb_bus_mem_alloc_all(&sc->sc_bus,
  124             USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
  125                 return (ENOMEM);
  126         }
  127 
  128         sc->sc_bus.usbrev = USB_REV_2_0;
  129 
  130         /* NB: hints fix the memory location and irq */
  131 
  132         rid = 0;
  133         sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  134         if (!sc->sc_io_res) {
  135                 device_printf(self, "Could not map memory\n");
  136                 goto error;
  137         }
  138 
  139         /*
  140          * Craft special resource for bus space ops that handle
  141          * byte-alignment of non-word addresses.  
  142          */
  143         sc->sc_io_tag = ar71xx_bus_space_reversed;
  144         sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
  145         sc->sc_io_size = rman_get_size(sc->sc_io_res);
  146 
  147         rid = 0;
  148         sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
  149             RF_ACTIVE | RF_SHAREABLE);
  150         if (sc->sc_irq_res == NULL) {
  151                 device_printf(self, "Could not allocate irq\n");
  152                 goto error;
  153         }
  154         sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
  155         if (!sc->sc_bus.bdev) {
  156                 device_printf(self, "Could not add USB device\n");
  157                 goto error;
  158         }
  159         device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
  160         device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
  161 
  162         sprintf(sc->sc_vendor, "Atheros");
  163 
  164         err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
  165             NULL, ar71xx_ehci_intr, sc, &sc->sc_intr_hdl);
  166         if (err) {
  167                 device_printf(self, "Could not setup irq, %d\n", err);
  168                 sc->sc_intr_hdl = NULL;
  169                 goto error;
  170         }
  171 
  172         /*
  173          * Arrange to force Host mode, select big-endian byte alignment,
  174          * and arrange to not terminate reset operations (the adapter
  175          * will ignore it if we do but might as well save a reg write).
  176          * Also, the controller has an embedded Transaction Translator
  177          * which means port speed must be read from the Port Status
  178          * register following a port enable.
  179          */
  180         sc->sc_flags = 0;
  181         sc->sc_vendor_post_reset = ar71xx_ehci_post_reset;
  182 
  183         switch (ar71xx_soc) {
  184                 case AR71XX_SOC_AR7241:
  185                 case AR71XX_SOC_AR7242:
  186                 case AR71XX_SOC_AR9130:
  187                 case AR71XX_SOC_AR9132:
  188                 case AR71XX_SOC_AR9330:
  189                 case AR71XX_SOC_AR9331:
  190                 case AR71XX_SOC_AR9341:
  191                 case AR71XX_SOC_AR9342:
  192                 case AR71XX_SOC_AR9344:
  193                 case AR71XX_SOC_QCA9533:
  194                 case AR71XX_SOC_QCA9533_V2:
  195                 case AR71XX_SOC_QCA9556:
  196                 case AR71XX_SOC_QCA9558:
  197                         sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
  198                         sc->sc_vendor_get_port_speed =
  199                             ehci_get_port_speed_portsc;
  200                         break;
  201                 default:
  202                         /* fallthrough */
  203                         break;
  204         }
  205 
  206         /*
  207          * ehci_reset() needs the correct offset to access the host controller
  208          * registers. The AR724x/AR913x offsets aren't 0.
  209         */
  210         sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION));
  211 
  212         (void) ehci_reset(sc);
  213 
  214         err = ehci_init(sc);
  215         if (!err) {
  216                 err = device_probe_and_attach(sc->sc_bus.bdev);
  217         }
  218         if (err) {
  219                 device_printf(self, "USB init failed err=%d\n", err);
  220                 goto error;
  221         }
  222         return (0);
  223 
  224 error:
  225         ar71xx_ehci_detach(self);
  226         return (ENXIO);
  227 }
  228 
  229 static int
  230 ar71xx_ehci_detach(device_t self)
  231 {
  232         struct ar71xx_ehci_softc *isc = device_get_softc(self);
  233         ehci_softc_t *sc = &isc->base;
  234         int err;
  235 
  236         /* during module unload there are lots of children leftover */
  237         device_delete_children(self);
  238 
  239         if (sc->sc_irq_res && sc->sc_intr_hdl) {
  240                 /*
  241                  * only call ehci_detach() after ehci_init()
  242                  */
  243                 ehci_detach(sc);
  244 
  245                 err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
  246 
  247                 if (err)
  248                         /* XXX or should we panic? */
  249                         device_printf(self, "Could not tear down irq, %d\n",
  250                             err);
  251                 sc->sc_intr_hdl = NULL;
  252         }
  253 
  254         if (sc->sc_irq_res) {
  255                 bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
  256                 sc->sc_irq_res = NULL;
  257         }
  258         if (sc->sc_io_res) {
  259                 bus_release_resource(self, SYS_RES_MEMORY, 0,
  260                     sc->sc_io_res);
  261                 sc->sc_io_res = NULL;
  262         }
  263         usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
  264 
  265         return (0);
  266 }
  267 
  268 static device_method_t ehci_methods[] = {
  269         /* Device interface */
  270         DEVMETHOD(device_probe, ar71xx_ehci_probe),
  271         DEVMETHOD(device_attach, ar71xx_ehci_attach),
  272         DEVMETHOD(device_detach, ar71xx_ehci_detach),
  273         DEVMETHOD(device_suspend, bus_generic_suspend),
  274         DEVMETHOD(device_resume, bus_generic_resume),
  275         DEVMETHOD(device_shutdown, bus_generic_shutdown),
  276 
  277         DEVMETHOD_END
  278 };
  279 
  280 static driver_t ehci_driver = {
  281         .name = "ehci",
  282         .methods = ehci_methods,
  283         .size = sizeof(struct ar71xx_ehci_softc),
  284 };
  285 
  286 static devclass_t ehci_devclass;
  287 
  288 DRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0);
  289 DRIVER_MODULE(ehci, apb, ehci_driver, ehci_devclass, 0, 0);
  290 
  291 MODULE_DEPEND(ehci, usb, 1, 1, 1);

Cache object: 6714bf0c7b776f15b491f0e5dd11c044


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.