ehci_fsl.c revision 261410
112651Skvn/*- 212651Skvn * Copyright (c) 2010-2012 Semihalf 312651Skvn * All rights reserved. 412651Skvn * 512651Skvn * Redistribution and use in source and binary forms, with or without 612651Skvn * modification, are permitted provided that the following conditions 712651Skvn * are met: 812651Skvn * 1. Redistributions of source code must retain the above copyright 912651Skvn * notice, this list of conditions and the following disclaimer. 1012651Skvn * 2. Redistributions in binary form must reproduce the above copyright 1112651Skvn * notice, this list of conditions and the following disclaimer in the 1212651Skvn * documentation and/or other materials provided with the distribution. 1312651Skvn * 1412651Skvn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1512651Skvn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1612651Skvn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1712651Skvn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1812651Skvn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1912651Skvn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2012651Skvn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2112651Skvn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2212651Skvn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2312651Skvn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2412651Skvn * SUCH DAMAGE. 2512651Skvn */ 2612651Skvn 2712651Skvn#include <sys/cdefs.h> 2812651Skvn__FBSDID("$FreeBSD: head/sys/dev/usb/controller/ehci_fsl.c 261410 2014-02-02 19:17:28Z ian $"); 2912651Skvn 3012651Skvn#include "opt_bus.h" 3112651Skvn 3212651Skvn#include <sys/param.h> 3312651Skvn#include <sys/systm.h> 3412651Skvn#include <sys/kernel.h> 3512651Skvn#include <sys/module.h> 3612651Skvn#include <sys/bus.h> 3712651Skvn#include <sys/queue.h> 3812651Skvn#include <sys/lock.h> 3912651Skvn#include <sys/lockmgr.h> 4012651Skvn#include <sys/condvar.h> 4112651Skvn#include <sys/rman.h> 4212651Skvn 4312651Skvn#include <dev/ofw/ofw_bus.h> 4412651Skvn#include <dev/ofw/ofw_bus_subr.h> 4512651Skvn 4612651Skvn#include <dev/usb/usb.h> 4712651Skvn#include <dev/usb/usbdi.h> 4812651Skvn#include <dev/usb/usb_core.h> 4912651Skvn#include <dev/usb/usb_busdma.h> 5012651Skvn#include <dev/usb/usb_process.h> 5112651Skvn#include <dev/usb/usb_util.h> 5212651Skvn#include <dev/usb/usb_controller.h> 5312651Skvn#include <dev/usb/usb_bus.h> 5412651Skvn#include <dev/usb/controller/ehci.h> 5512651Skvn#include <dev/usb/controller/ehcireg.h> 5612651Skvn 5712651Skvn#include <machine/bus.h> 5812651Skvn#include <machine/clock.h> 5912651Skvn#include <machine/resource.h> 6012651Skvn 6112651Skvn#include <powerpc/include/tlb.h> 6212651Skvn 6312651Skvn#include "opt_platform.h" 6412651Skvn 6512651Skvn/* 6612651Skvn * Register the driver 6712651Skvn */ 6812651Skvn/* Forward declarations */ 6912651Skvnstatic int fsl_ehci_attach(device_t self); 7012651Skvnstatic int fsl_ehci_detach(device_t self); 7112651Skvnstatic int fsl_ehci_probe(device_t self); 7212651Skvn 7312651Skvnstatic device_method_t ehci_methods[] = { 7412651Skvn /* Device interface */ 7512651Skvn DEVMETHOD(device_probe, fsl_ehci_probe), 7612651Skvn DEVMETHOD(device_attach, fsl_ehci_attach), 7712651Skvn DEVMETHOD(device_detach, fsl_ehci_detach), 7812651Skvn DEVMETHOD(device_suspend, bus_generic_suspend), 7912651Skvn DEVMETHOD(device_resume, bus_generic_resume), 8012651Skvn DEVMETHOD(device_shutdown, bus_generic_shutdown), 8112651Skvn 8212651Skvn /* Bus interface */ 8312651Skvn DEVMETHOD(bus_print_child, bus_generic_print_child), 8412651Skvn 8512651Skvn { 0, 0 } 8612651Skvn}; 8712651Skvn 8812651Skvn/* kobj_class definition */ 8912651Skvnstatic driver_t ehci_driver = { 9012651Skvn "ehci", 9112651Skvn ehci_methods, 9212651Skvn sizeof(struct ehci_softc) 9312651Skvn}; 9412651Skvn 9512651Skvnstatic devclass_t ehci_devclass; 9612651Skvn 9712651SkvnDRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); 9812651SkvnMODULE_DEPEND(ehci, usb, 1, 1, 1); 9912651Skvn 10012651Skvn/* 10112651Skvn * Private defines 10212651Skvn */ 10312651Skvn#define FSL_EHCI_REG_OFF 0x100 10412651Skvn#define FSL_EHCI_REG_SIZE 0x300 10512651Skvn 10612651Skvn/* 10712651Skvn * Internal interface registers' offsets. 10812651Skvn * Offsets from 0x000 ehci dev space, big-endian access. 10912651Skvn */ 11012651Skvnenum internal_reg { 11112651Skvn SNOOP1 = 0x400, 11212651Skvn SNOOP2 = 0x404, 11312651Skvn AGE_CNT_THRESH = 0x408, 11412651Skvn SI_CTRL = 0x410, 11512651Skvn CONTROL = 0x500 11612651Skvn}; 11712651Skvn 11812651Skvn/* CONTROL register bit flags */ 11912651Skvnenum control_flags { 12012651Skvn USB_EN = 0x00000004, 12112651Skvn UTMI_PHY_EN = 0x00000200, 12212651Skvn ULPI_INT_EN = 0x00000001 12312651Skvn}; 12412651Skvn 12512651Skvn/* SI_CTRL register bit flags */ 12612651Skvnenum si_ctrl_flags { 12712651Skvn FETCH_32 = 1, 12812651Skvn FETCH_64 = 0 12912651Skvn}; 13012651Skvn 13112651Skvn#define SNOOP_RANGE_2GB 0x1E 13212651Skvn 13312651Skvn/* 13412651Skvn * Operational registers' offsets. 13512651Skvn * Offsets from USBCMD register, little-endian access. 13612651Skvn */ 13712651Skvnenum special_op_reg { 13812651Skvn USBMODE = 0x0A8, 13912651Skvn PORTSC = 0x084, 14012651Skvn ULPI_VIEWPORT = 0x70 14112651Skvn}; 14212651Skvn 14312651Skvn/* USBMODE register bit flags */ 14412651Skvnenum usbmode_flags { 14512651Skvn HOST_MODE = 0x3, 14612651Skvn DEVICE_MODE = 0x2 14712651Skvn}; 14812651Skvn 14912651Skvn#define PORT_POWER_MASK 0x00001000 15012651Skvn 15112651Skvn/* 15212651Skvn * Private methods 15312651Skvn */ 15412651Skvn 15512651Skvnstatic void 15612651Skvnset_to_host_mode(ehci_softc_t *sc) 15712651Skvn{ 15812651Skvn int tmp; 15912651Skvn 16012651Skvn tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE); 16112651Skvn bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, USBMODE, tmp | HOST_MODE); 16212651Skvn} 16312651Skvn 16412651Skvnstatic void 16512651Skvnenable_usb(device_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) 16612651Skvn{ 16712651Skvn int tmp; 16812651Skvn phandle_t node; 16912651Skvn char *phy_type; 17012651Skvn 17112651Skvn phy_type = NULL; 17212651Skvn tmp = bus_space_read_4(iot, ioh, CONTROL) | USB_EN; 17312651Skvn 17412651Skvn node = ofw_bus_get_node(dev); 17512651Skvn if ((node != 0) && 17612651Skvn (OF_getprop_alloc(node, "phy_type", 1, (void **)&phy_type) > 0)) { 17712651Skvn if (strncasecmp(phy_type, "utmi", strlen("utmi")) == 0) 17812651Skvn tmp |= UTMI_PHY_EN; 17912651Skvn free(phy_type, M_OFWPROP); 18012651Skvn } 18112651Skvn bus_space_write_4(iot, ioh, CONTROL, tmp); 18212651Skvn} 18312651Skvn 18412651Skvnstatic void 18512651Skvnset_32b_prefetch(bus_space_tag_t iot, bus_space_handle_t ioh) 18612651Skvn{ 18712651Skvn 18812651Skvn bus_space_write_4(iot, ioh, SI_CTRL, FETCH_32); 18912651Skvn} 19012651Skvn 19112651Skvnstatic void 19212651Skvnset_snooping(bus_space_tag_t iot, bus_space_handle_t ioh) 19312651Skvn{ 19412651Skvn 19512651Skvn bus_space_write_4(iot, ioh, SNOOP1, SNOOP_RANGE_2GB); 19612651Skvn bus_space_write_4(iot, ioh, SNOOP2, 0x80000000 | SNOOP_RANGE_2GB); 19712651Skvn} 19812651Skvn 19912651Skvnstatic void 20012651Skvnclear_port_power(ehci_softc_t *sc) 20112651Skvn{ 20212651Skvn int tmp; 20312651Skvn 20412651Skvn tmp = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC); 20512651Skvn bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, PORTSC, tmp & ~PORT_POWER_MASK); 20612651Skvn} 20712651Skvn 20812651Skvn/* 20912651Skvn * Public methods 21012651Skvn */ 21112651Skvnstatic int 21212651Skvnfsl_ehci_probe(device_t dev) 21312651Skvn{ 21412651Skvn 21512651Skvn if (!ofw_bus_status_okay(dev)) 21612651Skvn return (ENXIO); 21712651Skvn 21812651Skvn if (((ofw_bus_is_compatible(dev, "fsl-usb2-dr")) == 0) && 21912651Skvn ((ofw_bus_is_compatible(dev, "fsl-usb2-mph")) == 0)) 22012651Skvn return (ENXIO); 22112651Skvn 22212651Skvn device_set_desc(dev, "Freescale integrated EHCI controller"); 22312651Skvn 22412651Skvn return (BUS_PROBE_DEFAULT); 22512651Skvn} 22612651Skvn 22712651Skvnstatic int 22812651Skvnfsl_ehci_attach(device_t self) 22912651Skvn{ 23012651Skvn ehci_softc_t *sc; 23112651Skvn int rid; 23212651Skvn int err; 23312651Skvn bus_space_handle_t ioh; 23412651Skvn bus_space_tag_t iot; 23512651Skvn 23612651Skvn sc = device_get_softc(self); 23712651Skvn rid = 0; 23812651Skvn 23912651Skvn sc->sc_bus.parent = self; 24012651Skvn sc->sc_bus.devices = sc->sc_devices; 24112651Skvn sc->sc_bus.devices_max = EHCI_MAX_DEVICES; 24212651Skvn 24312651Skvn if (usb_bus_mem_alloc_all(&sc->sc_bus, 24412651Skvn USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) 24512651Skvn return (ENOMEM); 24612651Skvn 24712651Skvn /* Allocate io resource for EHCI */ 24812651Skvn sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, 24912651Skvn RF_ACTIVE); 25012651Skvn if (sc->sc_io_res == NULL) { 25112651Skvn err = fsl_ehci_detach(self); 25212651Skvn if (err) { 25312651Skvn device_printf(self, 25412651Skvn "Detach of the driver failed with error %d\n", 25512651Skvn err); 25612651Skvn } 25712651Skvn return (ENXIO); 25812651Skvn } 25912651Skvn iot = rman_get_bustag(sc->sc_io_res); 26012651Skvn 26112651Skvn /* 26212651Skvn * Set handle to USB related registers subregion used by generic 26312651Skvn * EHCI driver 26412651Skvn */ 26512651Skvn ioh = rman_get_bushandle(sc->sc_io_res); 26612651Skvn 26712651Skvn err = bus_space_subregion(iot, ioh, FSL_EHCI_REG_OFF, FSL_EHCI_REG_SIZE, 26812651Skvn &sc->sc_io_hdl); 26912651Skvn if (err != 0) { 27012651Skvn err = fsl_ehci_detach(self); 27112651Skvn if (err) { 27212651Skvn device_printf(self, 27312651Skvn "Detach of the driver failed with error %d\n", 27412651Skvn err); 27512651Skvn } 27612651Skvn return (ENXIO); 27712651Skvn } 27812651Skvn 27912651Skvn /* Set little-endian tag for use by the generic EHCI driver */ 28012651Skvn sc->sc_io_tag = &bs_le_tag; 28112651Skvn 28212651Skvn /* Allocate irq */ 28312651Skvn sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, 28412651Skvn RF_ACTIVE); 28512651Skvn if (sc->sc_irq_res == NULL) { 28612651Skvn err = fsl_ehci_detach(self); 28712651Skvn if (err) { 28812651Skvn device_printf(self, 28912651Skvn "Detach of the driver failed with error %d\n", 29012651Skvn err); 29112651Skvn } 29212651Skvn return (ENXIO); 29312651Skvn } 29412651Skvn 29512651Skvn /* Setup interrupt handler */ 29612651Skvn err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO, 29712651Skvn NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); 29812651Skvn if (err) { 29912651Skvn device_printf(self, "Could not setup irq, %d\n", err); 30012651Skvn sc->sc_intr_hdl = NULL; 30112651Skvn err = fsl_ehci_detach(self); 30212651Skvn if (err) { 30312651Skvn device_printf(self, 30412651Skvn "Detach of the driver failed with error %d\n", 30512651Skvn err); 30612651Skvn } 30712651Skvn return (ENXIO); 30812651Skvn } 30912651Skvn 31012651Skvn /* Add USB device */ 31112651Skvn sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 31212651Skvn if (!sc->sc_bus.bdev) { 31312651Skvn device_printf(self, "Could not add USB device\n"); 31412651Skvn err = fsl_ehci_detach(self); 31512651Skvn if (err) { 31612651Skvn device_printf(self, 31712651Skvn "Detach of the driver failed with error %d\n", 31812651Skvn err); 31912651Skvn } 32012651Skvn return (ENOMEM); 32112651Skvn } 32212651Skvn device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 32312651Skvn 32412651Skvn sc->sc_id_vendor = 0x1234; 32512651Skvn strlcpy(sc->sc_vendor, "Freescale", sizeof(sc->sc_vendor)); 32612651Skvn 32712651Skvn /* Enable USB */ 32812651Skvn err = ehci_reset(sc); 32912651Skvn if (err) { 33012651Skvn device_printf(self, "Could not reset the controller\n"); 33112651Skvn err = fsl_ehci_detach(self); 33212651Skvn if (err) { 33312651Skvn device_printf(self, 33412651Skvn "Detach of the driver failed with error %d\n", 33512651Skvn err); 33612651Skvn } 33712651Skvn return (ENXIO); 33812651Skvn } 33912651Skvn 34012651Skvn enable_usb(self, iot, ioh); 34112651Skvn set_snooping(iot, ioh); 34212651Skvn set_to_host_mode(sc); 34312651Skvn set_32b_prefetch(iot, ioh); 34412651Skvn 34512651Skvn /* 34612651Skvn * If usb subsystem is enabled in U-Boot, port power has to be turned 34712651Skvn * off to allow proper discovery of devices during boot up. 34812651Skvn */ 34912651Skvn clear_port_power(sc); 35012651Skvn 35112651Skvn /* Set flags */ 35212651Skvn sc->sc_flags |= EHCI_SCFLG_DONTRESET | EHCI_SCFLG_NORESTERM; 35312651Skvn 35412651Skvn err = ehci_init(sc); 35512651Skvn if (!err) { 35612651Skvn sc->sc_flags |= EHCI_SCFLG_DONEINIT; 35712651Skvn err = device_probe_and_attach(sc->sc_bus.bdev); 35812651Skvn } 35912651Skvn 36012651Skvn if (err) { 36112651Skvn device_printf(self, "USB init failed err=%d\n", err); 36212651Skvn err = fsl_ehci_detach(self); 36312651Skvn if (err) { 36412651Skvn device_printf(self, 36512651Skvn "Detach of the driver failed with error %d\n", 36612651Skvn err); 36712651Skvn } 36812651Skvn return (EIO); 36912651Skvn } 37012651Skvn 37112651Skvn return (0); 37212651Skvn} 37312651Skvn 37412651Skvnstatic int 37512651Skvnfsl_ehci_detach(device_t self) 37612651Skvn{ 37712651Skvn 37812651Skvn int err; 37912651Skvn ehci_softc_t *sc; 38012651Skvn 38112651Skvn sc = device_get_softc(self); 38212651Skvn /* 38312651Skvn * only call ehci_detach() after ehci_init() 38412651Skvn */ 38512651Skvn if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { 38612651Skvn ehci_detach(sc); 38712651Skvn sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; 38812651Skvn } 38912651Skvn 39012651Skvn /* Disable interrupts that might have been switched on in ehci_init */ 39112651Skvn if (sc->sc_io_tag && sc->sc_io_hdl) 39212651Skvn bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, EHCI_USBINTR, 0); 39312651Skvn 39412651Skvn if (sc->sc_irq_res && sc->sc_intr_hdl) { 39512651Skvn err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); 39612651Skvn if (err) { 39712651Skvn device_printf(self, "Could not tear down irq, %d\n", 39812651Skvn err); 39912651Skvn return (err); 40012651Skvn } 40112651Skvn sc->sc_intr_hdl = NULL; 40212651Skvn } 40312651Skvn 40412651Skvn if (sc->sc_bus.bdev) { 40512651Skvn device_delete_child(self, sc->sc_bus.bdev); 40612651Skvn sc->sc_bus.bdev = NULL; 40712651Skvn } 40812651Skvn 40912651Skvn /* During module unload there are lots of children leftover */ 41012651Skvn device_delete_children(self); 41112651Skvn 41212651Skvn if (sc->sc_irq_res) { 41312651Skvn bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); 41412651Skvn sc->sc_irq_res = NULL; 41512651Skvn } 41612651Skvn 41712651Skvn if (sc->sc_io_res) { 41812651Skvn bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); 41912651Skvn sc->sc_io_res = NULL; 42012651Skvn sc->sc_io_tag = 0; 42112651Skvn sc->sc_io_hdl = 0; 42212651Skvn } 42312651Skvn 42412651Skvn return (0); 42512651Skvn} 42612651Skvn 42712651Skvn