summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorray <ray@FreeBSD.org>2013-03-20 15:39:27 +0000
committerray <ray@FreeBSD.org>2013-03-20 15:39:27 +0000
commita88f1a3d131b117c073d9babaa2cf03d4b2d232a (patch)
treef1b419d2a4a76881f82969c1ddfa46ffb1e62836 /sys/dev
parent1ba62d29d15f003883f84f1d20496240d9eda819 (diff)
downloadFreeBSD-src-a88f1a3d131b117c073d9babaa2cf03d4b2d232a.zip
FreeBSD-src-a88f1a3d131b117c073d9babaa2cf03d4b2d232a.tar.gz
Integrate Efika MX project back to home.
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/chipsets/ata-fsl.c238
-rw-r--r--sys/dev/uart/uart.h1
-rw-r--r--sys/dev/uart/uart_bus_fdt.c4
-rw-r--r--sys/dev/uart/uart_dev_imx.c436
-rw-r--r--sys/dev/uart/uart_dev_imx5xx.h222
-rw-r--r--sys/dev/usb/controller/ehci_imx.c282
6 files changed, 1183 insertions, 0 deletions
diff --git a/sys/dev/ata/chipsets/ata-fsl.c b/sys/dev/ata/chipsets/ata-fsl.c
new file mode 100644
index 0000000..5e5a686
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-fsl.c
@@ -0,0 +1,238 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/fdt.h>
+
+/* local prototypes */
+static int imx_ata_ch_attach(device_t dev);
+static int imx_ata_setmode(device_t dev, int target, int mode);
+
+static int
+imx_ata_probe(device_t dev)
+{
+ struct ata_pci_controller *ctrl;
+
+ if (!ofw_bus_is_compatible(dev, "fsl,imx51-ata"))
+ return (ENXIO);
+
+ ctrl = device_get_softc(dev);
+
+ device_set_desc(dev, "Freescale Integrated PATA Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static void
+imx_ata_intr(void *data)
+{
+ struct ata_pci_controller *ctrl = data;
+
+ bus_write_2(ctrl->r_res1, 0x28, bus_read_2(ctrl->r_res1, 0x28));
+ ctrl->interrupt[0].function(ctrl->interrupt[0].argument);
+}
+
+static int
+imx_ata_attach(device_t dev)
+{
+ struct ata_pci_controller *ctrl;
+ device_t child;
+ int unit;
+
+ ctrl = device_get_softc(dev);
+ /* do chipset specific setups only needed once */
+ ctrl->legacy = ata_legacy(dev);
+ ctrl->channels = 1;
+ ctrl->ichannels = -1;
+ ctrl->ch_attach = ata_pci_ch_attach;
+ ctrl->ch_detach = ata_pci_ch_detach;
+ ctrl->dev = dev;
+
+ ctrl->r_type1 = SYS_RES_MEMORY;
+ ctrl->r_rid1 = 0;
+ ctrl->r_res1 = bus_alloc_resource_any(dev, ctrl->r_type1,
+ &ctrl->r_rid1, RF_ACTIVE);
+
+ if (ata_setup_interrupt(dev, imx_ata_intr)) {
+ device_printf(dev, "failed to setup interrupt\n");
+ return ENXIO;
+ }
+
+ ctrl->channels = 1;
+
+ ctrl->ch_attach = imx_ata_ch_attach;
+ ctrl->setmode = imx_ata_setmode;
+
+ /* attach all channels on this controller */
+ unit = 0;
+ child = device_add_child(dev, "ata", ((unit == 0) && ctrl->legacy) ?
+ unit : devclass_find_free_unit(ata_devclass, 2));
+ if (child == NULL)
+ device_printf(dev, "failed to add ata child device\n");
+ else
+ device_set_ivars(child, (void *)(intptr_t)unit);
+
+ bus_generic_attach(dev);
+ return 0;
+}
+
+static int
+imx_ata_ch_attach(device_t dev)
+{
+ struct ata_pci_controller *ctrl;
+ struct ata_channel *ch;
+ int i;
+
+ ctrl = device_get_softc(device_get_parent(dev));
+ ch = device_get_softc(dev);
+ for (i = ATA_DATA; i < ATA_MAX_RES; i++)
+ ch->r_io[i].res = ctrl->r_res1;
+
+ bus_write_2(ctrl->r_res1, 0x24, 0x80);
+ DELAY(100);
+ bus_write_2(ctrl->r_res1, 0x24, 0xc0);
+ DELAY(100);
+
+
+ /* Write TIME_OFF/ON/1/2W */
+ bus_write_1(ctrl->r_res1, 0x00, 3);
+ bus_write_1(ctrl->r_res1, 0x01, 3);
+ bus_write_1(ctrl->r_res1, 0x02, (25 + 15) / 15);
+ bus_write_1(ctrl->r_res1, 0x03, (70 + 15) / 15);
+
+ /* Write TIME_2R/AX/RDX/4 */
+ bus_write_1(ctrl->r_res1, 0x04, (70 + 15) / 15);
+ bus_write_1(ctrl->r_res1, 0x05, (50 + 15) / 15 + 2);
+ bus_write_1(ctrl->r_res1, 0x06, 1);
+ bus_write_1(ctrl->r_res1, 0x07, (10 + 15) / 15);
+
+ /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */
+ bus_write_1(ctrl->r_res1, 0x08, (10 + 15) / 15);
+
+ bus_write_2(ctrl->r_res1, 0x24, 0xc1);
+ DELAY(30000);
+
+ /* setup ATA registers */
+ ch->r_io[ATA_DATA ].offset = 0xa0;
+ ch->r_io[ATA_FEATURE].offset = 0xa4;
+ ch->r_io[ATA_ERROR ].offset = 0xa4;
+ ch->r_io[ATA_COUNT ].offset = 0xa8;
+ ch->r_io[ATA_SECTOR ].offset = 0xac;
+ ch->r_io[ATA_CYL_LSB].offset = 0xb0;
+ ch->r_io[ATA_CYL_MSB].offset = 0xb4;
+ ch->r_io[ATA_DRIVE ].offset = 0xb8;
+ ch->r_io[ATA_COMMAND].offset = 0xbc;
+
+ ch->r_io[ATA_STATUS ].offset = 0xbc;
+ ch->r_io[ATA_ALTSTAT].offset = 0xd8;
+ ch->r_io[ATA_CONTROL].offset = 0xd8;
+
+ ata_pci_hw(dev);
+
+ ch->flags |= ATA_NO_SLAVE;
+ ch->flags |= ATA_USE_16BIT;
+ ch->flags |= ATA_CHECKS_CABLE;
+ ch->flags |= ATA_KNOWN_PRESENCE;
+
+ /* Clear pending interrupts. */
+ bus_write_2(ctrl->r_res1, 0x28, 0xf8);
+ /* Enable all, but Idle interrupts. */
+ bus_write_2(ctrl->r_res1, 0x2c, 0x88);
+
+ return 0;
+}
+
+static int
+imx_ata_setmode(device_t dev, int target, int mode)
+{
+
+ return (min(mode, ATA_PIO4));
+}
+
+static device_method_t imx_ata_methods[] = {
+ DEVMETHOD(device_probe, imx_ata_probe),
+ DEVMETHOD(device_attach, imx_ata_attach),
+ DEVMETHOD(device_detach, ata_pci_detach),
+ DEVMETHOD(device_suspend, ata_pci_suspend),
+ DEVMETHOD(device_resume, ata_pci_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(bus_read_ivar, ata_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ata_pci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ata_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
+ DEVMETHOD(pci_read_config, ata_pci_read_config),
+ DEVMETHOD(pci_write_config, ata_pci_write_config),
+ DEVMETHOD(bus_print_child, ata_pci_print_child),
+ DEVMETHOD(bus_child_location_str, ata_pci_child_location_str),
+ DEVMETHOD_END
+};
+static driver_t imx_ata_driver = {
+ "atapci",
+ imx_ata_methods,
+ sizeof(struct ata_pci_controller)
+};
+DRIVER_MODULE(imx_ata, simplebus, imx_ata_driver, ata_pci_devclass, NULL,
+ NULL);
+MODULE_VERSION(imx_ata, 1);
+MODULE_DEPEND(imx_ata, ata, 1, 1, 1);
+MODULE_DEPEND(imx_ata, atapci, 1, 1, 1);
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h
index 7647188..5229747 100644
--- a/sys/dev/uart/uart.h
+++ b/sys/dev/uart/uart.h
@@ -64,6 +64,7 @@ struct uart_bas {
*/
struct uart_class;
+extern struct uart_class uart_imx_class __attribute__((weak));
extern struct uart_class uart_ns8250_class __attribute__((weak));
extern struct uart_class uart_quicc_class __attribute__((weak));
extern struct uart_class uart_sab82532_class __attribute__((weak));
diff --git a/sys/dev/uart/uart_bus_fdt.c b/sys/dev/uart/uart_bus_fdt.c
index b55329e..cd4f71c 100644
--- a/sys/dev/uart/uart_bus_fdt.c
+++ b/sys/dev/uart/uart_bus_fdt.c
@@ -105,6 +105,8 @@ uart_fdt_probe(device_t dev)
sc->sc_class = &uart_ns8250_class;
else if (ofw_bus_is_compatible(dev, "lpc,uart"))
sc->sc_class = &uart_lpc_class;
+ else if (ofw_bus_is_compatible(dev, "fsl,imx-uart"))
+ sc->sc_class = &uart_imx_class;
else if (ofw_bus_is_compatible(dev, "arm,pl011"))
sc->sc_class = &uart_pl011_class;
else
@@ -184,6 +186,8 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
/*
* Finalize configuration.
*/
+ if (fdt_is_compatible(node, "fsl,imx-uart"))
+ class = &uart_imx_class;
if (fdt_is_compatible(node, "quicc"))
class = &uart_quicc_class;
if (fdt_is_compatible(node, "lpc"))
diff --git a/sys/dev/uart/uart_dev_imx.c b/sys/dev/uart/uart_dev_imx.c
new file mode 100644
index 0000000..81fe163
--- /dev/null
+++ b/sys/dev/uart/uart_dev_imx.c
@@ -0,0 +1,436 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kdb.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include <dev/uart/uart_dev_imx5xx.h>
+
+#include "uart_if.h"
+/*
+ * Low-level UART interface.
+ */
+static int imx_uart_probe(struct uart_bas *bas);
+static void imx_uart_init(struct uart_bas *bas, int, int, int, int);
+static void imx_uart_term(struct uart_bas *bas);
+static void imx_uart_putc(struct uart_bas *bas, int);
+static int imx_uart_rxready(struct uart_bas *bas);
+static int imx_uart_getc(struct uart_bas *bas, struct mtx *);
+
+static struct uart_ops uart_imx_uart_ops = {
+ .probe = imx_uart_probe,
+ .init = imx_uart_init,
+ .term = imx_uart_term,
+ .putc = imx_uart_putc,
+ .rxready = imx_uart_rxready,
+ .getc = imx_uart_getc,
+};
+
+static int
+imx_uart_probe(struct uart_bas *bas)
+{
+
+ return (0);
+}
+
+static void
+imx_uart_init(struct uart_bas *bas, int baudrate, int databits,
+ int stopbits, int parity)
+{
+
+}
+
+static void
+imx_uart_term(struct uart_bas *bas)
+{
+
+}
+
+static void
+imx_uart_putc(struct uart_bas *bas, int c)
+{
+
+ while (!(IS(bas, USR2, TXFE)))
+ ;
+ SETREG(bas, REG(UTXD), c);
+}
+
+static int
+imx_uart_rxready(struct uart_bas *bas)
+{
+
+ return ((IS(bas, USR2, RDR)) ? 1 : 0);
+}
+
+static int
+imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
+{
+ int c;
+
+ uart_lock(hwmtx);
+ while (!(IS(bas, USR2, RDR)))
+ ;
+
+ c = GETREG(bas, REG(URXD));
+ uart_unlock(hwmtx);
+#if defined(KDB)
+ if (c & FLD(URXD, BRK)) {
+ if (kdb_break())
+ return (0);
+ }
+#endif
+ return (c & 0xff);
+}
+
+/*
+ * High-level UART interface.
+ */
+struct imx_uart_softc {
+ struct uart_softc base;
+};
+
+static int imx_uart_bus_attach(struct uart_softc *);
+static int imx_uart_bus_detach(struct uart_softc *);
+static int imx_uart_bus_flush(struct uart_softc *, int);
+static int imx_uart_bus_getsig(struct uart_softc *);
+static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int imx_uart_bus_ipend(struct uart_softc *);
+static int imx_uart_bus_param(struct uart_softc *, int, int, int, int);
+static int imx_uart_bus_probe(struct uart_softc *);
+static int imx_uart_bus_receive(struct uart_softc *);
+static int imx_uart_bus_setsig(struct uart_softc *, int);
+static int imx_uart_bus_transmit(struct uart_softc *);
+
+static kobj_method_t imx_uart_methods[] = {
+ KOBJMETHOD(uart_attach, imx_uart_bus_attach),
+ KOBJMETHOD(uart_detach, imx_uart_bus_detach),
+ KOBJMETHOD(uart_flush, imx_uart_bus_flush),
+ KOBJMETHOD(uart_getsig, imx_uart_bus_getsig),
+ KOBJMETHOD(uart_ioctl, imx_uart_bus_ioctl),
+ KOBJMETHOD(uart_ipend, imx_uart_bus_ipend),
+ KOBJMETHOD(uart_param, imx_uart_bus_param),
+ KOBJMETHOD(uart_probe, imx_uart_bus_probe),
+ KOBJMETHOD(uart_receive, imx_uart_bus_receive),
+ KOBJMETHOD(uart_setsig, imx_uart_bus_setsig),
+ KOBJMETHOD(uart_transmit, imx_uart_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_imx_class = {
+ "imx",
+ imx_uart_methods,
+ sizeof(struct imx_uart_softc),
+ .uc_ops = &uart_imx_uart_ops,
+ .uc_range = 0x100,
+ .uc_rclk = 24000000 /* TODO: get value from CCM */
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+imx_uart_bus_attach(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ struct uart_devinfo *di;
+
+ bas = &sc->sc_bas;
+ if (sc->sc_sysdev != NULL) {
+ di = sc->sc_sysdev;
+ imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
+ di->parity);
+ } else {
+ imx_uart_init(bas, 115200, 8, 1, 0);
+ }
+
+ sc->sc_rxfifosz = 1;
+ sc->sc_txfifosz = 1;
+
+ (void)imx_uart_bus_getsig(sc);
+
+ /* XXX workaround to have working console on manut prompt */
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE){
+ DIS(bas, UCR4, DREN);
+ } else {
+ ENA(bas, UCR4, DREN);
+ }
+ DIS(bas, UCR1, RRDYEN);
+ DIS(bas, UCR1, IDEN);
+ DIS(bas, UCR3, RXDSEN);
+ DIS(bas, UCR2, ATEN);
+ DIS(bas, UCR1, TXMPTYEN);
+ DIS(bas, UCR1, TRDYEN);
+ DIS(bas, UCR4, TCEN);
+ DIS(bas, UCR4, OREN);
+ ENA(bas, UCR4, BKEN);
+ DIS(bas, UCR4, WKEN);
+ DIS(bas, UCR1, ADEN);
+ DIS(bas, UCR3, ACIEN);
+ DIS(bas, UCR2, ESCI);
+ DIS(bas, UCR4, ENIRI);
+ DIS(bas, UCR3, AIRINTEN);
+ DIS(bas, UCR3, AWAKEN);
+ DIS(bas, UCR3, FRAERREN);
+ DIS(bas, UCR3, PARERREN);
+ DIS(bas, UCR1, RTSDEN);
+ DIS(bas, UCR2, RTSEN);
+ DIS(bas, UCR3, DTREN);
+ DIS(bas, UCR3, RI);
+ DIS(bas, UCR3, DCD);
+ DIS(bas, UCR3, DTRDEN);
+
+ /* ACK all interrupts */
+ SETREG(bas, REG(USR1), 0xffff);
+ SETREG(bas, REG(USR2), 0xffff);
+ return (0);
+}
+
+static int
+imx_uart_bus_detach(struct uart_softc *sc)
+{
+
+ SETREG(&sc->sc_bas, REG(UCR4), 0);
+
+ return (0);
+}
+
+static int
+imx_uart_bus_flush(struct uart_softc *sc, int what)
+{
+
+ /* TODO */
+ return (0);
+}
+
+static int
+imx_uart_bus_getsig(struct uart_softc *sc)
+{
+ uint32_t new, old, sig;
+ uint8_t bes;
+
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ uart_lock(sc->sc_hwmtx);
+ bes = GETREG(&sc->sc_bas, REG(USR2));
+ uart_unlock(sc->sc_hwmtx);
+ /* XXX: chip can show delta */
+ SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD);
+ new = sig & ~SER_MASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+
+ return (sig);
+}
+
+static int
+imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas;
+ int error;
+
+ bas = &sc->sc_bas;
+ error = 0;
+ uart_lock(sc->sc_hwmtx);
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ /* TODO */
+ break;
+ case UART_IOCTL_BAUD:
+ /* TODO */
+ *(int*)data = 115200;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ uart_unlock(sc->sc_hwmtx);
+
+ return (error);
+}
+
+static int
+imx_uart_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend;
+ uint32_t usr1, usr2;
+ uint32_t ucr1, ucr4;
+
+ bas = &sc->sc_bas;
+ ipend = 0;
+
+ uart_lock(sc->sc_hwmtx);
+
+ /* Read pending interrupts */
+ usr1 = GETREG(bas, REG(USR1));
+ usr2 = GETREG(bas, REG(USR2));
+ /* ACK interrupts */
+ SETREG(bas, REG(USR1), usr1);
+ SETREG(bas, REG(USR2), usr2);
+
+ ucr1 = GETREG(bas, REG(UCR1));
+ ucr4 = GETREG(bas, REG(UCR4));
+
+ if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) {
+ DIS(bas, UCR1, TXMPTYEN);
+ /* Continue TXing */
+ ipend |= SER_INT_TXIDLE;
+ }
+ if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) {
+ DIS(bas, UCR4, DREN);
+ /* Wow, new char on input */
+ ipend |= SER_INT_RXREADY;
+ }
+ if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN)))
+ ipend |= SER_INT_BREAK;
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (ipend);
+}
+
+static int
+imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+
+ uart_lock(sc->sc_hwmtx);
+ imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+imx_uart_bus_probe(struct uart_softc *sc)
+{
+ int error;
+
+ error = imx_uart_probe(&sc->sc_bas);
+ if (error)
+ return (error);
+
+ device_set_desc(sc->sc_dev, "imx_uart");
+ return (0);
+}
+
+static int
+imx_uart_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int xc, out;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+
+ /* Read while we have anything in FIFO */
+ while (IS(bas, USR2, RDR)) {
+ if (uart_rx_full(sc)) {
+ /* No space left in input buffer */
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ break;
+ }
+ out = 0;
+ xc = GETREG(bas, REG(URXD));
+
+ /* We have valid char */
+ if (xc & FLD(URXD, CHARRDY))
+ out = xc & 0x000000ff;
+
+ if (xc & FLD(URXD, FRMERR))
+ out |= UART_STAT_FRAMERR;
+ if (xc & FLD(URXD, PRERR))
+ out |= UART_STAT_PARERR;
+ if (xc & FLD(URXD, OVRRUN))
+ out |= UART_STAT_OVERRUN;
+ if (xc & FLD(URXD, BRK))
+ out |= UART_STAT_BREAK;
+
+ uart_rx_put(sc, out);
+ }
+ /* Reenable Data Ready interrupt */
+ ENA(bas, UCR4, DREN);
+
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+imx_uart_bus_setsig(struct uart_softc *sc, int sig)
+{
+
+ /* TODO: implement (?) */
+
+ /* XXX workaround to have working console on mount prompt */
+ /* Enable RX interrupt */
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE)
+ if (!IS(&sc->sc_bas, UCR4, DREN))
+ ENA(&sc->sc_bas, UCR4, DREN);
+ return (0);
+}
+
+static int
+imx_uart_bus_transmit(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ int i;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+
+ /* Fill TX FIFO */
+ for (i = 0; i < sc->sc_txdatasz; i++) {
+ SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff);
+ }
+
+ sc->sc_txbusy = 1;
+ /* Call me when ready */
+ ENA(bas, UCR1, TXMPTYEN);
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (0);
+}
diff --git a/sys/dev/uart/uart_dev_imx5xx.h b/sys/dev/uart/uart_dev_imx5xx.h
new file mode 100644
index 0000000..ac24a3f
--- /dev/null
+++ b/sys/dev/uart/uart_dev_imx5xx.h
@@ -0,0 +1,222 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _UART_DEV_IMX5XX_H
+#define _UART_DEV_IMX5XX_H
+
+#define IMXUART_URXD_REG 0x0000 /* UART Receiver Register */
+#define IMXUART_URXD_CHARRDY (1 << 15)
+#define IMXUART_URXD_ERR (1 << 14)
+#define IMXUART_URXD_OVRRUN (1 << 13)
+#define IMXUART_URXD_FRMERR (1 << 12)
+#define IMXUART_URXD_BRK (1 << 11)
+#define IMXUART_URXD_PRERR (1 << 10)
+#define IMXUART_URXD_RX_DATA_MASK 0xff
+
+#define IMXUART_UTXD_REG 0x0040 /* UART Transmitter Register */
+#define IMXUART_UTXD_TX_DATA_MASK 0xff
+
+#define IMXUART_UCR1_REG 0x0080 /* UART Control Register 1 */
+#define IMXUART_UCR1_ADEN (1 << 15)
+#define IMXUART_UCR1_ADBR (1 << 14)
+#define IMXUART_UCR1_TRDYEN (1 << 13)
+#define IMXUART_UCR1_IDEN (1 << 12)
+#define IMXUART_UCR1_ICD_MASK (3 << 10)
+#define IMXUART_UCR1_ICD_IDLE4 (0 << 10)
+#define IMXUART_UCR1_ICD_IDLE8 (1 << 10)
+#define IMXUART_UCR1_ICD_IDLE16 (2 << 10)
+#define IMXUART_UCR1_ICD_IDLE32 (3 << 10)
+#define IMXUART_UCR1_RRDYEN (1 << 9)
+#define IMXUART_UCR1_RXDMAEN (1 << 8)
+#define IMXUART_UCR1_IREN (1 << 7)
+#define IMXUART_UCR1_TXMPTYEN (1 << 6)
+#define IMXUART_UCR1_RTSDEN (1 << 5)
+#define IMXUART_UCR1_SNDBRK (1 << 4)
+#define IMXUART_UCR1_TXDMAEN (1 << 3)
+#define IMXUART_UCR1_ATDMAEN (1 << 2)
+#define IMXUART_UCR1_DOZE (1 << 1)
+#define IMXUART_UCR1_UARTEN (1 << 0)
+
+#define IMXUART_UCR2_REG 0x0084 /* UART Control Register 2 */
+#define IMXUART_UCR2_ESCI (1 << 15)
+#define IMXUART_UCR2_IRTS (1 << 14)
+#define IMXUART_UCR2_CTSC (1 << 13)
+#define IMXUART_UCR2_CTS (1 << 12)
+#define IMXUART_UCR2_ESCEN (1 << 11)
+#define IMXUART_UCR2_RTEC_MASK (3 << 9)
+#define IMXUART_UCR2_RTEC_REDGE (0 << 9)
+#define IMXUART_UCR2_RTEC_FEDGE (1 << 9)
+#define IMXUART_UCR2_RTEC_EDGE (2 << 9)
+#define IMXUART_UCR2_PREN (1 << 8)
+#define IMXUART_UCR2_PROE (1 << 7)
+#define IMXUART_UCR2_STPB (1 << 6)
+#define IMXUART_UCR2_WS (1 << 5)
+#define IMXUART_UCR2_RTSEN (1 << 4)
+#define IMXUART_UCR2_ATEN (1 << 3)
+#define IMXUART_UCR2_TXEN (1 << 2)
+#define IMXUART_UCR2_RXEN (1 << 1)
+#define IMXUART_UCR2_N_SRST (1 << 0)
+
+#define IMXUART_UCR3_REG 0x0088 /* UART Control Register 3 */
+#define IMXUART_UCR3_DPEC_MASK (3 << 14)
+#define IMXUART_UCR3_DPEC_REDGE (0 << 14)
+#define IMXUART_UCR3_DPEC_FEDGE (1 << 14)
+#define IMXUART_UCR3_DPEC_EDGE (2 << 14)
+#define IMXUART_UCR3_DTREN (1 << 13)
+#define IMXUART_UCR3_PARERREN (1 << 12)
+#define IMXUART_UCR3_FRAERREN (1 << 11)
+#define IMXUART_UCR3_DSR (1 << 10)
+#define IMXUART_UCR3_DCD (1 << 9)
+#define IMXUART_UCR3_RI (1 << 8)
+#define IMXUART_UCR3_ADNIMP (1 << 7)
+#define IMXUART_UCR3_RXDSEN (1 << 6)
+#define IMXUART_UCR3_AIRINTEN (1 << 5)
+#define IMXUART_UCR3_AWAKEN (1 << 4)
+#define IMXUART_UCR3_DTRDEN (1 << 3)
+#define IMXUART_UCR3_RXDMUXSEL (1 << 2)
+#define IMXUART_UCR3_INVT (1 << 1)
+#define IMXUART_UCR3_ACIEN (1 << 0)
+
+#define IMXUART_UCR4_REG 0x008c /* UART Control Register 4 */
+#define IMXUART_UCR4_CTSTL_MASK (0x3f << 10)
+#define IMXUART_UCR4_CTSTL_SHIFT 10
+#define IMXUART_UCR4_INVR (1 << 9)
+#define IMXUART_UCR4_ENIRI (1 << 8)
+#define IMXUART_UCR4_WKEN (1 << 7)
+#define IMXUART_UCR4_IDDMAEN (1 << 6)
+#define IMXUART_UCR4_IRSC (1 << 5)
+#define IMXUART_UCR4_LPBYP (1 << 4)
+#define IMXUART_UCR4_TCEN (1 << 3)
+#define IMXUART_UCR4_BKEN (1 << 2)
+#define IMXUART_UCR4_OREN (1 << 1)
+#define IMXUART_UCR4_DREN (1 << 0)
+
+#define IMXUART_UFCR_REG 0x0090 /* UART FIFO Control Register */
+#define IMXUART_UFCR_TXTL_MASK (0x3f << 10)
+#define IMXUART_UFCR_TXTL_SHIFT 10
+#define IMXUART_UFCR_RFDIV_MASK (0x07 << 7)
+#define IMXUART_UFCR_RFDIV_SHIFT 7
+#define IMXUART_UFCR_RFDIV_SHIFT 7
+#define IMXUART_UFCR_RFDIV_DIV6 (0 << 7)
+#define IMXUART_UFCR_RFDIV_DIV5 (1 << 7)
+#define IMXUART_UFCR_RFDIV_DIV4 (2 << 7)
+#define IMXUART_UFCR_RFDIV_DIV3 (3 << 7)
+#define IMXUART_UFCR_RFDIV_DIV2 (4 << 7)
+#define IMXUART_UFCR_RFDIV_DIV1 (5 << 7)
+#define IMXUART_UFCR_RFDIV_DIV7 (6 << 7)
+#define IMXUART_UFCR_DCEDTE (1 << 6)
+#define IMXUART_UFCR_RXTL_MASK 0x0000003f
+#define IMXUART_UFCR_RXTL_SHIFT 0
+
+#define IMXUART_USR1_REG 0x0094 /* UART Status Register 1 */
+#define IMXUART_USR1_PARITYERR (1 << 15)
+#define IMXUART_USR1_RTSS (1 << 14)
+#define IMXUART_USR1_TRDY (1 << 13)
+#define IMXUART_USR1_RTSD (1 << 12)
+#define IMXUART_USR1_ESCF (1 << 11)
+#define IMXUART_USR1_FRAMERR (1 << 10)
+#define IMXUART_USR1_RRDY (1 << 9)
+#define IMXUART_USR1_AGTIM (1 << 8)
+#define IMXUART_USR1_DTRD (1 << 7)
+#define IMXUART_USR1_RXDS (1 << 6)
+#define IMXUART_USR1_AIRINT (1 << 5)
+#define IMXUART_USR1_AWAKE (1 << 4)
+/* 6040 5008 XXX */
+
+#define IMXUART_USR2_REG 0x0098 /* UART Status Register 2 */
+#define IMXUART_USR2_ADET (1 << 15)
+#define IMXUART_USR2_TXFE (1 << 14)
+#define IMXUART_USR2_DTRF (1 << 13)
+#define IMXUART_USR2_IDLE (1 << 12)
+#define IMXUART_USR2_ACST (1 << 11)
+#define IMXUART_USR2_RIDELT (1 << 10)
+#define IMXUART_USR2_RIIN (1 << 9)
+#define IMXUART_USR2_IRINT (1 << 8)
+#define IMXUART_USR2_WAKE (1 << 7)
+#define IMXUART_USR2_DCDDELT (1 << 6)
+#define IMXUART_USR2_DCDIN (1 << 5)
+#define IMXUART_USR2_RTSF (1 << 4)
+#define IMXUART_USR2_TXDC (1 << 3)
+#define IMXUART_USR2_BRCD (1 << 2)
+#define IMXUART_USR2_ORE (1 << 1)
+#define IMXUART_USR2_RDR (1 << 0)
+
+#define IMXUART_UESC_REG 0x009c /* UART Escape Character Register */
+#define IMXUART_UESC_ESC_CHAR_MASK 0x000000ff
+
+#define IMXUART_UTIM_REG 0x00a0 /* UART Escape Timer Register */
+#define IMXUART_UTIM_TIM_MASK 0x00000fff
+
+#define IMXUART_UBIR_REG 0x00a4 /* UART BRM Incremental Register */
+#define IMXUART_UBIR_INC_MASK 0x0000ffff
+
+#define IMXUART_UBMR_REG 0x00a8 /* UART BRM Modulator Register */
+#define IMXUART_UBMR_MOD_MASK 0x0000ffff
+
+#define IMXUART_UBRC_REG 0x00ac /* UART Baud Rate Count Register */
+#define IMXUART_UBRC_BCNT_MASK 0x0000ffff
+
+#define IMXUART_ONEMS_REG 0x00b0 /* UART One Millisecond Register */
+#define IMXUART_ONEMS_ONEMS_MASK 0x00ffffff
+
+#define IMXUART_UTS_REG 0x00b4 /* UART Test Register */
+#define IMXUART_UTS_FRCPERR (1 << 13)
+#define IMXUART_UTS_LOOP (1 << 12)
+#define IMXUART_UTS_DBGEN (1 << 11)
+#define IMXUART_UTS_LOOPIR (1 << 10)
+#define IMXUART_UTS_RXDBG (1 << 9)
+#define IMXUART_UTS_TXEMPTY (1 << 6)
+#define IMXUART_UTS_RXEMPTY (1 << 5)
+#define IMXUART_UTS_TXFULL (1 << 4)
+#define IMXUART_UTS_RXFULL (1 << 3)
+#define IMXUART_UTS_SOFTRST (1 << 0)
+
+#define REG(_r) IMXUART_ ## _r ## _REG
+#define FLD(_r, _v) IMXUART_ ## _r ## _ ## _v
+
+#define GETREG(bas, reg) \
+ bus_space_read_4((bas)->bst, (bas)->bsh, (reg))
+#define SETREG(bas, reg, value) \
+ bus_space_write_4((bas)->bst, (bas)->bsh, (reg), (value))
+
+#define CLR(_bas, _r, _b) \
+ SETREG((_bas), (_r), GETREG((_bas), (_r)) & ~(_b))
+#define SET(_bas, _r, _b) \
+ SETREG((_bas), (_r), GETREG((_bas), (_r)) | (_b))
+#define IS_SET(_bas, _r, _b) \
+ ((GETREG((_bas), (_r)) & (_b)) ? 1 : 0)
+
+#define ENA(_bas, _r, _b) SET((_bas), REG(_r), FLD(_r, _b))
+#define DIS(_bas, _r, _b) CLR((_bas), REG(_r), FLD(_r, _b))
+#define IS(_bas, _r, _b) IS_SET((_bas), REG(_r), FLD(_r, _b))
+
+
+#endif /* _UART_DEV_IMX5XX_H */
diff --git a/sys/dev/usb/controller/ehci_imx.c b/sys/dev/usb/controller/ehci_imx.c
new file mode 100644
index 0000000..e9f148c
--- /dev/null
+++ b/sys/dev/usb/controller/ehci_imx.c
@@ -0,0 +1,282 @@
+/*-
+ * Copyright (c) 2010-2012 Semihalf
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Oleksandr Rybalko
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/condvar.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include "opt_platform.h"
+
+#define FSL_EHCI_COUNT 4
+#define FSL_EHCI_REG_OFF 0x100
+#define FSL_EHCI_REG_SIZE 0x100
+#define FSL_EHCI_REG_STEP 0x200
+
+struct imx_ehci_softc {
+ ehci_softc_t ehci[FSL_EHCI_COUNT];
+ /* MEM + 4 interrupts */
+ struct resource *sc_res[1 + FSL_EHCI_COUNT];
+};
+
+/* i.MX515 have 4 EHCI inside USB core */
+/* TODO: we can get number of EHCIs by IRQ allocation */
+static struct resource_spec imx_ehci_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ /* RF_OPTIONAL will allow to use driver for systems with 3 EHCIs */
+ { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL },
+ { -1, 0 }
+};
+
+/* Forward declarations */
+static int fsl_ehci_attach(device_t self);
+static int fsl_ehci_detach(device_t self);
+static int fsl_ehci_probe(device_t self);
+
+static device_method_t ehci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fsl_ehci_probe),
+ DEVMETHOD(device_attach, fsl_ehci_attach),
+ DEVMETHOD(device_detach, fsl_ehci_detach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ { 0, 0 }
+};
+
+/* kobj_class definition */
+static driver_t ehci_driver = {
+ "ehci",
+ ehci_methods,
+ sizeof(struct imx_ehci_softc)
+};
+
+static devclass_t ehci_devclass;
+
+DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
+MODULE_DEPEND(ehci, usb, 1, 1, 1);
+
+/*
+ * Public methods
+ */
+static int
+fsl_ehci_probe(device_t dev)
+{
+
+ if (ofw_bus_is_compatible(dev, "fsl,usb-4core") == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale integrated USB controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fsl_ehci_attach(device_t self)
+{
+ struct imx_ehci_softc *sc;
+ bus_space_tag_t iot;
+ ehci_softc_t *esc;
+ int err, i, rid;
+
+ sc = device_get_softc(self);
+ rid = 0;
+
+ /* Allocate io resource for EHCI */
+ if (bus_alloc_resources(self, imx_ehci_spec, sc->sc_res)) {
+ device_printf(self, "could not allocate resources\n");
+ return (ENXIO);
+ }
+ iot = rman_get_bustag(sc->sc_res[0]);
+
+ /* TODO: Power/clock enable */
+ /* TODO: basic init */
+
+ for (i = 0; i < FSL_EHCI_COUNT; i ++) {
+ /* No interrupt - no driver */
+ if (sc->sc_res[1 + i] == NULL)
+ continue;
+
+ esc = &sc->ehci[i];
+ esc->sc_io_tag = iot;
+ esc->sc_bus.parent = self;
+ esc->sc_bus.devices = esc->sc_devices;
+ esc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+
+ if (usb_bus_mem_alloc_all(&esc->sc_bus, USB_GET_DMA_TAG(self),
+ &ehci_iterate_hw_softc))
+ continue;
+
+ /*
+ * Set handle to USB related registers subregion used by
+ * generic EHCI driver.
+ */
+ err = bus_space_subregion(iot,
+ rman_get_bushandle(sc->sc_res[0]),
+ FSL_EHCI_REG_OFF + (i * FSL_EHCI_REG_STEP),
+ FSL_EHCI_REG_SIZE, &esc->sc_io_hdl);
+ if (err != 0)
+ continue;
+
+ /* Setup interrupt handler */
+ err = bus_setup_intr(self, sc->sc_res[1 + i], INTR_TYPE_BIO,
+ NULL, (driver_intr_t *)ehci_interrupt, esc,
+ &esc->sc_intr_hdl);
+ if (err) {
+ device_printf(self, "Could not setup irq, "
+ "for EHCI%d %d\n", i, err);
+ continue;
+ }
+
+ /* Add USB device */
+ esc->sc_bus.bdev = device_add_child(self, "usbus", -1);
+ if (!esc->sc_bus.bdev) {
+ device_printf(self, "Could not add USB device\n");
+ err = bus_teardown_intr(self, esc->sc_irq_res,
+ esc->sc_intr_hdl);
+ if (err)
+ device_printf(self, "Could not tear down irq,"
+ " %d\n", err);
+ continue;
+ }
+ device_set_ivars(esc->sc_bus.bdev, &esc->sc_bus);
+
+ esc->sc_id_vendor = 0x1234;
+ strlcpy(esc->sc_vendor, "Freescale", sizeof(esc->sc_vendor));
+
+ /* Set flags */
+ esc->sc_flags |= EHCI_SCFLG_DONTRESET | EHCI_SCFLG_NORESTERM;
+
+ err = ehci_init(esc);
+ if (!err) {
+ esc->sc_flags |= EHCI_SCFLG_DONEINIT;
+ err = device_probe_and_attach(esc->sc_bus.bdev);
+ } else {
+ device_printf(self, "USB init failed err=%d\n", err);
+
+ device_delete_child(self, esc->sc_bus.bdev);
+ esc->sc_bus.bdev = NULL;
+
+ err = bus_teardown_intr(self, esc->sc_irq_res,
+ esc->sc_intr_hdl);
+ if (err)
+ device_printf(self, "Could not tear down irq,"
+ " %d\n", err);
+
+ continue;
+ }
+ }
+ return (0);
+}
+
+static int
+fsl_ehci_detach(device_t self)
+{
+ struct imx_ehci_softc *sc;
+ ehci_softc_t *esc;
+ int err, i;
+
+ sc = device_get_softc(self);
+
+ for (i = 0; i < FSL_EHCI_COUNT; i ++) {
+ esc = &sc->ehci[i];
+ if (esc->sc_flags & EHCI_SCFLG_DONEINIT)
+ continue;
+ /*
+ * only call ehci_detach() after ehci_init()
+ */
+ if (esc->sc_flags & EHCI_SCFLG_DONEINIT) {
+ ehci_detach(esc);
+ esc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
+ }
+
+ /*
+ * Disable interrupts that might have been switched on in
+ * ehci_init.
+ */
+ if (esc->sc_io_tag && esc->sc_io_hdl)
+ bus_space_write_4(esc->sc_io_tag, esc->sc_io_hdl,
+ EHCI_USBINTR, 0);
+
+ if (esc->sc_irq_res && esc->sc_intr_hdl) {
+ err = bus_teardown_intr(self, esc->sc_irq_res,
+ esc->sc_intr_hdl);
+ if (err) {
+ device_printf(self, "Could not tear down irq,"
+ " %d\n", err);
+ return (err);
+ }
+ esc->sc_intr_hdl = NULL;
+ }
+
+ if (esc->sc_bus.bdev) {
+ device_delete_child(self, esc->sc_bus.bdev);
+ esc->sc_bus.bdev = NULL;
+ }
+ }
+
+ /* During module unload there are lots of children leftover */
+ device_delete_children(self);
+
+ if (sc->sc_res[0])
+ bus_release_resources(self, imx_ehci_spec, sc->sc_res);
+
+ return (0);
+}
OpenPOWER on IntegriCloud