ehci_fsl.c revision 278278
1139825Simp/*- 294755Sbenno * Copyright (c) 2010-2012 Semihalf 3256901Snwhitehorn * All rights reserved. 4256901Snwhitehorn * 5256901Snwhitehorn * Redistribution and use in source and binary forms, with or without 694755Sbenno * modification, are permitted provided that the following conditions 794755Sbenno * are met: 894755Sbenno * 1. Redistributions of source code must retain the above copyright 994755Sbenno * notice, this list of conditions and the following disclaimer. 1094755Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1194755Sbenno * notice, this list of conditions and the following disclaimer in the 1294755Sbenno * documentation and/or other materials provided with the distribution. 1394755Sbenno * 1494755Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1594755Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1694755Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1794755Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18125702Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1994755Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2094755Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2194755Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2294755Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2394755Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2494755Sbenno * SUCH DAMAGE. 2594755Sbenno */ 2694755Sbenno 2794755Sbenno#include <sys/cdefs.h> 2894755Sbenno__FBSDID("$FreeBSD: stable/10/sys/dev/usb/controller/ehci_fsl.c 278278 2015-02-05 20:03:02Z hselasky $"); 2994755Sbenno 3094755Sbenno#include "opt_bus.h" 3194755Sbenno 3294755Sbenno#include <sys/param.h> 3394755Sbenno#include <sys/systm.h> 3494755Sbenno#include <sys/kernel.h> 35227843Smarius#include <sys/module.h> 36227843Smarius#include <sys/bus.h> 37227843Smarius#include <sys/queue.h> 3894755Sbenno#include <sys/lock.h> 3994755Sbenno#include <sys/lockmgr.h> 4094755Sbenno#include <sys/condvar.h> 4194755Sbenno#include <sys/rman.h> 4294755Sbenno 43256901Snwhitehorn#include <dev/ofw/ofw_bus.h> 44256901Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 45256901Snwhitehorn 4694755Sbenno#include <dev/usb/usb.h> 47256901Snwhitehorn#include <dev/usb/usbdi.h> 48256901Snwhitehorn#include <dev/usb/usb_core.h> 49256901Snwhitehorn#include <dev/usb/usb_busdma.h> 50256855Snwhitehorn#include <dev/usb/usb_process.h> 51212239Smav#include <dev/usb/usb_util.h> 5294755Sbenno#include <dev/usb/usb_controller.h> 53283477Sian#include <dev/usb/usb_bus.h> 5494755Sbenno#include <dev/usb/controller/ehci.h> 5594755Sbenno#include <dev/usb/controller/ehcireg.h> 5694755Sbenno 5794755Sbenno#include <machine/bus.h> 5894755Sbenno#include <machine/clock.h> 59261513Snwhitehorn#include <machine/resource.h> 60256901Snwhitehorn 61256901Snwhitehorn#include <powerpc/include/tlb.h> 62256901Snwhitehorn 6394755Sbenno#include "opt_platform.h" 6494755Sbenno 6594755Sbenno/* 66261513Snwhitehorn * Register the driver 67283477Sian */ 68261513Snwhitehorn/* Forward declarations */ 69261513Snwhitehornstatic int fsl_ehci_attach(device_t self); 70261513Snwhitehornstatic int fsl_ehci_detach(device_t self); 7199652Sbennostatic int fsl_ehci_probe(device_t self); 72261513Snwhitehorn 73261513Snwhitehornstatic device_method_t ehci_methods[] = { 74261513Snwhitehorn /* Device interface */ 75261513Snwhitehorn DEVMETHOD(device_probe, fsl_ehci_probe), 76261513Snwhitehorn DEVMETHOD(device_attach, fsl_ehci_attach), 77261513Snwhitehorn DEVMETHOD(device_detach, fsl_ehci_detach), 7899652Sbenno DEVMETHOD(device_suspend, bus_generic_suspend), 79261513Snwhitehorn DEVMETHOD(device_resume, bus_generic_resume), 8094755Sbenno DEVMETHOD(device_shutdown, bus_generic_shutdown), 81261513Snwhitehorn 82261513Snwhitehorn /* Bus interface */ 83261513Snwhitehorn DEVMETHOD(bus_print_child, bus_generic_print_child), 8494755Sbenno 85256901Snwhitehorn { 0, 0 } 86261513Snwhitehorn}; 87261513Snwhitehorn 88261513Snwhitehorn/* kobj_class definition */ 8994755Sbennostatic driver_t ehci_driver = { 90227843Smarius "ehci", 9194755Sbenno ehci_methods, 9294755Sbenno sizeof(struct ehci_softc) 93283477Sian}; 94283477Sian 95261513Snwhitehornstatic devclass_t ehci_devclass; 96270075Sian 97270075SianDRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 98261513SnwhitehornMODULE_DEPEND(ehci, usb, 1, 1, 1); 9994755Sbenno 100261513Snwhitehorn/* 101261513Snwhitehorn * Private defines 102261513Snwhitehorn */ 103261513Snwhitehorn#define FSL_EHCI_REG_OFF 0x100 104261513Snwhitehorn#define FSL_EHCI_REG_SIZE 0x300 105261513Snwhitehorn 106261513Snwhitehorn/* 107283477Sian * Internal interface registers' offsets. 108261513Snwhitehorn * Offsets from 0x000 ehci dev space, big-endian access. 109261513Snwhitehorn */ 110261513Snwhitehornenum internal_reg { 111261513Snwhitehorn SNOOP1 = 0x400, 112256901Snwhitehorn SNOOP2 = 0x404, 113261513Snwhitehorn AGE_CNT_THRESH = 0x408, 11494755Sbenno SI_CTRL = 0x410, 115256901Snwhitehorn CONTROL = 0x500 116261513Snwhitehorn}; 117261513Snwhitehorn 118178367Smarcel/* CONTROL register bit flags */ 119178367Smarcelenum control_flags { 120178367Smarcel USB_EN = 0x00000004, 121261513Snwhitehorn UTMI_PHY_EN = 0x00000200, 122178367Smarcel ULPI_INT_EN = 0x00000001 123261513Snwhitehorn}; 124256901Snwhitehorn 125283477Sian/* SI_CTRL register bit flags */ 12694755Sbennoenum si_ctrl_flags { 12799652Sbenno FETCH_32 = 1, 12899652Sbenno FETCH_64 = 0 129257075Snwhitehorn}; 130171805Smarcel 131261513Snwhitehorn#define SNOOP_RANGE_2GB 0x1E 132261513Snwhitehorn 133261513Snwhitehorn/* 134261513Snwhitehorn * Operational registers' offsets. 135261513Snwhitehorn * Offsets from USBCMD register, little-endian access. 136261513Snwhitehorn */ 137283477Sianenum special_op_reg { 138283477Sian USBMODE = 0x0A8, 139283477Sian PORTSC = 0x084, 140283477Sian ULPI_VIEWPORT = 0x70 141283477Sian}; 142257075Snwhitehorn 143257075Snwhitehorn/* USBMODE register bit flags */ 144257075Snwhitehornenum usbmode_flags { 145257075Snwhitehorn HOST_MODE = 0x3, 146257075Snwhitehorn DEVICE_MODE = 0x2 147257075Snwhitehorn}; 148257075Snwhitehorn 149257075Snwhitehorn#define PORT_POWER_MASK 0x00001000 150257075Snwhitehorn 151171805Smarcel/* 152256901Snwhitehorn * Private methods 153256901Snwhitehorn */ 154256901Snwhitehorn 155256901Snwhitehornstatic void 156256901Snwhitehornset_to_host_mode(ehci_softc_t *sc) 157256901Snwhitehorn{ 158256901Snwhitehorn int tmp; 159256901Snwhitehorn 160256901Snwhitehorn tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE); 161283477Sian bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE, tmp | HOST_MODE); 162256901Snwhitehorn} 163283477Sian 16494755Sbennostatic void 165178367Smarcelenable_usb(device_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) 16694755Sbenno{ 16794755Sbenno int tmp; 16899652Sbenno phandle_t node; 169261513Snwhitehorn char *phy_type; 17099652Sbenno 17199652Sbenno phy_type = NULL; 172261513Snwhitehorn tmp = bus_space_read_4(iot, ioh, CONTROL) | USB_EN; 173256901Snwhitehorn 174171805Smarcel node = ofw_bus_get_node(dev); 175256901Snwhitehorn if ((node != 0) && 176256901Snwhitehorn (OF_getprop_alloc(node, "phy_type", 1, (void **)&phy_type) > 0)) { 17799652Sbenno if (strncasecmp(phy_type, "utmi", strlen("utmi")) == 0) 178256901Snwhitehorn tmp |= UTMI_PHY_EN; 179256901Snwhitehorn free(phy_type, M_OFWPROP); 180257075Snwhitehorn } 181256901Snwhitehorn bus_space_write_4(iot, ioh, CONTROL, tmp); 182256901Snwhitehorn} 183256901Snwhitehorn 184256901Snwhitehornstatic void 185283477Sianset_32b_prefetch(bus_space_tag_t iot, bus_space_handle_t ioh) 186283477Sian{ 187283477Sian 188283477Sian bus_space_write_4(iot, ioh, SI_CTRL, FETCH_32); 189256901Snwhitehorn} 190283477Sian 191256901Snwhitehornstatic void 192256901Snwhitehornset_snooping(bus_space_tag_t iot, bus_space_handle_t ioh) 193256901Snwhitehorn{ 194256901Snwhitehorn 195256901Snwhitehorn bus_space_write_4(iot, ioh, SNOOP1, SNOOP_RANGE_2GB); 196256901Snwhitehorn bus_space_write_4(iot, ioh, SNOOP2, 0x80000000 | SNOOP_RANGE_2GB); 197256901Snwhitehorn} 198256901Snwhitehorn 199256901Snwhitehornstatic void 200256901Snwhitehornclear_port_power(ehci_softc_t *sc) 201256901Snwhitehorn{ 202256901Snwhitehorn int tmp; 203256901Snwhitehorn 20499652Sbenno tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC); 20599652Sbenno bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC, tmp & ~PORT_POWER_MASK); 20699652Sbenno} 207256901Snwhitehorn 208256901Snwhitehorn/* 209256901Snwhitehorn * Public methods 210171805Smarcel */ 211256901Snwhitehornstatic int 212256901Snwhitehornfsl_ehci_probe(device_t dev) 213256901Snwhitehorn{ 214256901Snwhitehorn 215256901Snwhitehorn if (!ofw_bus_status_okay(dev)) 216256901Snwhitehorn return (ENXIO); 217171805Smarcel 21899652Sbenno if (((ofw_bus_is_compatible(dev, "fsl-usb2-dr")) == 0) && 219256901Snwhitehorn ((ofw_bus_is_compatible(dev, "fsl-usb2-mph")) == 0)) 220256901Snwhitehorn return (ENXIO); 221256901Snwhitehorn 222256901Snwhitehorn device_set_desc(dev, "Freescale integrated EHCI controller"); 223256901Snwhitehorn 224256901Snwhitehorn return (BUS_PROBE_DEFAULT); 22599652Sbenno} 22699652Sbenno 22799652Sbennostatic int 22899652Sbennofsl_ehci_attach(device_t self) 22999652Sbenno{ 230261513Snwhitehorn ehci_softc_t *sc; 231256901Snwhitehorn int rid; 23299652Sbenno int err; 233261513Snwhitehorn bus_space_handle_t ioh; 234256901Snwhitehorn bus_space_tag_t iot; 235261513Snwhitehorn 23699652Sbenno sc = device_get_softc(self); 237261513Snwhitehorn rid = 0; 238261513Snwhitehorn 239261513Snwhitehorn sc->sc_bus.parent = self; 240261513Snwhitehorn sc->sc_bus.devices = sc->sc_devices; 241256901Snwhitehorn sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 242256901Snwhitehorn sc->sc_bus.dma_bits = 32; 243256901Snwhitehorn 244256901Snwhitehorn if (usb_bus_mem_alloc_all(&sc->sc_bus, 245256901Snwhitehorn USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) 246256901Snwhitehorn return (ENOMEM); 247256901Snwhitehorn 248256901Snwhitehorn /* Allocate io resource for EHCI */ 249124468Sgrehan sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 25099652Sbenno RF_ACTIVE); 251256901Snwhitehorn if (sc->sc_io_res == NULL) { 252256901Snwhitehorn err = fsl_ehci_detach(self); 253256901Snwhitehorn if (err) { 254256901Snwhitehorn device_printf(self, 255256901Snwhitehorn "Detach of the driver failed with error %d\n", 25699652Sbenno err); 25799652Sbenno } 258256901Snwhitehorn return (ENXIO); 259283332Sian } 260256901Snwhitehorn iot = rman_get_bustag(sc->sc_io_res); 26199652Sbenno 262283332Sian /* 263256901Snwhitehorn * Set handle to USB related registers subregion used by generic 26499652Sbenno * EHCI driver 265283332Sian */ 266283332Sian ioh = rman_get_bushandle(sc->sc_io_res); 267283332Sian 268283332Sian err = bus_space_subregion(iot, ioh, FSL_EHCI_REG_OFF, FSL_EHCI_REG_SIZE, 269283332Sian &sc->sc_io_hdl); 270256901Snwhitehorn if (err != 0) { 271256901Snwhitehorn err = fsl_ehci_detach(self); 272256901Snwhitehorn if (err) { 273256901Snwhitehorn device_printf(self, 274256855Snwhitehorn "Detach of the driver failed with error %d\n", 275256901Snwhitehorn err); 276256901Snwhitehorn } 277 return (ENXIO); 278 } 279 280 /* Set little-endian tag for use by the generic EHCI driver */ 281 sc->sc_io_tag = &bs_le_tag; 282 283 /* Allocate irq */ 284 sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 285 RF_ACTIVE); 286 if (sc->sc_irq_res == NULL) { 287 err = fsl_ehci_detach(self); 288 if (err) { 289 device_printf(self, 290 "Detach of the driver failed with error %d\n", 291 err); 292 } 293 return (ENXIO); 294 } 295 296 /* Setup interrupt handler */ 297 err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO, 298 NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 299 if (err) { 300 device_printf(self, "Could not setup irq, %d\n", err); 301 sc->sc_intr_hdl = NULL; 302 err = fsl_ehci_detach(self); 303 if (err) { 304 device_printf(self, 305 "Detach of the driver failed with error %d\n", 306 err); 307 } 308 return (ENXIO); 309 } 310 311 /* Add USB device */ 312 sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 313 if (!sc->sc_bus.bdev) { 314 device_printf(self, "Could not add USB device\n"); 315 err = fsl_ehci_detach(self); 316 if (err) { 317 device_printf(self, 318 "Detach of the driver failed with error %d\n", 319 err); 320 } 321 return (ENOMEM); 322 } 323 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 324 325 sc->sc_id_vendor = 0x1234; 326 strlcpy(sc->sc_vendor, "Freescale", sizeof(sc->sc_vendor)); 327 328 /* Enable USB */ 329 err = ehci_reset(sc); 330 if (err) { 331 device_printf(self, "Could not reset the controller\n"); 332 err = fsl_ehci_detach(self); 333 if (err) { 334 device_printf(self, 335 "Detach of the driver failed with error %d\n", 336 err); 337 } 338 return (ENXIO); 339 } 340 341 enable_usb(self, iot, ioh); 342 set_snooping(iot, ioh); 343 set_to_host_mode(sc); 344 set_32b_prefetch(iot, ioh); 345 346 /* 347 * If usb subsystem is enabled in U-Boot, port power has to be turned 348 * off to allow proper discovery of devices during boot up. 349 */ 350 clear_port_power(sc); 351 352 /* Set flags */ 353 sc->sc_flags |= EHCI_SCFLG_DONTRESET | EHCI_SCFLG_NORESTERM; 354 355 err = ehci_init(sc); 356 if (!err) { 357 sc->sc_flags |= EHCI_SCFLG_DONEINIT; 358 err = device_probe_and_attach(sc->sc_bus.bdev); 359 } 360 361 if (err) { 362 device_printf(self, "USB init failed err=%d\n", err); 363 err = fsl_ehci_detach(self); 364 if (err) { 365 device_printf(self, 366 "Detach of the driver failed with error %d\n", 367 err); 368 } 369 return (EIO); 370 } 371 372 return (0); 373} 374 375static int 376fsl_ehci_detach(device_t self) 377{ 378 379 int err; 380 ehci_softc_t *sc; 381 382 sc = device_get_softc(self); 383 /* 384 * only call ehci_detach() after ehci_init() 385 */ 386 if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { 387 ehci_detach(sc); 388 sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; 389 } 390 391 /* Disable interrupts that might have been switched on in ehci_init */ 392 if (sc->sc_io_tag && sc->sc_io_hdl) 393 bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, EHCI_USBINTR, 0); 394 395 if (sc->sc_irq_res && sc->sc_intr_hdl) { 396 err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 397 if (err) { 398 device_printf(self, "Could not tear down irq, %d\n", 399 err); 400 return (err); 401 } 402 sc->sc_intr_hdl = NULL; 403 } 404 405 if (sc->sc_bus.bdev) { 406 device_delete_child(self, sc->sc_bus.bdev); 407 sc->sc_bus.bdev = NULL; 408 } 409 410 /* During module unload there are lots of children leftover */ 411 device_delete_children(self); 412 413 if (sc->sc_irq_res) { 414 bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 415 sc->sc_irq_res = NULL; 416 } 417 418 if (sc->sc_io_res) { 419 bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); 420 sc->sc_io_res = NULL; 421 sc->sc_io_tag = 0; 422 sc->sc_io_hdl = 0; 423 } 424 425 return (0); 426} 427 428