generic_ohci.c revision 308401
1208625Sjkim/*- 2208625Sjkim * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3208625Sjkim * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org> 4208625Sjkim * All rights reserved. 5208625Sjkim * 6208625Sjkim * Redistribution and use in source and binary forms, with or without 7217365Sjkim * modification, are permitted provided that the following conditions 8217365Sjkim * are met: 9208625Sjkim * 1. Redistributions of source code must retain the above copyright 10208625Sjkim * notice, this list of conditions and the following disclaimer. 11217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright 12217365Sjkim * notice, this list of conditions and the following disclaimer in the 13217365Sjkim * documentation and/or other materials provided with the distribution. 14217365Sjkim * 15217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25208625Sjkim * SUCH DAMAGE. 26217365Sjkim */ 27217365Sjkim 28217365Sjkim/* 29208625Sjkim * Generic OHCI driver based on AT91 OHCI 30217365Sjkim */ 31217365Sjkim 32217365Sjkim#include <sys/cdefs.h> 33217365Sjkim__FBSDID("$FreeBSD: stable/11/sys/dev/usb/controller/generic_ohci.c 308401 2016-11-07 08:36:06Z hselasky $"); 34217365Sjkim 35217365Sjkim#include <sys/param.h> 36217365Sjkim#include <sys/systm.h> 37217365Sjkim#include <sys/bus.h> 38217365Sjkim#include <sys/rman.h> 39217365Sjkim#include <sys/condvar.h> 40217365Sjkim#include <sys/kernel.h> 41217365Sjkim#include <sys/module.h> 42217365Sjkim 43208625Sjkim#include <machine/bus.h> 44208625Sjkim#include <dev/ofw/ofw_bus.h> 45208625Sjkim#include <dev/ofw/ofw_bus_subr.h> 46209746Sjkim 47209746Sjkim#include <dev/usb/usb.h> 48209746Sjkim#include <dev/usb/usbdi.h> 49208625Sjkim 50208625Sjkim#include <dev/usb/usb_core.h> 51208625Sjkim#include <dev/usb/usb_busdma.h> 52208625Sjkim#include <dev/usb/usb_process.h> 53208625Sjkim#include <dev/usb/usb_util.h> 54208625Sjkim 55208625Sjkim#include <dev/usb/usb_controller.h> 56208625Sjkim#include <dev/usb/usb_bus.h> 57208625Sjkim#include <dev/usb/controller/ohci.h> 58208625Sjkim#include <dev/usb/controller/ohcireg.h> 59208625Sjkim 60208625Sjkim#ifdef EXT_RESOURCES 61208625Sjkim#include <dev/extres/clk/clk.h> 62208625Sjkim#include <dev/extres/hwreset/hwreset.h> 63208625Sjkim#include <dev/extres/phy/phy.h> 64208625Sjkim#endif 65208625Sjkim 66208625Sjkim#include "generic_usb_if.h" 67208625Sjkim 68208625Sjkim#ifdef EXT_RESOURCES 69208625Sjkimstruct clk_list { 70208625Sjkim TAILQ_ENTRY(clk_list) next; 71208625Sjkim clk_t clk; 72208625Sjkim}; 73208625Sjkim#endif 74208625Sjkim 75208625Sjkimstruct generic_ohci_softc { 76208625Sjkim ohci_softc_t ohci_sc; 77208625Sjkim 78208625Sjkim#ifdef EXT_RESOURCES 79208625Sjkim hwreset_t rst; 80208625Sjkim phy_t phy; 81208625Sjkim TAILQ_HEAD(, clk_list) clk_list; 82208625Sjkim#endif 83208625Sjkim}; 84208625Sjkim 85208625Sjkimstatic int generic_ohci_detach(device_t); 86208625Sjkim 87208625Sjkimstatic int 88208625Sjkimgeneric_ohci_probe(device_t dev) 89208625Sjkim{ 90208625Sjkim 91208625Sjkim if (!ofw_bus_status_okay(dev)) 92208625Sjkim return (ENXIO); 93208625Sjkim 94208625Sjkim if (!ofw_bus_is_compatible(dev, "generic-ohci")) 95208625Sjkim return (ENXIO); 96208625Sjkim 97208625Sjkim device_set_desc(dev, "Generic OHCI Controller"); 98208625Sjkim 99208625Sjkim return (BUS_PROBE_DEFAULT); 100208625Sjkim} 101208625Sjkim 102208625Sjkimstatic int 103208625Sjkimgeneric_ohci_attach(device_t dev) 104208625Sjkim{ 105208625Sjkim struct generic_ohci_softc *sc = device_get_softc(dev); 106208625Sjkim int err, rid; 107208625Sjkim#ifdef EXT_RESOURCES 108208625Sjkim int off; 109208625Sjkim struct clk_list *clkp; 110208625Sjkim clk_t clk; 111208625Sjkim#endif 112208625Sjkim 113208625Sjkim sc->ohci_sc.sc_bus.parent = dev; 114208625Sjkim sc->ohci_sc.sc_bus.devices = sc->ohci_sc.sc_devices; 115208625Sjkim sc->ohci_sc.sc_bus.devices_max = OHCI_MAX_DEVICES; 116208625Sjkim sc->ohci_sc.sc_bus.dma_bits = 32; 117208625Sjkim 118208625Sjkim /* get all DMA memory */ 119208625Sjkim if (usb_bus_mem_alloc_all(&sc->ohci_sc.sc_bus, 120208625Sjkim USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { 121208625Sjkim return (ENOMEM); 122208625Sjkim } 123208625Sjkim 124208625Sjkim rid = 0; 125208625Sjkim sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 126208625Sjkim &rid, RF_ACTIVE); 127208625Sjkim if (sc->ohci_sc.sc_io_res == 0) { 128208625Sjkim err = ENOMEM; 129208625Sjkim goto error; 130208625Sjkim } 131208625Sjkim 132208625Sjkim sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res); 133208625Sjkim sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res); 134208625Sjkim sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res); 135208625Sjkim 136208625Sjkim rid = 0; 137208625Sjkim sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 138208625Sjkim RF_ACTIVE); 139208625Sjkim if (sc->ohci_sc.sc_irq_res == 0) { 140208625Sjkim err = ENXIO; 141208625Sjkim goto error; 142208625Sjkim } 143208625Sjkim sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1); 144208625Sjkim if (sc->ohci_sc.sc_bus.bdev == 0) { 145208625Sjkim err = ENXIO; 146208625Sjkim goto error; 147208625Sjkim } 148208625Sjkim device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus); 149208625Sjkim 150208625Sjkim strlcpy(sc->ohci_sc.sc_vendor, "Generic", 151208625Sjkim sizeof(sc->ohci_sc.sc_vendor)); 152208625Sjkim 153208625Sjkim err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res, 154208625Sjkim INTR_TYPE_BIO | INTR_MPSAFE, NULL, 155208625Sjkim (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl); 156208625Sjkim if (err) { 157208625Sjkim sc->ohci_sc.sc_intr_hdl = NULL; 158208625Sjkim goto error; 159208625Sjkim } 160208625Sjkim 161208625Sjkim#ifdef EXT_RESOURCES 162208625Sjkim TAILQ_INIT(&sc->clk_list); 163208625Sjkim /* Enable clock */ 164208625Sjkim for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { 165208625Sjkim err = clk_enable(clk); 166208625Sjkim if (err != 0) { 167208625Sjkim device_printf(dev, "Could not enable clock %s\n", 168208625Sjkim clk_get_name(clk)); 169208625Sjkim goto error; 170208625Sjkim } 171208625Sjkim clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); 172208625Sjkim clkp->clk = clk; 173208625Sjkim TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); 174208625Sjkim } 175208625Sjkim 176208625Sjkim /* De-assert reset */ 177208625Sjkim if (hwreset_get_by_ofw_idx(dev, 0, 0, &sc->rst) == 0) { 178208625Sjkim err = hwreset_deassert(sc->rst); 179208625Sjkim if (err != 0) { 180208625Sjkim device_printf(dev, "Could not de-assert reset %d\n", 181208625Sjkim off); 182208625Sjkim goto error; 183208625Sjkim } 184208625Sjkim } 185208625Sjkim 186208625Sjkim /* Enable phy */ 187208625Sjkim if (phy_get_by_ofw_name(dev, 0, "usb", &sc->phy) == 0) { 188208625Sjkim err = phy_enable(dev, sc->phy); 189208625Sjkim if (err != 0) { 190208625Sjkim device_printf(dev, "Could not enable phy\n"); 191208625Sjkim goto error; 192208625Sjkim } 193208625Sjkim } 194208625Sjkim#endif 195208625Sjkim 196208625Sjkim if (GENERIC_USB_INIT(dev) != 0) { 197208625Sjkim err = ENXIO; 198208625Sjkim goto error; 199208625Sjkim } 200208625Sjkim 201208625Sjkim err = ohci_init(&sc->ohci_sc); 202208625Sjkim if (err == 0) 203208625Sjkim err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev); 204208625Sjkim if (err) 205208625Sjkim goto error; 206208625Sjkim 207208625Sjkim return (0); 208208625Sjkimerror: 209208625Sjkim generic_ohci_detach(dev); 210208625Sjkim return (err); 211208625Sjkim} 212208625Sjkim 213208625Sjkimstatic int 214208625Sjkimgeneric_ohci_detach(device_t dev) 215208625Sjkim{ 216208625Sjkim struct generic_ohci_softc *sc = device_get_softc(dev); 217208625Sjkim int err; 218208625Sjkim#ifdef EXT_RESOURCES 219208625Sjkim struct clk_list *clk, *clk_tmp; 220208625Sjkim#endif 221208625Sjkim 222208625Sjkim /* during module unload there are lots of children leftover */ 223208625Sjkim device_delete_children(dev); 224208625Sjkim 225208625Sjkim /* 226208625Sjkim * Put the controller into reset, then disable clocks and do 227208625Sjkim * the MI tear down. We have to disable the clocks/hardware 228208625Sjkim * after we do the rest of the teardown. We also disable the 229208625Sjkim * clocks in the opposite order we acquire them, but that 230208625Sjkim * doesn't seem to be absolutely necessary. We free up the 231208625Sjkim * clocks after we disable them, so the system could, in 232208625Sjkim * theory, reuse them. 233208625Sjkim */ 234208625Sjkim bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl, 235208625Sjkim OHCI_CONTROL, 0); 236208625Sjkim 237208625Sjkim if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) { 238208625Sjkim /* 239208625Sjkim * only call ohci_detach() after ohci_init() 240208625Sjkim */ 241208625Sjkim ohci_detach(&sc->ohci_sc); 242208625Sjkim 243208625Sjkim err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res, 244208625Sjkim sc->ohci_sc.sc_intr_hdl); 245208625Sjkim sc->ohci_sc.sc_intr_hdl = NULL; 246208625Sjkim } 247208625Sjkim if (sc->ohci_sc.sc_irq_res) { 248208625Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, 249208625Sjkim sc->ohci_sc.sc_irq_res); 250208625Sjkim sc->ohci_sc.sc_irq_res = NULL; 251208625Sjkim } 252208625Sjkim if (sc->ohci_sc.sc_io_res) { 253208625Sjkim bus_release_resource(dev, SYS_RES_MEMORY, 0, 254208625Sjkim sc->ohci_sc.sc_io_res); 255208625Sjkim sc->ohci_sc.sc_io_res = NULL; 256208625Sjkim } 257208625Sjkim usb_bus_mem_free_all(&sc->ohci_sc.sc_bus, &ohci_iterate_hw_softc); 258208625Sjkim 259208625Sjkim#ifdef EXT_RESOURCES 260208625Sjkim /* Disable phy */ 261208625Sjkim if (sc->phy) { 262208625Sjkim err = phy_disable(dev, sc->phy); 263208625Sjkim if (err != 0) 264208625Sjkim device_printf(dev, "Could not disable phy\n"); 265208625Sjkim phy_release(sc->phy); 266208625Sjkim } 267208625Sjkim 268208625Sjkim /* Disable clock */ 269208625Sjkim TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) { 270208625Sjkim err = clk_disable(clk->clk); 271208625Sjkim if (err != 0) 272208625Sjkim device_printf(dev, "Could not disable clock %s\n", 273208625Sjkim clk_get_name(clk->clk)); 274208625Sjkim err = clk_release(clk->clk); 275208625Sjkim if (err != 0) 276208625Sjkim device_printf(dev, "Could not release clock %s\n", 277208625Sjkim clk_get_name(clk->clk)); 278208625Sjkim TAILQ_REMOVE(&sc->clk_list, clk, next); 279208625Sjkim free(clk, M_DEVBUF); 280208625Sjkim } 281208625Sjkim 282208625Sjkim /* De-assert reset */ 283208625Sjkim if (sc->rst) { 284208625Sjkim err = hwreset_assert(sc->rst); 285208625Sjkim if (err != 0) 286208625Sjkim device_printf(dev, "Could not assert reset\n"); 287208625Sjkim hwreset_release(sc->rst); 288208625Sjkim } 289208625Sjkim#endif 290208625Sjkim 291208625Sjkim if (GENERIC_USB_DEINIT(dev) != 0) 292208625Sjkim return (ENXIO); 293208625Sjkim 294208625Sjkim return (0); 295208625Sjkim} 296208625Sjkim 297208625Sjkimstatic device_method_t generic_ohci_methods[] = { 298208625Sjkim /* Device interface */ 299208625Sjkim DEVMETHOD(device_probe, generic_ohci_probe), 300208625Sjkim DEVMETHOD(device_attach, generic_ohci_attach), 301208625Sjkim DEVMETHOD(device_detach, generic_ohci_detach), 302208625Sjkim 303208625Sjkim DEVMETHOD(device_suspend, bus_generic_suspend), 304208625Sjkim DEVMETHOD(device_resume, bus_generic_resume), 305208625Sjkim DEVMETHOD(device_shutdown, bus_generic_shutdown), 306208625Sjkim 307208625Sjkim DEVMETHOD_END 308208625Sjkim}; 309208625Sjkim 310208625Sjkimdriver_t generic_ohci_driver = { 311208625Sjkim .name = "ohci", 312208625Sjkim .methods = generic_ohci_methods, 313208625Sjkim .size = sizeof(struct generic_ohci_softc), 314208625Sjkim}; 315208625Sjkim 316208625Sjkimstatic devclass_t generic_ohci_devclass; 317208625Sjkim 318208625SjkimDRIVER_MODULE(ohci, simplebus, generic_ohci_driver, 319208625Sjkim generic_ohci_devclass, 0, 0); 320208625SjkimMODULE_DEPEND(ohci, usb, 1, 1, 1); 321208625Sjkim