1239278Sgonzo/*- 2239278Sgonzo * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> 3239278Sgonzo * All rights reserved. 4239278Sgonzo * 5239278Sgonzo * Redistribution and use in source and binary forms, with or without 6239278Sgonzo * modification, are permitted provided that the following conditions 7239278Sgonzo * are met: 8239278Sgonzo * 1. Redistributions of source code must retain the above copyright 9239278Sgonzo * notice, this list of conditions and the following disclaimer. 10239278Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11239278Sgonzo * notice, this list of conditions and the following disclaimer in the 12239278Sgonzo * documentation and/or other materials provided with the distribution. 13239278Sgonzo * 14239278Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15239278Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16239278Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17239278Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18239278Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19239278Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20239278Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21239278Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22239278Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239278Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239278Sgonzo * SUCH DAMAGE. 25239278Sgonzo * 26239278Sgonzo */ 27239278Sgonzo#include <sys/cdefs.h> 28239278Sgonzo__FBSDID("$FreeBSD: releng/11.0/sys/arm/lpc/lpc_ohci.c 276717 2015-01-05 20:22:18Z hselasky $"); 29239278Sgonzo 30239278Sgonzo#include <sys/stdint.h> 31239278Sgonzo#include <sys/stddef.h> 32239278Sgonzo#include <sys/param.h> 33239278Sgonzo#include <sys/queue.h> 34239278Sgonzo#include <sys/types.h> 35239278Sgonzo#include <sys/systm.h> 36239278Sgonzo#include <sys/kernel.h> 37239278Sgonzo#include <sys/bus.h> 38239278Sgonzo#include <sys/module.h> 39239278Sgonzo#include <sys/lock.h> 40239278Sgonzo#include <sys/mutex.h> 41239278Sgonzo#include <sys/condvar.h> 42239278Sgonzo#include <sys/sysctl.h> 43239278Sgonzo#include <sys/rman.h> 44239278Sgonzo#include <sys/sx.h> 45239278Sgonzo#include <sys/unistd.h> 46239278Sgonzo#include <sys/callout.h> 47239278Sgonzo#include <sys/malloc.h> 48239278Sgonzo#include <sys/priv.h> 49239278Sgonzo 50239278Sgonzo#include <sys/kdb.h> 51239278Sgonzo 52239278Sgonzo#include <dev/ofw/ofw_bus.h> 53239278Sgonzo#include <dev/ofw/ofw_bus_subr.h> 54239278Sgonzo 55239278Sgonzo#include <dev/usb/usb.h> 56239278Sgonzo#include <dev/usb/usbdi.h> 57239278Sgonzo 58239278Sgonzo#include <dev/usb/usb_core.h> 59239278Sgonzo#include <dev/usb/usb_busdma.h> 60239278Sgonzo#include <dev/usb/usb_process.h> 61239278Sgonzo#include <dev/usb/usb_util.h> 62239278Sgonzo 63239278Sgonzo#include <dev/usb/usb_controller.h> 64239278Sgonzo#include <dev/usb/usb_bus.h> 65239278Sgonzo#include <dev/usb/controller/ohci.h> 66239278Sgonzo#include <dev/usb/controller/ohcireg.h> 67239278Sgonzo 68239278Sgonzo#include <arm/lpc/lpcreg.h> 69239278Sgonzo#include <arm/lpc/lpcvar.h> 70239278Sgonzo 71239278Sgonzo#define I2C_START_BIT (1 << 8) 72239278Sgonzo#define I2C_STOP_BIT (1 << 9) 73239278Sgonzo#define I2C_READ 0x01 74239278Sgonzo#define I2C_WRITE 0x00 75239278Sgonzo#define DUMMY_BYTE 0x55 76239278Sgonzo 77239278Sgonzo#define lpc_otg_read_4(_sc, _reg) \ 78239278Sgonzo bus_space_read_4(_sc->sc_io_tag, _sc->sc_io_hdl, _reg) 79239278Sgonzo#define lpc_otg_write_4(_sc, _reg, _value) \ 80239278Sgonzo bus_space_write_4(_sc->sc_io_tag, _sc->sc_io_hdl, _reg, _value) 81239278Sgonzo#define lpc_otg_wait_write_4(_sc, _wreg, _sreg, _value) \ 82239278Sgonzo do { \ 83239278Sgonzo lpc_otg_write_4(_sc, _wreg, _value); \ 84239278Sgonzo while ((lpc_otg_read_4(_sc, _sreg) & _value) != _value); \ 85239278Sgonzo } while (0); 86239278Sgonzo 87239278Sgonzostatic int lpc_ohci_probe(device_t dev); 88239278Sgonzostatic int lpc_ohci_attach(device_t dev); 89239278Sgonzostatic int lpc_ohci_detach(device_t dev); 90239278Sgonzo 91239278Sgonzostatic void lpc_otg_i2c_reset(struct ohci_softc *); 92239278Sgonzo 93239278Sgonzostatic int lpc_isp3101_read(struct ohci_softc *, int); 94239278Sgonzostatic void lpc_isp3101_write(struct ohci_softc *, int, int); 95239278Sgonzostatic void lpc_isp3101_clear(struct ohci_softc *, int, int); 96239278Sgonzostatic void lpc_isp3101_configure(device_t dev, struct ohci_softc *); 97239278Sgonzo 98239278Sgonzostatic int 99239278Sgonzolpc_ohci_probe(device_t dev) 100239278Sgonzo{ 101261410Sian 102261410Sian if (!ofw_bus_status_okay(dev)) 103261410Sian return (ENXIO); 104261410Sian 105239278Sgonzo if (!ofw_bus_is_compatible(dev, "lpc,usb-ohci")) 106239278Sgonzo return (ENXIO); 107239278Sgonzo 108239278Sgonzo device_set_desc(dev, "LPC32x0 USB OHCI controller"); 109239278Sgonzo return (BUS_PROBE_DEFAULT); 110239278Sgonzo} 111239278Sgonzo 112239278Sgonzostatic int 113239278Sgonzolpc_ohci_attach(device_t dev) 114239278Sgonzo{ 115239278Sgonzo struct ohci_softc *sc = device_get_softc(dev); 116239278Sgonzo int err; 117239278Sgonzo int rid; 118239278Sgonzo int i = 0; 119239278Sgonzo uint32_t usbctrl; 120239278Sgonzo uint32_t otgstatus; 121239278Sgonzo 122239278Sgonzo sc->sc_bus.parent = dev; 123239278Sgonzo sc->sc_bus.devices = sc->sc_devices; 124239278Sgonzo sc->sc_bus.devices_max = OHCI_MAX_DEVICES; 125276717Shselasky sc->sc_bus.dma_bits = 32; 126239278Sgonzo 127239278Sgonzo if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), 128239278Sgonzo &ohci_iterate_hw_softc)) 129239278Sgonzo return (ENOMEM); 130239278Sgonzo 131239278Sgonzo rid = 0; 132239278Sgonzo sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 133239278Sgonzo if (!sc->sc_io_res) { 134239278Sgonzo device_printf(dev, "cannot map OHCI register space\n"); 135239278Sgonzo goto fail; 136239278Sgonzo } 137239278Sgonzo 138239278Sgonzo sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); 139239278Sgonzo sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); 140239278Sgonzo sc->sc_io_size = rman_get_size(sc->sc_io_res); 141239278Sgonzo 142239278Sgonzo rid = 0; 143239278Sgonzo sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 144239278Sgonzo if (sc->sc_irq_res == NULL) { 145239278Sgonzo device_printf(dev, "cannot allocate interrupt\n"); 146239278Sgonzo goto fail; 147239278Sgonzo } 148239278Sgonzo 149239278Sgonzo sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); 150239278Sgonzo if (!(sc->sc_bus.bdev)) 151239278Sgonzo goto fail; 152239278Sgonzo 153239278Sgonzo device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 154239278Sgonzo strlcpy(sc->sc_vendor, "NXP", sizeof(sc->sc_vendor)); 155239278Sgonzo 156239278Sgonzo err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 157239278Sgonzo NULL, (void *)ohci_interrupt, sc, &sc->sc_intr_hdl); 158239278Sgonzo if (err) { 159239278Sgonzo sc->sc_intr_hdl = NULL; 160239278Sgonzo goto fail; 161239278Sgonzo } 162239278Sgonzo 163239278Sgonzo usbctrl = lpc_pwr_read(dev, LPC_CLKPWR_USB_CTRL); 164239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_SLAVE_HCLK | LPC_CLKPWR_USB_CTRL_BUSKEEPER; 165239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl); 166239278Sgonzo 167239278Sgonzo /* Enable OTG I2C clock */ 168239278Sgonzo lpc_otg_wait_write_4(sc, LPC_OTG_CLOCK_CTRL, 169239278Sgonzo LPC_OTG_CLOCK_STATUS, LPC_OTG_CLOCK_CTRL_I2C_EN); 170239278Sgonzo 171239278Sgonzo /* Reset OTG I2C bus */ 172239278Sgonzo lpc_otg_i2c_reset(sc); 173239278Sgonzo 174239278Sgonzo lpc_isp3101_configure(dev, sc); 175239278Sgonzo 176239278Sgonzo /* Configure PLL */ 177239278Sgonzo usbctrl &= ~(LPC_CLKPWR_USB_CTRL_CLK_EN1 | LPC_CLKPWR_USB_CTRL_CLK_EN2); 178239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl); 179239278Sgonzo 180239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_CLK_EN1; 181239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl); 182239278Sgonzo 183239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_FDBKDIV(192-1); 184239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_POSTDIV(1); 185239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_PLL_PDOWN; 186239278Sgonzo 187239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl); 188239278Sgonzo do { 189239278Sgonzo usbctrl = lpc_pwr_read(dev, LPC_CLKPWR_USB_CTRL); 190239278Sgonzo if (i++ > 100000) { 191239278Sgonzo device_printf(dev, "USB OTG PLL doesn't lock!\n"); 192239278Sgonzo goto fail; 193239278Sgonzo } 194239278Sgonzo } while ((usbctrl & LPC_CLKPWR_USB_CTRL_PLL_LOCK) == 0); 195239278Sgonzo 196239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_CLK_EN2; 197239278Sgonzo usbctrl |= LPC_CLKPWR_USB_CTRL_HOST_NEED_CLK_EN; 198239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl); 199239278Sgonzo lpc_otg_wait_write_4(sc, LPC_OTG_CLOCK_CTRL, LPC_OTG_CLOCK_STATUS, 200239278Sgonzo (LPC_OTG_CLOCK_CTRL_AHB_EN | LPC_OTG_CLOCK_CTRL_OTG_EN | 201239278Sgonzo LPC_OTG_CLOCK_CTRL_I2C_EN | LPC_OTG_CLOCK_CTRL_HOST_EN)); 202239278Sgonzo 203239278Sgonzo otgstatus = lpc_otg_read_4(sc, LPC_OTG_STATUS); 204239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_STATUS, otgstatus | 205239278Sgonzo LPC_OTG_STATUS_HOST_EN); 206239278Sgonzo 207239278Sgonzo lpc_isp3101_write(sc, LPC_ISP3101_OTG_CONTROL_1, 208239278Sgonzo LPC_ISP3101_OTG1_VBUS_DRV); 209239278Sgonzo 210239278Sgonzo err = ohci_init(sc); 211239278Sgonzo if (err) 212239278Sgonzo goto fail; 213239278Sgonzo 214239278Sgonzo err = device_probe_and_attach(sc->sc_bus.bdev); 215239278Sgonzo if (err) 216239278Sgonzo goto fail; 217239278Sgonzo 218239278Sgonzo return (0); 219239278Sgonzo 220239278Sgonzofail: 221239278Sgonzo if (sc->sc_intr_hdl) 222239278Sgonzo bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); 223239278Sgonzo if (sc->sc_irq_res) 224239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 225239278Sgonzo if (sc->sc_io_res) 226239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res); 227239278Sgonzo 228239278Sgonzo return (ENXIO); 229239278Sgonzo} 230239278Sgonzo 231239278Sgonzostatic int 232239278Sgonzolpc_isp3101_read(struct ohci_softc *sc, int reg) 233239278Sgonzo{ 234239278Sgonzo int status; 235239278Sgonzo int i = 0; 236239278Sgonzo 237239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, 238239278Sgonzo (LPC_ISP3101_I2C_ADDR << 1) | I2C_START_BIT); 239239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, reg); 240239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, (LPC_ISP3101_I2C_ADDR << 1) | 241239278Sgonzo I2C_START_BIT | I2C_READ); 242239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, I2C_STOP_BIT | DUMMY_BYTE); 243239278Sgonzo 244239278Sgonzo do { 245239278Sgonzo status = lpc_otg_read_4(sc, LPC_OTG_I2C_STATUS); 246239278Sgonzo i++; 247239278Sgonzo } while ((status & LPC_OTG_I2C_STATUS_TDI) == 0 || i < 100000); 248239278Sgonzo 249239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_STATUS, LPC_OTG_I2C_STATUS_TDI); 250239278Sgonzo 251239278Sgonzo return (lpc_otg_read_4(sc, LPC_OTG_I2C_TXRX) & 0xff); 252239278Sgonzo} 253239278Sgonzo 254239278Sgonzostatic void 255239278Sgonzolpc_otg_i2c_reset(struct ohci_softc *sc) 256239278Sgonzo{ 257239278Sgonzo int ctrl; 258239278Sgonzo int i = 0; 259239278Sgonzo 260239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_CLKHI, 0x3f); 261239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_CLKLO, 0x3f); 262239278Sgonzo 263239278Sgonzo ctrl = lpc_otg_read_4(sc, LPC_OTG_I2C_CTRL); 264239278Sgonzo lpc_otg_write_4(sc, LPC_OTG_I2C_CTRL, ctrl | LPC_OTG_I2C_CTRL_SRST); 265239278Sgonzo 266239278Sgonzo do { 267239278Sgonzo ctrl = lpc_otg_read_4(sc, LPC_OTG_I2C_CTRL); 268239278Sgonzo i++; 269239278Sgonzo } while (ctrl & LPC_OTG_I2C_CTRL_SRST); 270239278Sgonzo} 271239278Sgonzo 272239278Sgonzostatic void 273239278Sgonzolpc_isp3101_write(struct ohci_softc *sc, int reg, int value) 274239278Sgonzo{ 275239278Sgonzo int status; 276239278Sgonzo int i = 0; 277239278Sgonzo 278239278Sgonzo bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX, 279239278Sgonzo (LPC_ISP3101_I2C_ADDR << 1) | I2C_START_BIT); 280239278Sgonzo bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX, 281239278Sgonzo (reg | I2C_WRITE)); 282239278Sgonzo bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX, 283239278Sgonzo (value | I2C_STOP_BIT)); 284239278Sgonzo 285239278Sgonzo do { 286239278Sgonzo status = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl, 287239278Sgonzo LPC_OTG_I2C_STATUS); 288239278Sgonzo i++; 289239278Sgonzo } while ((status & LPC_OTG_I2C_STATUS_TDI) == 0 || i < 100000); 290239278Sgonzo 291239278Sgonzo bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_STATUS, 292239278Sgonzo LPC_OTG_I2C_STATUS_TDI); 293239278Sgonzo} 294239278Sgonzo 295239278Sgonzostatic __inline void 296239278Sgonzolpc_isp3101_clear(struct ohci_softc *sc, int reg, int value) 297239278Sgonzo{ 298239278Sgonzo lpc_isp3101_write(sc, (reg | LPC_ISP3101_REG_CLEAR_ADDR), value); 299239278Sgonzo} 300239278Sgonzo 301239278Sgonzostatic void 302239278Sgonzolpc_isp3101_configure(device_t dev, struct ohci_softc *sc) 303239278Sgonzo{ 304239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_UART_EN); 305239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_1, ~LPC_ISP3101_MC1_SPEED_REG); 306239278Sgonzo lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_SPEED_REG); 307239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_2, ~0); 308239278Sgonzo lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_2, 309239278Sgonzo (LPC_ISP3101_MC2_BI_DI | LPC_ISP3101_MC2_PSW_EN 310239278Sgonzo | LPC_ISP3101_MC2_SPD_SUSP_CTRL)); 311239278Sgonzo 312239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_OTG_CONTROL_1, ~0); 313239278Sgonzo lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_DAT_SE0); 314239278Sgonzo lpc_isp3101_write(sc, LPC_ISP3101_OTG_CONTROL_1, 315239278Sgonzo (LPC_ISP3101_OTG1_DM_PULLDOWN | LPC_ISP3101_OTG1_DP_PULLDOWN)); 316239278Sgonzo 317239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_OTG_CONTROL_1, 318239278Sgonzo (LPC_ISP3101_OTG1_DM_PULLUP | LPC_ISP3101_OTG1_DP_PULLUP)); 319239278Sgonzo 320239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_LATCH, ~0); 321239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_FALLING, ~0); 322239278Sgonzo lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_RISING, ~0); 323239278Sgonzo 324239278Sgonzo device_printf(dev, 325239278Sgonzo "ISP3101 PHY <vendor:0x%04x, product:0x%04x, version:0x%04x>\n", 326239278Sgonzo (lpc_isp3101_read(sc, 0x00) | (lpc_isp3101_read(sc, 0x01) << 8)), 327239278Sgonzo (lpc_isp3101_read(sc, 0x03) | (lpc_isp3101_read(sc, 0x04) << 8)), 328239278Sgonzo (lpc_isp3101_read(sc, 0x14) | (lpc_isp3101_read(sc, 0x15) << 8))); 329239278Sgonzo} 330239278Sgonzo 331239278Sgonzostatic int 332239278Sgonzolpc_ohci_detach(device_t dev) 333239278Sgonzo{ 334239278Sgonzo return (0); 335239278Sgonzo} 336239278Sgonzo 337239278Sgonzo 338239278Sgonzostatic device_method_t lpc_ohci_methods[] = { 339239278Sgonzo /* Device interface */ 340239278Sgonzo DEVMETHOD(device_probe, lpc_ohci_probe), 341239278Sgonzo DEVMETHOD(device_attach, lpc_ohci_attach), 342239278Sgonzo DEVMETHOD(device_detach, lpc_ohci_detach), 343239278Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 344239278Sgonzo 345239278Sgonzo /* Bus interface */ 346239278Sgonzo DEVMETHOD(bus_print_child, bus_generic_print_child), 347239278Sgonzo { 0, 0 } 348239278Sgonzo}; 349239278Sgonzo 350239278Sgonzostatic driver_t lpc_ohci_driver = { 351239278Sgonzo "ohci", 352239278Sgonzo lpc_ohci_methods, 353239278Sgonzo sizeof(struct ohci_softc), 354239278Sgonzo}; 355239278Sgonzo 356239278Sgonzostatic devclass_t lpc_ohci_devclass; 357239278Sgonzo 358239278SgonzoDRIVER_MODULE(ohci, simplebus, lpc_ohci_driver, lpc_ohci_devclass, 0, 0); 359239278SgonzoMODULE_DEPEND(ohci, usb, 1, 1, 1); 360