[rtems-libbsd commit] Import am335x usb driver file from FreeBSD.

Sebastian Huber sebh at rtems.org
Thu Jul 13 05:31:44 UTC 2017


Module:    rtems-libbsd
Branch:    master
Commit:    bd3c01a1260ced850ee348809712be1f2db24772
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=bd3c01a1260ced850ee348809712be1f2db24772

Author:    Sichen Zhao <1473996754 at qq.com>
Date:      Thu Jul 13 10:24:04 2017 +0800

Import am335x usb driver file from FreeBSD.

---

 freebsd/sys/arm/ti/am335x/am335x_musb.c   |  421 +++
 freebsd/sys/arm/ti/am335x/am335x_prcm.c   |  857 ++++++
 freebsd/sys/arm/ti/am335x/am335x_scm.h    |   49 +
 freebsd/sys/arm/ti/am335x/am335x_usbss.c  |  226 ++
 freebsd/sys/arm/ti/ti_cpuid.h             |   83 +
 freebsd/sys/arm/ti/ti_prcm.c              |  357 +++
 freebsd/sys/arm/ti/ti_prcm.h              |  207 ++
 freebsd/sys/arm/ti/ti_scm.c               |  176 ++
 freebsd/sys/arm/ti/ti_scm.h               |   56 +
 freebsd/sys/arm/ti/tivar.h                |   41 +
 freebsd/sys/dev/fdt/fdt_pinctrl.h         |   58 +
 freebsd/sys/dev/usb/controller/musb_otg.c | 4257 +++++++++++++++++++++++++++++
 freebsd/sys/dev/usb/controller/musb_otg.h |  435 +++
 freebsd/sys/sys/timeet.h                  |  106 +
 freebsd/sys/sys/watchdog.h                |  115 +
 15 files changed, 7444 insertions(+)

diff --git a/freebsd/sys/arm/ti/am335x/am335x_musb.c b/freebsd/sys/arm/ti/am335x/am335x_musb.c
new file mode 100644
index 0000000..52d799c
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/am335x_musb.c
@@ -0,0 +1,421 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ *
+ * 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 <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <rtems/bsd/sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/ofw/openfirm.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_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#define	USB_DEBUG_VAR usbssdebug
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/musb_otg.h>
+#include <dev/usb/usb_debug.h>
+
+#include <sys/rman.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/am335x/am335x_scm.h>
+
+#define USBCTRL_REV		0x00
+#define USBCTRL_CTRL		0x14
+#define USBCTRL_STAT		0x18
+#define USBCTRL_IRQ_STAT0	0x30
+#define		IRQ_STAT0_RXSHIFT	16
+#define		IRQ_STAT0_TXSHIFT	0
+#define USBCTRL_IRQ_STAT1	0x34
+#define 	IRQ_STAT1_DRVVBUS	(1 << 8)
+#define USBCTRL_INTEN_SET0	0x38
+#define USBCTRL_INTEN_SET1	0x3C
+#define 	USBCTRL_INTEN_USB_ALL	0x1ff
+#define 	USBCTRL_INTEN_USB_SOF	(1 << 3)
+#define USBCTRL_INTEN_CLR0	0x40
+#define USBCTRL_INTEN_CLR1	0x44
+#define USBCTRL_UTMI		0xE0
+#define		USBCTRL_UTMI_FSDATAEXT		(1 << 1)
+#define USBCTRL_MODE		0xE8
+#define 	USBCTRL_MODE_IDDIG		(1 << 8)
+#define 	USBCTRL_MODE_IDDIGMUX		(1 << 7)
+
+/* USBSS resource + 2 MUSB ports */
+
+#define RES_USBCORE	0
+#define RES_USBCTRL	1
+
+#define	USB_WRITE4(sc, idx, reg, val)	do {		\
+	bus_write_4((sc)->sc_mem_res[idx], (reg), (val));	\
+} while (0)
+
+#define	USB_READ4(sc, idx, reg) bus_read_4((sc)->sc_mem_res[idx], (reg))
+
+#define	USBCTRL_WRITE4(sc, reg, val)	\
+    USB_WRITE4((sc), RES_USBCTRL, (reg), (val))
+#define	USBCTRL_READ4(sc, reg)		\
+    USB_READ4((sc), RES_USBCTRL, (reg))
+
+static struct resource_spec am335x_musbotg_mem_spec[] = {
+	{ SYS_RES_MEMORY,   0,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   1,  RF_ACTIVE },
+	{ -1,               0,  0 }
+};
+
+#ifdef USB_DEBUG
+static int usbssdebug = 0;
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, am335x_usbss, CTLFLAG_RW, 0, "AM335x USBSS");
+SYSCTL_INT(_hw_usb_am335x_usbss, OID_AUTO, debug, CTLFLAG_RW,
+    &usbssdebug, 0, "Debug level");
+#endif
+
+static device_probe_t musbotg_probe;
+static device_attach_t musbotg_attach;
+static device_detach_t musbotg_detach;
+
+struct musbotg_super_softc {
+	struct musbotg_softc	sc_otg;
+	struct resource		*sc_mem_res[2];
+	int			sc_irq_rid;
+};
+
+static void
+musbotg_vbus_poll(struct musbotg_super_softc *sc)
+{
+	uint32_t stat;
+
+	if (sc->sc_otg.sc_mode == MUSB2_DEVICE_MODE)
+		musbotg_vbus_interrupt(&sc->sc_otg, 1);
+	else {
+		stat = USBCTRL_READ4(sc, USBCTRL_STAT);
+		musbotg_vbus_interrupt(&sc->sc_otg, stat & 1);
+	}
+}
+
+/*
+ * Arg to musbotg_clocks_on and musbot_clocks_off is
+ * a uint32_t * pointing to the SCM register offset.
+ */
+static uint32_t USB_CTRL[] = {SCM_USB_CTRL0, SCM_USB_CTRL1};
+
+static void
+musbotg_clocks_on(void *arg)
+{
+	struct musbotg_softc *sc;
+	uint32_t c, reg;
+
+	sc = arg;
+        reg = USB_CTRL[sc->sc_id];
+
+	ti_scm_reg_read_4(reg, &c);
+	c &= ~3; /* Enable power */
+	c |= 1 << 19; /* VBUS detect enable */
+	c |= 1 << 20; /* Session end enable */
+	ti_scm_reg_write_4(reg, c);
+}
+
+static void
+musbotg_clocks_off(void *arg)
+{
+	struct musbotg_softc *sc;
+	uint32_t c, reg;
+
+	sc = arg;
+        reg = USB_CTRL[sc->sc_id];
+
+	/* Disable power to PHY */
+	ti_scm_reg_read_4(reg, &c);
+	ti_scm_reg_write_4(reg, c | 3);
+}
+
+static void
+musbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on)
+{
+	struct musbotg_super_softc *ssc = sc->sc_platform_data;
+	uint32_t epmask;
+
+	epmask = ((1 << ep) << IRQ_STAT0_RXSHIFT);
+	epmask |= ((1 << ep) << IRQ_STAT0_TXSHIFT);
+	if (on)
+		USBCTRL_WRITE4(ssc, USBCTRL_INTEN_SET0, epmask);
+	else
+		USBCTRL_WRITE4(ssc, USBCTRL_INTEN_CLR0, epmask);
+}
+
+static void
+musbotg_wrapper_interrupt(void *arg)
+{
+	struct musbotg_softc *sc = arg;
+	struct musbotg_super_softc *ssc = sc->sc_platform_data;
+	uint32_t stat, stat0, stat1;
+
+	stat = USBCTRL_READ4(ssc, USBCTRL_STAT);
+	stat0 = USBCTRL_READ4(ssc, USBCTRL_IRQ_STAT0);
+	stat1 = USBCTRL_READ4(ssc, USBCTRL_IRQ_STAT1);
+	if (stat0)
+		USBCTRL_WRITE4(ssc, USBCTRL_IRQ_STAT0, stat0);
+	if (stat1)
+		USBCTRL_WRITE4(ssc, USBCTRL_IRQ_STAT1, stat1);
+
+	DPRINTFN(4, "port%d: stat0=%08x stat1=%08x, stat=%08x\n",
+	    sc->sc_id, stat0, stat1, stat);
+
+	if (stat1 & IRQ_STAT1_DRVVBUS)
+		musbotg_vbus_interrupt(sc, stat & 1);
+
+	musbotg_interrupt(arg, ((stat0 >> 16) & 0xffff),
+	    stat0 & 0xffff, stat1 & 0xff);
+}
+
+static int
+musbotg_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "ti,musb-am33xx"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI AM33xx integrated USB OTG controller");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+musbotg_attach(device_t dev)
+{
+	struct musbotg_super_softc *sc = device_get_softc(dev);
+	char mode[16];
+	int err;
+	uint32_t reg;
+
+	sc->sc_otg.sc_id = device_get_unit(dev);
+
+	/* Request the memory resources */
+	err = bus_alloc_resources(dev, am335x_musbotg_mem_spec,
+		sc->sc_mem_res);
+	if (err) {
+		device_printf(dev,
+		    "Error: could not allocate mem resources\n");
+		return (ENXIO);
+	}
+
+	/* Request the IRQ resources */
+	sc->sc_otg.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &sc->sc_irq_rid, RF_ACTIVE);
+	if (sc->sc_otg.sc_irq_res == NULL) {
+		device_printf(dev,
+		    "Error: could not allocate irq resources\n");
+		return (ENXIO);
+	}
+
+	/* setup MUSB OTG USB controller interface softc */
+	sc->sc_otg.sc_clocks_on = &musbotg_clocks_on;
+	sc->sc_otg.sc_clocks_off = &musbotg_clocks_off;
+	sc->sc_otg.sc_clocks_arg = &sc->sc_otg;
+
+	sc->sc_otg.sc_ep_int_set = musbotg_ep_int_set;
+
+	/* initialise some bus fields */
+	sc->sc_otg.sc_bus.parent = dev;
+	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
+	sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES;
+	sc->sc_otg.sc_bus.dma_bits = 32;
+
+	/* get all DMA memory */
+	if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
+	    USB_GET_DMA_TAG(dev), NULL)) {
+		device_printf(dev,
+		    "Failed allocate bus mem for musb\n");
+		return (ENOMEM);
+	}
+	sc->sc_otg.sc_io_res = sc->sc_mem_res[RES_USBCORE];
+	sc->sc_otg.sc_io_tag =
+	    rman_get_bustag(sc->sc_otg.sc_io_res);
+	sc->sc_otg.sc_io_hdl =
+	    rman_get_bushandle(sc->sc_otg.sc_io_res);
+	sc->sc_otg.sc_io_size =
+	    rman_get_size(sc->sc_otg.sc_io_res);
+
+	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
+	if (!(sc->sc_otg.sc_bus.bdev)) {
+		device_printf(dev, "No busdev for musb\n");
+		goto error;
+	}
+	device_set_ivars(sc->sc_otg.sc_bus.bdev,
+	    &sc->sc_otg.sc_bus);
+
+	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res,
+	    INTR_TYPE_BIO | INTR_MPSAFE,
+	    NULL, (driver_intr_t *)musbotg_wrapper_interrupt,
+	    &sc->sc_otg, &sc->sc_otg.sc_intr_hdl);
+	if (err) {
+		sc->sc_otg.sc_intr_hdl = NULL;
+		device_printf(dev,
+		    "Failed to setup interrupt for musb\n");
+		goto error;
+	}
+
+	sc->sc_otg.sc_platform_data = sc;
+	if (OF_getprop(ofw_bus_get_node(dev), "dr_mode", mode,
+	    sizeof(mode)) > 0) {
+		if (strcasecmp(mode, "host") == 0)
+			sc->sc_otg.sc_mode = MUSB2_HOST_MODE;
+		else
+			sc->sc_otg.sc_mode = MUSB2_DEVICE_MODE;
+	} else {
+		/* Beaglebone defaults: USB0 device, USB1 HOST. */
+		if (sc->sc_otg.sc_id == 0)
+			sc->sc_otg.sc_mode = MUSB2_DEVICE_MODE;
+		else
+			sc->sc_otg.sc_mode = MUSB2_HOST_MODE;
+	}
+
+	/*
+	 * software-controlled function
+	 */
+
+	if (sc->sc_otg.sc_mode == MUSB2_HOST_MODE) {
+		reg = USBCTRL_READ4(sc, USBCTRL_MODE);
+		reg |= USBCTRL_MODE_IDDIGMUX;
+		reg &= ~USBCTRL_MODE_IDDIG;
+		USBCTRL_WRITE4(sc, USBCTRL_MODE, reg);
+		USBCTRL_WRITE4(sc, USBCTRL_UTMI,
+		    USBCTRL_UTMI_FSDATAEXT);
+	} else {
+		reg = USBCTRL_READ4(sc, USBCTRL_MODE);
+		reg |= USBCTRL_MODE_IDDIGMUX;
+		reg |= USBCTRL_MODE_IDDIG;
+		USBCTRL_WRITE4(sc, USBCTRL_MODE, reg);
+	}
+
+	reg = USBCTRL_INTEN_USB_ALL & ~USBCTRL_INTEN_USB_SOF;
+	USBCTRL_WRITE4(sc, USBCTRL_INTEN_SET1, reg);
+	USBCTRL_WRITE4(sc, USBCTRL_INTEN_CLR0, 0xffffffff);
+
+	err = musbotg_init(&sc->sc_otg);
+	if (!err)
+		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
+
+	if (err)
+		goto error;
+
+	/* poll VBUS one time */
+	musbotg_vbus_poll(sc);
+
+	return (0);
+
+error:
+	musbotg_detach(dev);
+	return (ENXIO);
+}
+
+static int
+musbotg_detach(device_t dev)
+{
+	struct musbotg_super_softc *sc = device_get_softc(dev);
+	int err;
+
+	/* during module unload there are lots of children leftover */
+	device_delete_children(dev);
+
+	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
+		/*
+		 * only call musbotg_uninit() after musbotg_init()
+		 */
+		musbotg_uninit(&sc->sc_otg);
+
+		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
+		    sc->sc_otg.sc_intr_hdl);
+		sc->sc_otg.sc_intr_hdl = NULL;
+	}
+
+	usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
+
+	/* Free resources if any */
+	if (sc->sc_mem_res[0])
+		bus_release_resources(dev, am335x_musbotg_mem_spec,
+		    sc->sc_mem_res);
+
+	if (sc->sc_otg.sc_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid,
+		    sc->sc_otg.sc_irq_res);
+
+	return (0);
+}
+
+static device_method_t musbotg_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, musbotg_probe),
+	DEVMETHOD(device_attach, musbotg_attach),
+	DEVMETHOD(device_detach, musbotg_detach),
+	DEVMETHOD(device_suspend, bus_generic_suspend),
+	DEVMETHOD(device_resume, bus_generic_resume),
+	DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+	DEVMETHOD_END
+};
+
+static driver_t musbotg_driver = {
+	.name = "musbotg",
+	.methods = musbotg_methods,
+	.size = sizeof(struct musbotg_super_softc),
+};
+
+static devclass_t musbotg_devclass;
+
+DRIVER_MODULE(musbotg, usbss, musbotg_driver, musbotg_devclass, 0, 0);
+MODULE_DEPEND(musbotg, usbss, 1, 1, 1);
diff --git a/freebsd/sys/arm/ti/am335x/am335x_prcm.c b/freebsd/sys/arm/ti/am335x/am335x_prcm.c
new file mode 100644
index 0000000..1d10f7f
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/am335x_prcm.c
@@ -0,0 +1,857 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * All rights reserved.
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+
+#include "am335x_scm.h"
+
+#define CM_PER				0
+#define CM_PER_L4LS_CLKSTCTRL		(CM_PER + 0x000)
+#define CM_PER_L3S_CLKSTCTRL		(CM_PER + 0x004)
+#define CM_PER_L3_CLKSTCTRL		(CM_PER + 0x00C)
+#define CM_PER_CPGMAC0_CLKCTRL		(CM_PER + 0x014)
+#define CM_PER_LCDC_CLKCTRL		(CM_PER + 0x018)
+#define CM_PER_USB0_CLKCTRL		(CM_PER + 0x01C)
+#define CM_PER_TPTC0_CLKCTRL		(CM_PER + 0x024)
+#define CM_PER_UART5_CLKCTRL		(CM_PER + 0x038)
+#define CM_PER_MMC0_CLKCTRL		(CM_PER + 0x03C)
+#define CM_PER_I2C2_CLKCTRL		(CM_PER + 0x044)
+#define CM_PER_I2C1_CLKCTRL		(CM_PER + 0x048)
+#define CM_PER_SPI0_CLKCTRL		(CM_PER + 0x04C)
+#define CM_PER_SPI1_CLKCTRL		(CM_PER + 0x050)
+#define CM_PER_UART1_CLKCTRL		(CM_PER + 0x06C)
+#define CM_PER_UART2_CLKCTRL		(CM_PER + 0x070)
+#define CM_PER_UART3_CLKCTRL		(CM_PER + 0x074)
+#define CM_PER_UART4_CLKCTRL		(CM_PER + 0x078)
+#define CM_PER_TIMER7_CLKCTRL		(CM_PER + 0x07C)
+#define CM_PER_TIMER2_CLKCTRL		(CM_PER + 0x080)
+#define CM_PER_TIMER3_CLKCTRL		(CM_PER + 0x084)
+#define CM_PER_TIMER4_CLKCTRL		(CM_PER + 0x088)
+#define CM_PER_GPIO1_CLKCTRL		(CM_PER + 0x0AC)
+#define CM_PER_GPIO2_CLKCTRL		(CM_PER + 0x0B0)
+#define CM_PER_GPIO3_CLKCTRL		(CM_PER + 0x0B4)
+#define CM_PER_TPCC_CLKCTRL		(CM_PER + 0x0BC)
+#define CM_PER_EPWMSS1_CLKCTRL		(CM_PER + 0x0CC)
+#define CM_PER_EPWMSS0_CLKCTRL		(CM_PER + 0x0D4)
+#define CM_PER_EPWMSS2_CLKCTRL		(CM_PER + 0x0D8)
+#define CM_PER_L3_INSTR_CLKCTRL		(CM_PER + 0x0DC)
+#define CM_PER_L3_CLKCTRL		(CM_PER + 0x0E0)
+#define	CM_PER_PRUSS_CLKCTRL		(CM_PER + 0x0E8)
+#define CM_PER_TIMER5_CLKCTRL		(CM_PER + 0x0EC)
+#define CM_PER_TIMER6_CLKCTRL		(CM_PER + 0x0F0)
+#define CM_PER_MMC1_CLKCTRL		(CM_PER + 0x0F4)
+#define CM_PER_MMC2_CLKCTRL		(CM_PER + 0x0F8)
+#define CM_PER_TPTC1_CLKCTRL		(CM_PER + 0x0FC)
+#define CM_PER_TPTC2_CLKCTRL		(CM_PER + 0x100)
+#define	CM_PER_SPINLOCK0_CLKCTRL	(CM_PER + 0x10C)
+#define	CM_PER_MAILBOX0_CLKCTRL		(CM_PER + 0x110)
+#define CM_PER_OCPWP_L3_CLKSTCTRL	(CM_PER + 0x12C)
+#define CM_PER_OCPWP_CLKCTRL		(CM_PER + 0x130)
+#define CM_PER_CPSW_CLKSTCTRL		(CM_PER + 0x144)
+#define	CM_PER_PRUSS_CLKSTCTRL		(CM_PER + 0x140)
+
+#define CM_WKUP				0x400
+#define CM_WKUP_CLKSTCTRL		(CM_WKUP + 0x000)
+#define CM_WKUP_CONTROL_CLKCTRL		(CM_WKUP + 0x004)
+#define CM_WKUP_GPIO0_CLKCTRL		(CM_WKUP + 0x008)
+#define CM_WKUP_CM_L3_AON_CLKSTCTRL	(CM_WKUP + 0x01C)
+#define CM_WKUP_CM_CLKSEL_DPLL_MPU	(CM_WKUP + 0x02C)
+#define CM_WKUP_CM_IDLEST_DPLL_DISP	(CM_WKUP + 0x048)
+#define CM_WKUP_CM_CLKSEL_DPLL_DISP	(CM_WKUP + 0x054)
+#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER	(CM_WKUP + 0x07C)
+#define CM_WKUP_CM_CLKMODE_DPLL_DISP	(CM_WKUP + 0x098)
+#define CM_WKUP_I2C0_CLKCTRL		(CM_WKUP + 0x0B8)
+#define CM_WKUP_ADC_TSC_CLKCTRL		(CM_WKUP + 0x0BC)
+
+#define CM_DPLL				0x500
+#define CLKSEL_TIMER7_CLK		(CM_DPLL + 0x004)
+#define CLKSEL_TIMER2_CLK		(CM_DPLL + 0x008)
+#define CLKSEL_TIMER3_CLK		(CM_DPLL + 0x00C)
+#define CLKSEL_TIMER4_CLK		(CM_DPLL + 0x010)
+#define CLKSEL_TIMER5_CLK		(CM_DPLL + 0x018)
+#define CLKSEL_TIMER6_CLK		(CM_DPLL + 0x01C)
+#define	CLKSEL_PRUSS_OCP_CLK		(CM_DPLL + 0x030)
+
+#define	CM_RTC				0x800
+#define	CM_RTC_RTC_CLKCTRL		(CM_RTC + 0x000)
+#define	CM_RTC_CLKSTCTRL		(CM_RTC + 0x004)
+
+#define	PRM_PER				0xC00
+#define	PRM_PER_RSTCTRL			(PRM_PER + 0x00)
+
+#define PRM_DEVICE_OFFSET		0xF00
+#define PRM_RSTCTRL			(PRM_DEVICE_OFFSET + 0x00)
+
+struct am335x_prcm_softc {
+	struct resource *	res[2];
+	bus_space_tag_t		bst;
+	bus_space_handle_t	bsh;
+};
+
+static struct resource_spec am335x_prcm_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct am335x_prcm_softc *am335x_prcm_sc = NULL;
+
+static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev);
+static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
+static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq);
+static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq);
+static void am335x_prcm_reset(void);
+static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
+
+#define AM335X_NOOP_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_noop_activate, \
+		.clk_deactivate = am335x_clk_noop_deactivate, \
+		.clk_set_source = am335x_clk_noop_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = NULL, \
+		.clk_set_source_freq = NULL \
+	}
+
+#define AM335X_GENERIC_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_generic_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = NULL, \
+		.clk_set_source_freq = NULL \
+	}
+
+#define AM335X_GPIO_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_gpio_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = NULL, \
+		.clk_set_source_freq = NULL \
+	}
+
+#define AM335X_MMCHS_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_generic_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq, \
+		.clk_set_source_freq = NULL \
+	}
+
+struct ti_clock_dev ti_am335x_clk_devmap[] = {
+	/* System clocks */
+	{	.id                  = SYS_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = am335x_clk_get_sysclk_freq,
+		.clk_set_source_freq = NULL,
+	},
+	/* MPU (ARM) core clocks */
+	{	.id                  = MPU_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
+		.clk_set_source_freq = NULL,
+	},
+	/* CPSW Ethernet Switch core clocks */
+	{	.id                  = CPSW_CLK,
+		.clk_activate        = am335x_clk_cpsw_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = NULL,
+		.clk_set_source_freq = NULL,
+	},
+
+	/* Mentor USB HS controller core clocks */
+	{	.id                  = MUSB0_CLK,
+		.clk_activate        = am335x_clk_musb0_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = NULL,
+		.clk_set_source_freq = NULL,
+	},
+
+	/* LCD controller clocks */
+	{	.id                  = LCDC_CLK,
+		.clk_activate        = am335x_clk_lcdc_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = am335x_clk_get_arm_disp_freq,
+		.clk_set_source_freq = am335x_clk_set_arm_disp_freq,
+	},
+
+        /* UART */
+	AM335X_NOOP_CLOCK_DEV(UART1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(UART2_CLK),
+	AM335X_GENERIC_CLOCK_DEV(UART3_CLK),
+	AM335X_GENERIC_CLOCK_DEV(UART4_CLK),
+	AM335X_GENERIC_CLOCK_DEV(UART5_CLK),
+	AM335X_GENERIC_CLOCK_DEV(UART6_CLK),
+
+	/* DMTimer */
+	AM335X_GENERIC_CLOCK_DEV(TIMER2_CLK),
+	AM335X_GENERIC_CLOCK_DEV(TIMER3_CLK),
+	AM335X_GENERIC_CLOCK_DEV(TIMER4_CLK),
+	AM335X_GENERIC_CLOCK_DEV(TIMER5_CLK),
+	AM335X_GENERIC_CLOCK_DEV(TIMER6_CLK),
+	AM335X_GENERIC_CLOCK_DEV(TIMER7_CLK),
+
+	/* GPIO, we use hwmods as reference, not units in spec */
+	AM335X_GPIO_CLOCK_DEV(GPIO1_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO2_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO3_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO4_CLK),
+
+	/* I2C we use hwmods as reference, not units in spec */
+	AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
+	AM335X_GENERIC_CLOCK_DEV(I2C3_CLK),
+
+	/* McSPI we use hwmods as reference, not units in spec */
+	AM335X_GENERIC_CLOCK_DEV(SPI0_CLK),
+	AM335X_GENERIC_CLOCK_DEV(SPI1_CLK),
+
+	/* TSC_ADC */
+	AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK),
+
+	/* EDMA */
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK),
+
+	/* MMCHS */
+	AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
+	AM335X_MMCHS_CLOCK_DEV(MMC2_CLK),
+	AM335X_MMCHS_CLOCK_DEV(MMC3_CLK),
+
+	/* PWMSS */
+	AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK),
+	AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK),
+
+	/* System Mailbox clock */
+	AM335X_GENERIC_CLOCK_DEV(MAILBOX0_CLK),
+
+	/* SPINLOCK */
+	AM335X_GENERIC_CLOCK_DEV(SPINLOCK0_CLK),
+
+	/* PRU-ICSS */
+	{	.id		     = PRUSS_CLK,
+		.clk_activate	     = am335x_clk_pruss_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = NULL,
+		.clk_set_source_freq = NULL,
+	},
+
+	/* RTC */
+	AM335X_GENERIC_CLOCK_DEV(RTC_CLK),
+
+	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
+};
+
+struct am335x_clk_details {
+	clk_ident_t	id;
+	uint32_t	clkctrl_reg;
+	uint32_t	clksel_reg;
+};
+
+#define _CLK_DETAIL(i, c, s) \
+	{	.id = (i), \
+		.clkctrl_reg = (c), \
+		.clksel_reg = (s), \
+	}
+
+static struct am335x_clk_details g_am335x_clk_details[] = {
+
+        /* UART. UART0 clock not controllable. */
+	_CLK_DETAIL(UART1_CLK, 0, 0),
+	_CLK_DETAIL(UART2_CLK, CM_PER_UART1_CLKCTRL, 0),
+	_CLK_DETAIL(UART3_CLK, CM_PER_UART2_CLKCTRL, 0),
+	_CLK_DETAIL(UART4_CLK, CM_PER_UART3_CLKCTRL, 0),
+	_CLK_DETAIL(UART5_CLK, CM_PER_UART4_CLKCTRL, 0),
+	_CLK_DETAIL(UART6_CLK, CM_PER_UART5_CLKCTRL, 0),
+
+	/* DMTimer modules */
+	_CLK_DETAIL(TIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
+	_CLK_DETAIL(TIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
+	_CLK_DETAIL(TIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
+	_CLK_DETAIL(TIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
+	_CLK_DETAIL(TIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
+	_CLK_DETAIL(TIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
+
+	/* GPIO modules, hwmods start with gpio1 */
+	_CLK_DETAIL(GPIO1_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO1_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO2_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO4_CLK, CM_PER_GPIO3_CLKCTRL, 0),
+
+	/* I2C modules, hwmods start with i2c1 */
+	_CLK_DETAIL(I2C1_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
+	_CLK_DETAIL(I2C2_CLK, CM_PER_I2C1_CLKCTRL, 0),
+	_CLK_DETAIL(I2C3_CLK, CM_PER_I2C2_CLKCTRL, 0),
+
+	/* McSPI modules, hwmods start with spi0 */
+	_CLK_DETAIL(SPI0_CLK, CM_PER_SPI0_CLKCTRL, 0),
+	_CLK_DETAIL(SPI1_CLK, CM_PER_SPI1_CLKCTRL, 0),
+
+	/* TSC_ADC module */
+	_CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0),
+
+	/* EDMA modules */
+	_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0),
+
+	/* MMCHS modules, hwmods start with mmc1*/
+	_CLK_DETAIL(MMC1_CLK, CM_PER_MMC0_CLKCTRL, 0),
+	_CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0),
+	_CLK_DETAIL(MMC3_CLK, CM_PER_MMC1_CLKCTRL, 0),
+
+	/* PWMSS modules */
+	_CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0),
+	_CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0),
+	_CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0),
+
+	_CLK_DETAIL(MAILBOX0_CLK, CM_PER_MAILBOX0_CLKCTRL, 0),
+	_CLK_DETAIL(SPINLOCK0_CLK, CM_PER_SPINLOCK0_CLKCTRL, 0),
+
+	/* RTC module */
+	_CLK_DETAIL(RTC_CLK, CM_RTC_RTC_CLKCTRL, 0),
+
+	{ INVALID_CLK_IDENT, 0},
+};
+
+/* Read/Write macros */
+#define prcm_read_4(reg)		\
+	bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg)
+#define prcm_write_4(reg, val)		\
+	bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val)
+
+void am335x_prcm_setup_dmtimer(int);
+
+static int
+am335x_prcm_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_is_compatible(dev, "ti,am3-prcm")) {
+		device_set_desc(dev, "AM335x Power and Clock Management");
+		return(BUS_PROBE_DEFAULT);
+	}
+
+	return (ENXIO);
+}
+
+static int
+am335x_prcm_attach(device_t dev)
+{
+	struct am335x_prcm_softc *sc = device_get_softc(dev);
+	unsigned int sysclk, fclk;
+
+	if (am335x_prcm_sc)
+		return (ENXIO);
+
+	if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->bst = rman_get_bustag(sc->res[0]);
+	sc->bsh = rman_get_bushandle(sc->res[0]);
+
+	am335x_prcm_sc = sc;
+	ti_cpu_reset = am335x_prcm_reset;
+
+	if (am335x_clk_get_sysclk_freq(NULL, &sysclk) != 0)
+		sysclk = 0;
+	if (am335x_clk_get_arm_fclk_freq(NULL, &fclk) != 0)
+		fclk = 0;
+	if (sysclk && fclk)
+		device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
+		    sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
+	else
+		device_printf(dev, "can't read frequencies yet (SCM device not ready?)\n");
+
+	return (0);
+}
+
+static device_method_t am335x_prcm_methods[] = {
+	DEVMETHOD(device_probe,		am335x_prcm_probe),
+	DEVMETHOD(device_attach,	am335x_prcm_attach),
+	{ 0, 0 }
+};
+
+static driver_t am335x_prcm_driver = {
+	"am335x_prcm",
+	am335x_prcm_methods,
+	sizeof(struct am335x_prcm_softc),
+};
+
+static devclass_t am335x_prcm_devclass;
+
+DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver,
+	am335x_prcm_devclass, 0, 0);
+MODULE_VERSION(am335x_prcm, 1);
+MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1);
+
+static struct am335x_clk_details*
+am335x_clk_details(clk_ident_t id)
+{
+	struct am335x_clk_details *walker;
+
+	for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
+		if (id == walker->id)
+			return (walker);
+	}
+
+	return NULL;
+}
+
+static int
+am335x_clk_noop_activate(struct ti_clock_dev *clkdev)
+{
+
+	return (0);
+}
+
+static int
+am335x_clk_generic_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
+	prcm_write_4(clk_details->clkctrl_reg, 2);
+	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_gpio_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
+	/* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */
+	prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18));
+	while ((prcm_read_4(clk_details->clkctrl_reg) &
+	    (3 | (1 << 18) )) != (2 | (1 << 18)))
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev)
+{
+
+	return(0);
+}
+
+static int
+am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */
+	prcm_write_4(clk_details->clkctrl_reg, 0);
+	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc)
+{
+
+	return (0);
+}
+
+static int
+am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+	uint32_t reg;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	switch (clksrc) {
+		case EXT_CLK:
+			reg = 0; /* SEL2: TCLKIN clock */
+			break;
+		case SYSCLK_CLK:
+			reg = 1; /* SEL1: CLK_M_OSC clock */
+			break;
+		case F32KHZ_CLK:
+			reg = 2; /* SEL3: CLK_32KHZ clock */
+			break;
+		default:
+			return (ENXIO);
+	}
+
+	prcm_write_4(clk_details->clksel_reg, reg);
+	while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq)
+{
+	*freq = 96000000;
+	return (0);
+}
+
+static int
+am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+	uint32_t ctrl_status;
+
+	/* Read the input clock freq from the control module. */
+	if (ti_scm_reg_read_4(SCM_CTRL_STATUS, &ctrl_status))
+		return (ENXIO);
+
+	switch ((ctrl_status>>22) & 0x3) {
+	case 0x0:
+		/* 19.2Mhz */
+		*freq = 19200000;
+		break;
+	case 0x1:
+		/* 24Mhz */
+		*freq = 24000000;
+		break;
+	case 0x2:
+		/* 25Mhz */
+		*freq = 25000000;
+		break;
+	case 0x3:
+		/* 26Mhz */
+		*freq = 26000000;
+		break;
+	}
+
+	return (0);
+}
+
+#define DPLL_BYP_CLKSEL(reg)	((reg>>23) & 1)
+#define DPLL_DIV(reg)		((reg & 0x7f)+1)
+#define DPLL_MULT(reg)		((reg>>8) & 0x7FF)
+#define	DPLL_MAX_MUL		0x800
+#define	DPLL_MAX_DIV		0x80
+
+static int
+am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+	uint32_t reg;
+	uint32_t sysclk;
+
+	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU);
+
+	/*Check if we are running in bypass */
+	if (DPLL_BYP_CLKSEL(reg))
+		return ENXIO;
+
+	am335x_clk_get_sysclk_freq(NULL, &sysclk);
+	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
+	return(0);
+}
+
+static int
+am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+	uint32_t reg;
+	uint32_t sysclk;
+
+	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP);
+
+	/*Check if we are running in bypass */
+	if (DPLL_BYP_CLKSEL(reg))
+		return ENXIO;
+
+	am335x_clk_get_sysclk_freq(NULL, &sysclk);
+	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
+	return(0);
+}
+
+static int
+am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq)
+{
+	uint32_t sysclk;
+	uint32_t mul, div;
+	uint32_t i, j;
+	unsigned int delta, min_delta;
+
+	am335x_clk_get_sysclk_freq(NULL, &sysclk);
+
+	/* Bypass mode */
+	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4);
+
+	/* Make sure it's in bypass mode */
+	while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
+	    & (1 << 8)))
+		DELAY(10);
+
+	/* Dumb and non-optimal implementation */
+	min_delta = freq;
+	for (i = 1; i < DPLL_MAX_MUL; i++) {
+		for (j = 1; j < DPLL_MAX_DIV; j++) {
+			delta = abs(freq - i*(sysclk/j));
+			if (delta < min_delta) {
+				mul = i;
+				div = j;
+				min_delta = delta;
+			}
+			if (min_delta == 0)
+				break;
+		}
+	}
+
+	prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (mul << 8) | (div - 1));
+
+	/* Locked mode */
+	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7);
+
+	int timeout = 10000;
+	while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
+	    & (1 << 0))) && timeout--)
+		DELAY(10);
+
+	return(0);
+}
+
+static void
+am335x_prcm_reset(void)
+{
+	prcm_write_4(PRM_RSTCTRL, (1<<1));
+}
+
+static int
+am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	/* set MODULENAME to ENABLE */
+	prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2);
+
+	/* wait for IDLEST to become Func(0) */
+	while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16));
+
+	/*set CLKTRCTRL to SW_WKUP(2) */
+	prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2);
+
+	/* wait for 125 MHz OCP clock to become active */
+	while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0);
+	return(0);
+}
+
+static int
+am335x_clk_musb0_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	/* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */
+	/* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/
+        prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300);
+
+	/*set MODULEMODE to ENABLE(2) */
+	prcm_write_4(CM_PER_USB0_CLKCTRL, 2);
+
+	/* wait for MODULEMODE to become ENABLE(2) */
+	while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2)
+		DELAY(10);
+
+	/* wait for IDLEST to become Func(0) */
+	while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16))
+		DELAY(10);
+
+	return(0);
+}
+
+static int
+am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	/*
+	 * For now set frequency to 2*VGA_PIXEL_CLOCK 
+	 */
+	am335x_clk_set_arm_disp_freq(clkdev, 25175000*2);
+
+	/*set MODULEMODE to ENABLE(2) */
+	prcm_write_4(CM_PER_LCDC_CLKCTRL, 2);
+
+	/* wait for MODULEMODE to become ENABLE(2) */
+	while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2)
+		DELAY(10);
+
+	/* wait for IDLEST to become Func(0) */
+	while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16))
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_pruss_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	/* Set MODULEMODE to ENABLE(2) */
+	prcm_write_4(CM_PER_PRUSS_CLKCTRL, 2);
+
+	/* Wait for MODULEMODE to become ENABLE(2) */
+	while ((prcm_read_4(CM_PER_PRUSS_CLKCTRL) & 0x3) != 2)
+		DELAY(10);
+
+	/* Set CLKTRCTRL to SW_WKUP(2) */
+	prcm_write_4(CM_PER_PRUSS_CLKSTCTRL, 2);
+
+	/* Wait for the 200 MHz OCP clock to become active */
+	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<4)) == 0)
+		DELAY(10);
+
+	/* Wait for the 200 MHz IEP clock to become active */
+	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<5)) == 0)
+		DELAY(10);
+
+	/* Wait for the 192 MHz UART clock to become active */
+	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<6)) == 0)
+		DELAY(10);
+
+	/* Select L3F as OCP clock */
+	prcm_write_4(CLKSEL_PRUSS_OCP_CLK, 0);
+	while ((prcm_read_4(CLKSEL_PRUSS_OCP_CLK) & 0x3) != 0)
+		DELAY(10);
+
+	/* Clear the RESET bit */
+	prcm_write_4(PRM_PER_RSTCTRL, prcm_read_4(PRM_PER_RSTCTRL) & ~2);
+
+	return (0);
+}
diff --git a/freebsd/sys/arm/ti/am335x/am335x_scm.h b/freebsd/sys/arm/ti/am335x/am335x_scm.h
new file mode 100644
index 0000000..6116be0
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/am335x_scm.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * All rights reserved.
+ *
+ * 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 __AM335X_SCM_H__
+#define __AM335X_SCM_H__
+
+/* AM335x-specific registers for control module (scm) */
+#define	SCM_CTRL_STATUS	0x40
+#define	SCM_BGAP_CTRL	0x448
+#define	SCM_BGAP_TEMP_MASK	0xff
+#define	SCM_BGAP_TEMP_SHIFT	8
+#define	SCM_BGAP_BGOFF		(1 << 6)
+#define	SCM_BGAP_SOC		(1 << 4)
+#define	SCM_BGAP_CLRZ		(1 << 3)
+#define	SCM_BGAP_CONTCONV	(1 << 2)
+#define	SCM_BGAP_EOCZ		(1 << 1)
+#define	SCM_USB_CTRL0	0x620
+#define	SCM_USB_STS0	0x624
+#define	SCM_USB_CTRL1	0x628
+#define	SCM_USB_STS1	0x62C
+#define	SCM_MAC_ID0_LO	0x630
+#define	SCM_MAC_ID0_HI	0x634
+#define	SCM_PWMSS_CTRL	0x664
+
+#endif /* __AM335X_SCM_H__ */
diff --git a/freebsd/sys/arm/ti/am335x/am335x_usbss.c b/freebsd/sys/arm/ti/am335x/am335x_usbss.c
new file mode 100644
index 0000000..8369171
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/am335x_usbss.c
@@ -0,0 +1,226 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ *
+ * 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 <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <rtems/bsd/sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/openfirm.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_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/musb_otg.h>
+#include <dev/usb/usb_debug.h>
+
+#include <sys/rman.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/am335x/am335x_scm.h>
+
+#define	AM335X_USB_PORTS	2
+
+#define	USBSS_REVREG		0x00
+#define	USBSS_SYSCONFIG		0x10
+#define		USBSS_SYSCONFIG_SRESET		1
+
+#define USBCTRL_REV		0x00
+#define USBCTRL_CTRL		0x14
+#define USBCTRL_STAT		0x18
+#define USBCTRL_IRQ_STAT0	0x30
+#define		IRQ_STAT0_RXSHIFT	16
+#define		IRQ_STAT0_TXSHIFT	0
+#define USBCTRL_IRQ_STAT1	0x34
+#define 	IRQ_STAT1_DRVVBUS	(1 << 8)
+#define USBCTRL_INTEN_SET0	0x38
+#define USBCTRL_INTEN_SET1	0x3C
+#define 	USBCTRL_INTEN_USB_ALL	0x1ff
+#define 	USBCTRL_INTEN_USB_SOF	(1 << 3)
+#define USBCTRL_INTEN_CLR0	0x40
+#define USBCTRL_INTEN_CLR1	0x44
+#define USBCTRL_UTMI		0xE0
+#define		USBCTRL_UTMI_FSDATAEXT		(1 << 1)
+#define USBCTRL_MODE		0xE8
+#define 	USBCTRL_MODE_IDDIG		(1 << 8)
+#define 	USBCTRL_MODE_IDDIGMUX		(1 << 7)
+
+#define	USBSS_WRITE4(sc, reg, val)		\
+    bus_write_4((sc)->sc_mem_res, (reg), (val))
+#define	USBSS_READ4(sc, reg)			\
+    bus_read_4((sc)->sc_mem_res, (reg))
+
+static device_probe_t usbss_probe;
+static device_attach_t usbss_attach;
+static device_detach_t usbss_detach;
+
+struct usbss_softc {
+	struct simplebus_softc	simplebus_sc;
+	struct resource		*sc_mem_res;
+	int			sc_mem_rid;
+};
+
+static int
+usbss_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "ti,am33xx-usb"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI AM33xx integrated USB OTG controller");
+	
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+usbss_attach(device_t dev)
+{
+	struct usbss_softc *sc = device_get_softc(dev);
+	int i;
+	uint32_t rev;
+	phandle_t node;
+
+	/* Request the memory resources */
+	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &sc->sc_mem_rid, RF_ACTIVE);
+	if (sc->sc_mem_res == NULL) {
+		device_printf(dev,
+		    "Error: could not allocate mem resources\n");
+		return (ENXIO);
+	}
+
+	/* Enable device clocks. */
+	ti_prcm_clk_enable(MUSB0_CLK);
+
+	/*
+	 * Reset USBSS, USB0 and USB1.
+	 * The registers of USB subsystem must not be accessed while the
+	 * reset pulse is active (200ns).
+	 */
+	USBSS_WRITE4(sc, USBSS_SYSCONFIG, USBSS_SYSCONFIG_SRESET);
+	DELAY(100);
+	i = 10;
+	while (USBSS_READ4(sc, USBSS_SYSCONFIG) & USBSS_SYSCONFIG_SRESET) {
+		DELAY(100);
+		if (i-- == 0) {
+			device_printf(dev, "reset timeout.\n");
+			return (ENXIO);
+		}
+	}
+
+	/* Read the module revision. */
+	rev = USBSS_READ4(sc, USBSS_REVREG);
+	device_printf(dev, "TI AM335X USBSS v%d.%d.%d\n",
+	    (rev >> 8) & 7, (rev >> 6) & 3, rev & 63);
+
+	node = ofw_bus_get_node(dev);
+
+	if (node == -1) {
+		usbss_detach(dev);
+		return (ENXIO);
+	}
+
+	simplebus_init(dev, node);
+
+	/*
+	 * Allow devices to identify.
+	 */
+	bus_generic_probe(dev);
+
+	/*
+	 * Now walk the OFW tree and attach top-level devices.
+	 */
+	for (node = OF_child(node); node > 0; node = OF_peer(node))
+		simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+
+	return (bus_generic_attach(dev));
+}
+
+static int
+usbss_detach(device_t dev)
+{
+	struct usbss_softc *sc = device_get_softc(dev);
+
+	/* Free resources if any */
+	if (sc->sc_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid,
+		    sc->sc_mem_res);
+
+	/* during module unload there are lots of children leftover */
+	device_delete_children(dev);
+
+	return (0);
+}
+
+static device_method_t usbss_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, usbss_probe),
+	DEVMETHOD(device_attach, usbss_attach),
+	DEVMETHOD(device_detach, usbss_detach),
+	DEVMETHOD(device_suspend, bus_generic_suspend),
+	DEVMETHOD(device_resume, bus_generic_resume),
+	DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(usbss, usbss_driver, usbss_methods,
+    sizeof(struct usbss_softc), simplebus_driver);
+static devclass_t usbss_devclass;
+DRIVER_MODULE(usbss, simplebus, usbss_driver, usbss_devclass, 0, 0);
+MODULE_DEPEND(usbss, usb, 1, 1, 1);
diff --git a/freebsd/sys/arm/ti/ti_cpuid.h b/freebsd/sys/arm/ti/ti_cpuid.h
new file mode 100644
index 0000000..715f080
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_cpuid.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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 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 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 _TI_CPUID_H_
+#define	_TI_CPUID_H_
+
+#define	OMAP_MAKEREV(d, a, b, c) \
+	(uint32_t)(((d) << 16) | (((a) & 0xf) << 8) | (((b) & 0xf) << 4) | ((c) & 0xf))
+
+#define	OMAP_REV_DEVICE(x)	(((x) >> 16) & 0xffff)
+#define	OMAP_REV_MAJOR(x)	(((x) >> 8) & 0xf)
+#define	OMAP_REV_MINOR(x)	(((x) >> 4) & 0xf)
+#define	OMAP_REV_MINOR_MINOR(x)	(((x) >> 0) & 0xf)
+
+#define	OMAP3350_DEV		0x3530
+#define	OMAP3350_REV_ES1_0	OMAP_MAKEREV(OMAP3350_DEV, 1, 0, 0)
+#define	OMAP3530_REV_ES2_0	OMAP_MAKEREV(OMAP3350_DEV, 2, 0, 0)
+#define	OMAP3530_REV_ES2_1	OMAP_MAKEREV(OMAP3350_DEV, 2, 1, 0)
+#define	OMAP3530_REV_ES3_0	OMAP_MAKEREV(OMAP3350_DEV, 3, 0, 0)
+#define	OMAP3530_REV_ES3_1	OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 0)
+#define	OMAP3530_REV_ES3_1_2	OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 2)
+
+#define	OMAP4430_DEV		0x4430
+#define	OMAP4430_REV_ES1_0	OMAP_MAKEREV(OMAP4430_DEV, 1, 0, 0)
+#define	OMAP4430_REV_ES2_0	OMAP_MAKEREV(OMAP4430_DEV, 2, 0, 0)
+#define	OMAP4430_REV_ES2_1	OMAP_MAKEREV(OMAP4430_DEV, 2, 1, 0)
+#define	OMAP4430_REV_ES2_2	OMAP_MAKEREV(OMAP4430_DEV, 2, 2, 0)
+#define	OMAP4430_REV_ES2_3	OMAP_MAKEREV(OMAP4430_DEV, 2, 3, 0)
+#define	OMAP4430_REV_UNKNOWN	OMAP_MAKEREV(OMAP4430_DEV, 9, 9, 9)
+
+#define	OMAP4460_DEV		0x4460
+#define	OMAP4460_REV_ES1_0	OMAP_MAKEREV(OMAP4460_DEV, 1, 0, 0)
+#define	OMAP4460_REV_ES1_1	OMAP_MAKEREV(OMAP4460_DEV, 1, 1, 0)
+#define	OMAP4460_REV_UNKNOWN	OMAP_MAKEREV(OMAP4460_DEV, 9, 9, 9)
+
+#define	OMAP4470_DEV		0x4470
+#define	OMAP4470_REV_ES1_0	OMAP_MAKEREV(OMAP4470_DEV, 1, 0, 0)
+#define	OMAP4470_REV_UNKNOWN	OMAP_MAKEREV(OMAP4470_DEV, 9, 9, 9)
+
+#define	OMAP_UNKNOWN_DEV	OMAP_MAKEREV(0x9999, 9, 9, 9)
+
+#define	AM335X_DEVREV(x)	((x) >> 28)
+
+#define	CHIP_OMAP_4	0
+#define	CHIP_AM335X	1
+
+extern int _ti_chip;
+
+static __inline int ti_chip(void)
+{
+	KASSERT(_ti_chip != -1, ("Can't determine TI Chip"));
+	return _ti_chip;
+}
+
+uint32_t ti_revision(void);
+
+#endif  /* _TI_CPUID_H_ */
diff --git a/freebsd/sys/arm/ti/ti_prcm.c b/freebsd/sys/arm/ti/ti_prcm.c
new file mode 100644
index 0000000..b4dd03f
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_prcm.c
@@ -0,0 +1,357 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/**
+ * Power, Reset and Clock Management Module
+ *
+ * This is a very simple driver wrapper around the PRCM set of registers in
+ * the OMAP3 chip. It allows you to turn on and off things like the functional
+ * and interface clocks to the various on-chip modules.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <rtems/bsd/sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+
+/**
+ *	ti_*_clk_devmap - Array of clock devices, should be defined one per SoC 
+ *
+ *	This array is typically defined in one of the targeted *_prcm_clk.c
+ *	files and is specific to the given SoC platform.  Each entry in the array
+ *	corresponds to an individual clock device.
+ */
+extern struct ti_clock_dev ti_omap4_clk_devmap[];
+extern struct ti_clock_dev ti_am335x_clk_devmap[];
+
+/**
+ *	ti_prcm_clk_dev - returns a pointer to the clock device with given id
+ *	@clk: the ID of the clock device to get
+ *
+ *	Simply iterates through the clk_devmap global array and returns a pointer
+ *	to the clock device if found. 
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	The pointer to the clock device on success, on failure NULL is returned.
+ */
+static struct ti_clock_dev *
+ti_prcm_clk_dev(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = NULL;
+	switch(ti_chip()) {
+#ifdef SOC_OMAP4
+	case CHIP_OMAP_4:
+		clk_dev = &(ti_omap4_clk_devmap[0]);
+		break;
+#endif
+#ifdef SOC_TI_AM335X
+	case CHIP_AM335X:
+		clk_dev = &(ti_am335x_clk_devmap[0]);
+		break;
+#endif
+	}
+	if (clk_dev == NULL)
+		panic("No clock devmap found");
+	while (clk_dev->id != INVALID_CLK_IDENT) {
+		if (clk_dev->id == clk) {
+			return (clk_dev);
+		}
+		clk_dev++;
+	}
+
+	/* Sanity check we managed to find the clock */
+	printf("ti_prcm: Failed to find clock device (%d)\n", clk);
+	return (NULL);
+}
+
+/**
+ *	ti_prcm_clk_valid - enables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_valid(clk_ident_t clk)
+{
+	int ret = 0;
+
+	if (ti_prcm_clk_dev(clk) == NULL)
+		ret = EINVAL;
+	
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_enable - enables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_enable(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_activate)
+		ret = clk_dev->clk_activate(clk_dev);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_disable - disables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_disable(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_deactivate)
+		ret = clk_dev->clk_deactivate(clk_dev);
+	else
+		ret = EINVAL;
+	
+	return (ret);
+}
+
+/**
+ *	ti_prcm_clk_set_source - sets the source 
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_set_source)
+		ret = clk_dev->clk_set_source(clk_dev, clksrc);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_get_source_freq - gets the source clock frequency
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	@freq: pointer to an integer that upon return will contain the src freq
+ *
+ *	This function returns the frequency of the source clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Get the source frequency of the clock */
+	if (clk_dev->clk_get_source_freq)
+		ret = clk_dev->clk_get_source_freq(clk_dev, freq);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
+
+/**
+ *	ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	@freq: requested freq
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Get the source frequency of the clock */
+	if (clk_dev->clk_set_source_freq)
+		ret = clk_dev->clk_set_source_freq(clk_dev, freq);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
diff --git a/freebsd/sys/arm/ti/ti_prcm.h b/freebsd/sys/arm/ti/ti_prcm.h
new file mode 100644
index 0000000..61b6960
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_prcm.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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$
+ */
+
+
+/*
+ * Texas Instruments - OMAP3xxx series processors
+ *
+ * Reference:
+ *  OMAP35x Applications Processor
+ *   Technical Reference Manual
+ *  (omap35xx_techref.pdf)
+ */
+#ifndef _TI_PRCM_H_
+#define _TI_PRCM_H_
+
+typedef enum {
+
+	INVALID_CLK_IDENT = 0,
+
+	/* System clocks, typically you can only call ti_prcm_clk_get_source_freq()
+	 * on these clocks as they are enabled by default.
+	 */
+	SYS_CLK = 1,
+
+	/* The MPU (ARM) core clock */
+	MPU_CLK = 20,
+
+	/* MMC modules */
+	MMC1_CLK = 100,
+	MMC2_CLK,
+	MMC3_CLK,
+	MMC4_CLK,
+	MMC5_CLK,
+	MMC6_CLK,
+
+	/* I2C modules */
+	I2C1_CLK = 200,
+	I2C2_CLK,
+	I2C3_CLK,
+	I2C4_CLK,
+	I2C5_CLK,
+
+	/* USB module(s) */
+	USBTLL_CLK = 300,
+	USBHSHOST_CLK,
+	USBFSHOST_CLK,
+	USBP1_PHY_CLK,
+	USBP2_PHY_CLK,
+	USBP1_UTMI_CLK,
+	USBP2_UTMI_CLK,
+	USBP1_HSIC_CLK,
+	USBP2_HSIC_CLK,
+
+	/* UART modules */
+	UART1_CLK = 400,
+	UART2_CLK,
+	UART3_CLK,
+	UART4_CLK,
+	UART5_CLK,
+	UART6_CLK,
+	UART7_CLK,
+	UART8_CLK,
+	UART9_CLK,
+
+	/* General purpose timer modules */
+	TIMER1_CLK = 500,
+	TIMER2_CLK,
+	TIMER3_CLK,
+	TIMER4_CLK,
+	TIMER5_CLK,
+	TIMER6_CLK,
+	TIMER7_CLK,
+	TIMER8_CLK,
+	TIMER9_CLK,
+	TIMER10_CLK,
+	TIMER11_CLK,
+	TIMER12_CLK,
+
+	/* McBSP module(s) */
+	MCBSP1_CLK = 600,
+	MCBSP2_CLK,
+	MCBSP3_CLK,
+	MCBSP4_CLK,
+	MCBSP5_CLK,
+
+	/* General purpose I/O modules */
+	GPIO1_CLK = 700,
+	GPIO2_CLK,
+	GPIO3_CLK,
+	GPIO4_CLK,
+	GPIO5_CLK,
+	GPIO6_CLK,
+	GPIO7_CLK,
+
+	/* sDMA module */
+	SDMA_CLK = 800,
+
+	/* CPSW modules */
+	CPSW_CLK = 1000,
+
+	/* Mentor USB modules */
+	MUSB0_CLK = 1100,
+
+	/* EDMA module */
+	EDMA_TPCC_CLK = 1200,
+	EDMA_TPTC0_CLK,
+	EDMA_TPTC1_CLK,
+	EDMA_TPTC2_CLK,
+
+	/* LCD controller module */
+	LCDC_CLK = 1300,
+
+	/* PWM modules */
+	PWMSS0_CLK = 1400,
+	PWMSS1_CLK,
+	PWMSS2_CLK,
+
+	/* Mailbox modules */
+	MAILBOX0_CLK = 1500,
+
+	/* Spinlock modules */
+	SPINLOCK0_CLK = 1600,
+
+	PRUSS_CLK = 1700,
+
+	TSC_ADC_CLK = 1800,
+
+	/* RTC module */
+	RTC_CLK = 1900,
+
+	/* McSPI */
+	SPI0_CLK = 2000,
+	SPI1_CLK,
+} clk_ident_t;
+
+/*
+ *
+ */
+typedef enum {
+	SYSCLK_CLK,   /* System clock */
+	EXT_CLK,
+
+	F32KHZ_CLK,   /* 32KHz clock */
+	F48MHZ_CLK,   /* 48MHz clock */
+	F64MHZ_CLK,   /* 64MHz clock */
+	F96MHZ_CLK,   /* 96MHz clock */
+
+} clk_src_t;
+
+struct ti_clock_dev {
+	/* The profile of the timer */
+	clk_ident_t  id;
+
+	/* A bunch of callbacks associated with the clock device */
+	int (*clk_activate)(struct ti_clock_dev *clkdev);
+	int (*clk_deactivate)(struct ti_clock_dev *clkdev);
+	int (*clk_set_source)(struct ti_clock_dev *clkdev,
+	    clk_src_t clksrc);
+	int (*clk_accessible)(struct ti_clock_dev *clkdev);
+	int (*clk_set_source_freq)(struct ti_clock_dev *clkdev,
+	    unsigned int freq);
+	int (*clk_get_source_freq)(struct ti_clock_dev *clkdev,
+	    unsigned int *freq);
+};
+
+int ti_prcm_clk_valid(clk_ident_t clk);
+int ti_prcm_clk_enable(clk_ident_t clk);
+int ti_prcm_clk_disable(clk_ident_t clk);
+int ti_prcm_clk_accessible(clk_ident_t clk);
+int ti_prcm_clk_disable_autoidle(clk_ident_t clk);
+int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc);
+int ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq);
+int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq);
+void ti_prcm_reset(void);
+
+#endif   /* _TI_PRCM_H_ */
diff --git a/freebsd/sys/arm/ti/ti_scm.c b/freebsd/sys/arm/ti/ti_scm.c
new file mode 100644
index 0000000..2e54262
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_scm.c
@@ -0,0 +1,176 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/**
+ *	SCM - System Control Module
+ *
+ *	Hopefully in the end this module will contain a bunch of utility functions
+ *	for configuring and querying the general system control registers, but for
+ *	now it only does pin(pad) multiplexing.
+ *
+ *	This is different from the GPIO module in that it is used to configure the
+ *	pins between modules not just GPIO input/output.
+ *
+ *	This file contains the generic top level driver, however it relies on chip
+ *	specific settings and therefore expects an array of ti_scm_padconf structs
+ *	call ti_padconf_devmap to be located somewhere in the kernel.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <rtems/bsd/sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/fdt/fdt_pinctrl.h>
+
+#include "ti_scm.h"
+
+static struct resource_spec ti_scm_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Control memory window */
+	{ -1, 0 }
+};
+
+static struct ti_scm_softc *ti_scm_sc;
+
+#define	ti_scm_read_4(sc, reg)		\
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define	ti_scm_write_4(sc, reg, val)		\
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+/*
+ * Device part of OMAP SCM driver
+ */
+static int
+ti_scm_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "syscon"))
+		return (ENXIO);
+
+	if (ti_scm_sc) {
+		return (EEXIST);
+	}
+
+	device_set_desc(dev, "TI Control Module");
+	return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ *	ti_scm_attach - attaches the timer to the simplebus
+ *	@dev: new device
+ *
+ *	Reserves memory and interrupt resources, stores the softc structure
+ *	globally and registers both the timecount and eventtimer objects.
+ *
+ *	RETURNS
+ *	Zero on success or ENXIO if an error occuried.
+ */
+static int
+ti_scm_attach(device_t dev)
+{
+	struct ti_scm_softc *sc = device_get_softc(dev);
+
+	sc->sc_dev = dev;
+
+	if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	/* Global timer interface */
+	sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
+	sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
+
+	ti_scm_sc = sc;
+
+	/* Attach platform extensions, if any. */
+	bus_generic_probe(dev);
+
+	return (bus_generic_attach(dev));
+}
+
+int
+ti_scm_reg_read_4(uint32_t reg, uint32_t *val)
+{
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	*val = ti_scm_read_4(ti_scm_sc, reg);
+	return (0);
+}
+
+int
+ti_scm_reg_write_4(uint32_t reg, uint32_t val)
+{
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	ti_scm_write_4(ti_scm_sc, reg, val);
+	return (0);
+}
+
+
+static device_method_t ti_scm_methods[] = {
+	DEVMETHOD(device_probe,		ti_scm_probe),
+	DEVMETHOD(device_attach,	ti_scm_attach),
+
+	{ 0, 0 }
+};
+
+static driver_t ti_scm_driver = {
+	"ti_scm",
+	ti_scm_methods,
+	sizeof(struct ti_scm_softc),
+};
+
+static devclass_t ti_scm_devclass;
+
+EARLY_DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0,
+    BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
diff --git a/freebsd/sys/arm/ti/ti_scm.h b/freebsd/sys/arm/ti/ti_scm.h
new file mode 100644
index 0000000..1342ddc
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_scm.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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$
+ */
+
+
+/**
+ *	Functions to configure the PIN multiplexing on the chip.
+ *
+ *	This is different from the GPIO module in that it is used to configure the
+ *	pins between modules not just GPIO input output.
+ *
+ */
+#ifndef _TI_SCM_H_
+#define _TI_SCM_H_
+
+struct ti_scm_softc {
+	device_t		sc_dev;
+	struct resource *	sc_res[4];
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+};
+
+int ti_scm_reg_read_4(uint32_t reg, uint32_t *val);
+int ti_scm_reg_write_4(uint32_t reg, uint32_t val);
+
+#endif /* _TI_SCM_H_ */
diff --git a/freebsd/sys/arm/ti/tivar.h b/freebsd/sys/arm/ti/tivar.h
new file mode 100644
index 0000000..248ad90
--- /dev/null
+++ b/freebsd/sys/arm/ti/tivar.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at gmail.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 _TIVAR_H_
+#define	_TIVAR_H_
+
+/* board-dependent reset function implementation */
+extern void (*ti_cpu_reset)(void);
+
+#endif /* _TIVAR_H_ */
diff --git a/freebsd/sys/dev/fdt/fdt_pinctrl.h b/freebsd/sys/dev/fdt/fdt_pinctrl.h
new file mode 100644
index 0000000..507d13f
--- /dev/null
+++ b/freebsd/sys/dev/fdt/fdt_pinctrl.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian at freebsd.org>
+ * All rights reserved.
+ *
+ * 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 ``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 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 DEV_FDT_PINCTRL_H
+#define DEV_FDT_PINCTRL_H
+
+#include <rtems/bsd/local/fdt_pinctrl_if.h>
+
+/*
+ * Configure pins by name or index.  This looks up the pinctrl-N property in
+ * client's fdt data by index or name, and passes each handle in it to the
+ * pinctrl driver for configuration.
+ */
+int fdt_pinctrl_configure(device_t client, u_int index);
+int fdt_pinctrl_configure_by_name(device_t client, const char * name);
+
+/*
+ * Register a pinctrl driver so that it can be used by other devices which call
+ * fdt_pinctrl_configure().  The pinprop argument is the name of a property that
+ * identifies each descendent of the pinctrl node which is a pin configuration
+ * node whose xref phandle can be passed to FDT_PINCTRL_CONFIGURE().  If this is
+ * NULL, every descendant node is registered.
+ */
+int fdt_pinctrl_register(device_t pinctrl, const char *pinprop);
+
+/*
+ * Walk the device tree and configure pins for each enabled device whose
+ * pinctrl-0 property contains references to nodes which are children of the
+ * given pinctrl device.  This helper routine is for use by pinctrl drivers.
+ */
+int fdt_pinctrl_configure_tree(device_t pinctrl);
+
+#endif /* DEV_FDT_PINCTRL_H */
+
diff --git a/freebsd/sys/dev/usb/controller/musb_otg.c b/freebsd/sys/dev/usb/controller/musb_otg.c
new file mode 100644
index 0000000..0f1953b
--- /dev/null
+++ b/freebsd/sys/dev/usb/controller/musb_otg.c
@@ -0,0 +1,4257 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Thanks to Mentor Graphics for providing a reference driver for this USB chip
+ * at their homepage.
+ */
+
+/*
+ * This file contains the driver for the Mentor Graphics Inventra USB
+ * 2.0 High Speed Dual-Role controller.
+ *
+ */
+
+#ifdef USB_GLOBAL_INCLUDE_FILE
+#include USB_GLOBAL_INCLUDE_FILE
+#else
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <rtems/bsd/sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#define	USB_DEBUG_VAR musbotgdebug
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_transfer.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_hub.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#endif			/* USB_GLOBAL_INCLUDE_FILE */
+
+#include <dev/usb/controller/musb_otg.h>
+
+#define	MUSBOTG_INTR_ENDPT 1
+
+#define	MUSBOTG_BUS2SC(bus) \
+   ((struct musbotg_softc *)(((uint8_t *)(bus)) - \
+   USB_P2U(&(((struct musbotg_softc *)0)->sc_bus))))
+
+#define	MUSBOTG_PC2SC(pc) \
+   MUSBOTG_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
+
+#ifdef USB_DEBUG
+static int musbotgdebug = 0;
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg");
+SYSCTL_INT(_hw_usb_musbotg, OID_AUTO, debug, CTLFLAG_RWTUN,
+    &musbotgdebug, 0, "Debug level");
+#endif
+
+#define	MAX_NAK_TO	16
+
+/* prototypes */
+
+static const struct usb_bus_methods musbotg_bus_methods;
+static const struct usb_pipe_methods musbotg_device_bulk_methods;
+static const struct usb_pipe_methods musbotg_device_ctrl_methods;
+static const struct usb_pipe_methods musbotg_device_intr_methods;
+static const struct usb_pipe_methods musbotg_device_isoc_methods;
+
+/* Control transfers: Device mode */
+static musbotg_cmd_t musbotg_dev_ctrl_setup_rx;
+static musbotg_cmd_t musbotg_dev_ctrl_data_rx;
+static musbotg_cmd_t musbotg_dev_ctrl_data_tx;
+static musbotg_cmd_t musbotg_dev_ctrl_status;
+
+/* Control transfers: Host mode */
+static musbotg_cmd_t musbotg_host_ctrl_setup_tx;
+static musbotg_cmd_t musbotg_host_ctrl_data_rx;
+static musbotg_cmd_t musbotg_host_ctrl_data_tx;
+static musbotg_cmd_t musbotg_host_ctrl_status_rx;
+static musbotg_cmd_t musbotg_host_ctrl_status_tx;
+
+/* Bulk, Interrupt, Isochronous: Device mode */
+static musbotg_cmd_t musbotg_dev_data_rx;
+static musbotg_cmd_t musbotg_dev_data_tx;
+
+/* Bulk, Interrupt, Isochronous: Host mode */
+static musbotg_cmd_t musbotg_host_data_rx;
+static musbotg_cmd_t musbotg_host_data_tx;
+
+static void	musbotg_device_done(struct usb_xfer *, usb_error_t);
+static void	musbotg_do_poll(struct usb_bus *);
+static void	musbotg_standard_done(struct usb_xfer *);
+static void	musbotg_interrupt_poll(struct musbotg_softc *);
+static void	musbotg_root_intr(struct musbotg_softc *);
+static int	musbotg_channel_alloc(struct musbotg_softc *, struct musbotg_td *td, uint8_t);
+static void	musbotg_channel_free(struct musbotg_softc *, struct musbotg_td *td);
+static void	musbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on);
+
+/*
+ * Here is a configuration that the chip supports.
+ */
+static const struct usb_hw_ep_profile musbotg_ep_profile[1] = {
+
+	[0] = {
+		.max_in_frame_size = 64,/* fixed */
+		.max_out_frame_size = 64,	/* fixed */
+		.is_simplex = 1,
+		.support_control = 1,
+	}
+};
+
+static int
+musbotg_channel_alloc(struct musbotg_softc *sc, struct musbotg_td *td, uint8_t is_tx)
+{
+	int ch;
+	int ep;
+
+	ep = td->ep_no;
+
+	/* In device mode each EP got its own channel */
+	if (sc->sc_mode == MUSB2_DEVICE_MODE) {
+		musbotg_ep_int_set(sc, ep, 1);
+		return (ep);
+	}
+
+	/*
+	 * All control transactions go through EP0
+	 */
+	if (ep == 0) {
+		if (sc->sc_channel_mask & (1 << 0))
+			return (-1);
+		sc->sc_channel_mask |= (1 << 0);
+		musbotg_ep_int_set(sc, ep, 1);
+		return (0);
+	}
+
+	for (ch = sc->sc_ep_max; ch != 0; ch--) {
+		if (sc->sc_channel_mask & (1 << ch))
+			continue;
+
+		/* check FIFO size requirement */
+		if (is_tx) {
+			if (td->max_frame_size >
+			    sc->sc_hw_ep_profile[ch].max_in_frame_size)
+				continue;
+		} else {
+			if (td->max_frame_size >
+			    sc->sc_hw_ep_profile[ch].max_out_frame_size)
+				continue;
+		}
+		sc->sc_channel_mask |= (1 << ch);
+		musbotg_ep_int_set(sc, ch, 1);
+		return (ch);
+	}
+
+	DPRINTFN(-1, "No available channels. Mask: %04x\n",  sc->sc_channel_mask);
+
+	return (-1);
+}
+
+static void	
+musbotg_channel_free(struct musbotg_softc *sc, struct musbotg_td *td)
+{
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	if (sc->sc_mode == MUSB2_DEVICE_MODE)
+		return;
+
+	if (td == NULL)
+		return;
+	if (td->channel == -1)
+		return;
+
+	musbotg_ep_int_set(sc, td->channel, 0);
+	sc->sc_channel_mask &= ~(1 << td->channel);
+
+	td->channel = -1;
+}
+
+static void
+musbotg_get_hw_ep_profile(struct usb_device *udev,
+    const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
+{
+	struct musbotg_softc *sc;
+
+	sc = MUSBOTG_BUS2SC(udev->bus);
+
+	if (ep_addr == 0) {
+		/* control endpoint */
+		*ppf = musbotg_ep_profile;
+	} else if (ep_addr <= sc->sc_ep_max) {
+		/* other endpoints */
+		*ppf = sc->sc_hw_ep_profile + ep_addr;
+	} else {
+		*ppf = NULL;
+	}
+}
+
+static void
+musbotg_clocks_on(struct musbotg_softc *sc)
+{
+	if (sc->sc_flags.clocks_off &&
+	    sc->sc_flags.port_powered) {
+
+		DPRINTFN(4, "\n");
+
+		if (sc->sc_clocks_on) {
+			(sc->sc_clocks_on) (sc->sc_clocks_arg);
+		}
+		sc->sc_flags.clocks_off = 0;
+
+		/* XXX enable Transceiver */
+	}
+}
+
+static void
+musbotg_clocks_off(struct musbotg_softc *sc)
+{
+	if (!sc->sc_flags.clocks_off) {
+
+		DPRINTFN(4, "\n");
+
+		/* XXX disable Transceiver */
+
+		if (sc->sc_clocks_off) {
+			(sc->sc_clocks_off) (sc->sc_clocks_arg);
+		}
+		sc->sc_flags.clocks_off = 1;
+	}
+}
+
+static void
+musbotg_pull_common(struct musbotg_softc *sc, uint8_t on)
+{
+	uint8_t temp;
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	if (on)
+		temp |= MUSB2_MASK_SOFTC;
+	else
+		temp &= ~MUSB2_MASK_SOFTC;
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+}
+
+static void
+musbotg_pull_up(struct musbotg_softc *sc)
+{
+	/* pullup D+, if possible */
+
+	if (!sc->sc_flags.d_pulled_up &&
+	    sc->sc_flags.port_powered) {
+		sc->sc_flags.d_pulled_up = 1;
+		musbotg_pull_common(sc, 1);
+	}
+}
+
+static void
+musbotg_pull_down(struct musbotg_softc *sc)
+{
+	/* pulldown D+, if possible */
+
+	if (sc->sc_flags.d_pulled_up) {
+		sc->sc_flags.d_pulled_up = 0;
+		musbotg_pull_common(sc, 0);
+	}
+}
+
+static void
+musbotg_suspend_host(struct musbotg_softc *sc)
+{
+	uint8_t temp;
+
+	if (sc->sc_flags.status_suspend) {
+		return;
+	}
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	temp |= MUSB2_MASK_SUSPMODE;
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+	sc->sc_flags.status_suspend = 1;
+}
+
+static void
+musbotg_wakeup_host(struct musbotg_softc *sc)
+{
+	uint8_t temp;
+
+	if (!(sc->sc_flags.status_suspend)) {
+		return;
+	}
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	temp &= ~MUSB2_MASK_SUSPMODE;
+	temp |= MUSB2_MASK_RESUME;
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+
+	/* wait 20 milliseconds */
+	/* Wait for reset to complete. */
+	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50);
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	temp &= ~MUSB2_MASK_RESUME;
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+
+	sc->sc_flags.status_suspend = 0;
+}
+
+static void
+musbotg_wakeup_peer(struct musbotg_softc *sc)
+{
+	uint8_t temp;
+
+	if (!(sc->sc_flags.status_suspend)) {
+		return;
+	}
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	temp |= MUSB2_MASK_RESUME;
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+
+	/* wait 8 milliseconds */
+	/* Wait for reset to complete. */
+	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+	temp &= ~MUSB2_MASK_RESUME;
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
+}
+
+static void
+musbotg_set_address(struct musbotg_softc *sc, uint8_t addr)
+{
+	DPRINTFN(4, "addr=%d\n", addr);
+	addr &= 0x7F;
+	MUSB2_WRITE_1(sc, MUSB2_REG_FADDR, addr);
+}
+
+static uint8_t
+musbotg_dev_ctrl_setup_rx(struct musbotg_td *td)
+{
+	struct musbotg_softc *sc;
+	struct usb_device_request req;
+	uint16_t count;
+	uint8_t csr;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 0);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	/*
+	 * NOTE: If DATAEND is set we should not call the
+	 * callback, hence the status stage is not complete.
+	 */
+	if (csr & MUSB2_MASK_CSR0L_DATAEND) {
+		/* do not stall at this point */
+		td->did_stall = 1;
+		/* wait for interrupt */
+		DPRINTFN(1, "CSR0 DATAEND\n");
+		goto not_complete;
+	}
+
+	if (csr & MUSB2_MASK_CSR0L_SENTSTALL) {
+		/* clear SENTSTALL */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		/* get latest status */
+		csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+		/* update EP0 state */
+		sc->sc_ep0_busy = 0;
+	}
+	if (csr & MUSB2_MASK_CSR0L_SETUPEND) {
+		/* clear SETUPEND */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSR0L_SETUPEND_CLR);
+		/* get latest status */
+		csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+		/* update EP0 state */
+		sc->sc_ep0_busy = 0;
+	}
+	if (sc->sc_ep0_busy) {
+		DPRINTFN(1, "EP0 BUSY\n");
+		goto not_complete;
+	}
+	if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) {
+		goto not_complete;
+	}
+	/* get the packet byte count */
+	count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
+
+	/* verify data length */
+	if (count != td->remainder) {
+		DPRINTFN(1, "Invalid SETUP packet "
+		    "length, %d bytes\n", count);
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		      MUSB2_MASK_CSR0L_RXPKTRDY_CLR);
+		/* don't clear stall */
+		td->did_stall = 1;
+		goto not_complete;
+	}
+	if (count != sizeof(req)) {
+		DPRINTFN(1, "Unsupported SETUP packet "
+		    "length, %d bytes\n", count);
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		      MUSB2_MASK_CSR0L_RXPKTRDY_CLR);
+		/* don't clear stall */
+		td->did_stall = 1;
+		goto not_complete;
+	}
+	/* clear did stall flag */
+	td->did_stall = 0;
+
+	/* receive data */
+	bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+	    MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req));
+
+	/* copy data into real buffer */
+	usbd_copy_in(td->pc, 0, &req, sizeof(req));
+
+	td->offset = sizeof(req);
+	td->remainder = 0;
+
+	/* set pending command */
+	sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR;
+
+	/* we need set stall or dataend after this */
+	sc->sc_ep0_busy = 1;
+
+	/* sneak peek the set address */
+	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
+	    (req.bRequest == UR_SET_ADDRESS)) {
+		sc->sc_dv_addr = req.wValue[0] & 0x7F;
+	} else {
+		sc->sc_dv_addr = 0xFF;
+	}
+
+	musbotg_channel_free(sc, td);
+	return (0);			/* complete */
+
+not_complete:
+	/* abort any ongoing transfer */
+	if (!td->did_stall) {
+		DPRINTFN(4, "stalling\n");
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSR0L_SENDSTALL);
+		td->did_stall = 1;
+	}
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_host_ctrl_setup_tx(struct musbotg_td *td)
+{
+	struct musbotg_softc *sc;
+	struct usb_device_request req;
+	uint8_t csr, csrh;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 1);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	/* Not ready yet yet */
+	if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
+		return (1);
+
+	/* Failed */
+	if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
+	    MUSB2_MASK_CSR0L_ERROR))
+	{
+		/* Clear status bit */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
+		td->error = 1;
+	}
+
+	if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
+		DPRINTFN(1, "NAK timeout\n");
+
+		if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
+			csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
+			csrh |= MUSB2_MASK_CSR0H_FFLUSH;
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
+				csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
+				csrh |= MUSB2_MASK_CSR0H_FFLUSH;
+				MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
+				csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			}
+		}
+
+		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		td->error = 1;
+	}
+
+	if (td->error) {
+		musbotg_channel_free(sc, td);
+		return (0);
+	}
+
+	/* Fifo is not empty and there is no NAK timeout */
+	if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
+		return (1);
+
+	/* check if we are complete */
+	if (td->remainder == 0) {
+		/* we are complete */
+		musbotg_channel_free(sc, td);
+		return (0);
+	}
+
+	/* copy data into real buffer */
+	usbd_copy_out(td->pc, 0, &req, sizeof(req));
+
+	/* send data */
+	bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+	    MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req));
+
+	/* update offset and remainder */
+	td->offset += sizeof(req);
+	td->remainder -= sizeof(req);
+
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
+
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_TXPKTRDY | 
+	    MUSB2_MASK_CSR0L_SETUPPKT);
+
+	/* Just to be consistent, not used above */
+	td->transaction_started = 1;
+
+	return (1);			/* in progress */
+}
+
+/* Control endpoint only data handling functions (RX/TX/SYNC) */
+
+static uint8_t
+musbotg_dev_ctrl_data_rx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr;
+	uint8_t got_short;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* check if a command is pending */
+	if (sc->sc_ep0_cmd) {
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd);
+		sc->sc_ep0_cmd = 0;
+	}
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	got_short = 0;
+
+	if (csr & (MUSB2_MASK_CSR0L_SETUPEND |
+	    MUSB2_MASK_CSR0L_SENTSTALL)) {
+		if (td->remainder == 0) {
+			/*
+			 * We are actually complete and have
+			 * received the next SETUP
+			 */
+			DPRINTFN(4, "faking complete\n");
+			return (0);	/* complete */
+		}
+		/*
+	         * USB Host Aborted the transfer.
+	         */
+		td->error = 1;
+		return (0);		/* complete */
+	}
+	if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) {
+		return (1);		/* not complete */
+	}
+	/* get the packet byte count */
+	count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
+
+	/* verify the packet byte count */
+	if (count != td->max_frame_size) {
+		if (count < td->max_frame_size) {
+			/* we have a short packet */
+			td->short_pkt = 1;
+			got_short = 1;
+		} else {
+			/* invalid USB packet */
+			td->error = 1;
+			return (0);	/* we are complete */
+		}
+	}
+	/* verify the packet byte count */
+	if (count > td->remainder) {
+		/* invalid USB packet */
+		td->error = 1;
+		return (0);		/* we are complete */
+	}
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    (void *)(&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usbd_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* receive data 4 bytes at a time */
+			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(0), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* receive data */
+		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* check if we are complete */
+	if ((td->remainder == 0) || got_short) {
+		if (td->short_pkt) {
+			/* we are complete */
+			sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR;
+			return (0);
+		}
+		/* else need to receive a zero length packet */
+	}
+	/* write command - need more data */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_RXPKTRDY_CLR);
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_dev_ctrl_data_tx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* check if a command is pending */
+	if (sc->sc_ep0_cmd) {
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd);
+		sc->sc_ep0_cmd = 0;
+	}
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (csr & (MUSB2_MASK_CSR0L_SETUPEND |
+	    MUSB2_MASK_CSR0L_SENTSTALL)) {
+		/*
+	         * The current transfer was aborted
+	         * by the USB Host
+	         */
+		td->error = 1;
+		return (0);		/* complete */
+	}
+	if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) {
+		return (1);		/* not complete */
+	}
+	count = td->max_frame_size;
+	if (td->remainder < count) {
+		/* we have a short packet */
+		td->short_pkt = 1;
+		count = td->remainder;
+	}
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usbd_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* transmit data 4 bytes at a time */
+			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(0), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* transmit data */
+		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* check remainder */
+	if (td->remainder == 0) {
+		if (td->short_pkt) {
+			sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_TXPKTRDY;
+			return (0);	/* complete */
+		}
+		/* else we need to transmit a short packet */
+	}
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_TXPKTRDY);
+
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_host_ctrl_data_rx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr;
+	uint8_t got_short;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 0);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	got_short = 0;
+	if (!td->transaction_started) {
+		td->transaction_started = 1;
+
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO);
+
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0),
+		    td->dev_addr);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type);
+
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSR0L_REQPKT);
+
+		return (1);
+	}
+
+	if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
+		csr &= ~MUSB2_MASK_CSR0L_REQPKT;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		td->error = 1;
+	}
+
+	/* Failed */
+	if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
+	    MUSB2_MASK_CSR0L_ERROR))
+	{
+		/* Clear status bit */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
+		td->error = 1;
+	}
+
+	if (td->error) {
+		musbotg_channel_free(sc, td);
+		return (0);	/* we are complete */
+	}
+
+	if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY))
+		return (1); /* not yet */
+
+	/* get the packet byte count */
+	count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
+
+	/* verify the packet byte count */
+	if (count != td->max_frame_size) {
+		if (count < td->max_frame_size) {
+			/* we have a short packet */
+			td->short_pkt = 1;
+			got_short = 1;
+		} else {
+			/* invalid USB packet */
+			td->error = 1;
+			musbotg_channel_free(sc, td);
+			return (0);	/* we are complete */
+		}
+	}
+	/* verify the packet byte count */
+	if (count > td->remainder) {
+		/* invalid USB packet */
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0);		/* we are complete */
+	}
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    (void *)(&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usbd_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* receive data 4 bytes at a time */
+			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(0), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* receive data */
+		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	csr &= ~MUSB2_MASK_CSR0L_RXPKTRDY;
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+	/* check if we are complete */
+	if ((td->remainder == 0) || got_short) {
+		if (td->short_pkt) {
+			/* we are complete */
+
+			musbotg_channel_free(sc, td);
+			return (0);
+		}
+		/* else need to receive a zero length packet */
+	}
+
+	td->transaction_started = 1;
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_REQPKT);
+
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_host_ctrl_data_tx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr, csrh;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 1);
+
+	/* No free EPs */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
+	    MUSB2_MASK_CSR0L_ERROR)) {
+		/* clear status bits */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		td->error = 1;
+	}
+
+	if (csr & MUSB2_MASK_CSR0L_NAKTIMO ) {
+
+		if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
+			csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
+			csrh |= MUSB2_MASK_CSR0H_FFLUSH;
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
+				csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
+				csrh |= MUSB2_MASK_CSR0H_FFLUSH;
+				MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
+				csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			}
+		}
+
+		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		td->error = 1;
+	}
+
+
+	if (td->error) {
+		musbotg_channel_free(sc, td);
+		return (0);	/* complete */
+	}
+
+	/*
+	 * Wait while FIFO is empty. 
+	 * Do not flush it because it will cause transactions
+	 * with size more then packet size. It might upset
+	 * some devices
+	 */
+	if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY)
+		return (1);
+
+	/* Packet still being processed */
+	if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
+		return (1);
+
+	if (td->transaction_started) {
+		/* check remainder */
+		if (td->remainder == 0) {
+			if (td->short_pkt) {
+				musbotg_channel_free(sc, td);
+				return (0);	/* complete */
+			}
+			/* else we need to transmit a short packet */
+		}
+
+		/* We're not complete - more transactions required */
+		td->transaction_started = 0;
+	}
+
+	/* check for short packet */
+	count = td->max_frame_size;
+	if (td->remainder < count) {
+		/* we have a short packet */
+		td->short_pkt = 1;
+		count = td->remainder;
+	}
+
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usbd_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(0),
+				    sc->sc_bounce_buf, temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* transmit data 4 bytes at a time */
+			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(0), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* transmit data */
+		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(0), buf_res.buffer,
+		    buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* Function address */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
+
+	/* TX NAK timeout */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
+
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_TXPKTRDY);
+
+	td->transaction_started = 1;
+
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_dev_ctrl_status(struct musbotg_td *td)
+{
+	struct musbotg_softc *sc;
+	uint8_t csr;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	if (sc->sc_ep0_busy) {
+		sc->sc_ep0_busy = 0;
+		sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd);
+		sc->sc_ep0_cmd = 0;
+	}
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (csr & MUSB2_MASK_CSR0L_DATAEND) {
+		/* wait for interrupt */
+		return (1);		/* not complete */
+	}
+	if (sc->sc_dv_addr != 0xFF) {
+		/* write function address */
+		musbotg_set_address(sc, sc->sc_dv_addr);
+	}
+
+	musbotg_channel_free(sc, td);
+	return (0);			/* complete */
+}
+
+static uint8_t
+musbotg_host_ctrl_status_rx(struct musbotg_td *td)
+{
+	struct musbotg_softc *sc;
+	uint8_t csr, csrh;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 0);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	if (!td->transaction_started) {
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0),
+		    td->dev_addr);
+
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type);
+
+		/* RX NAK timeout */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO);
+
+		td->transaction_started = 1;
+
+		/* Disable PING */
+		csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH);
+		csrh |= MUSB2_MASK_CSR0H_PING_DIS;
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh);
+
+		/* write command */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSR0L_STATUSPKT | 
+		    MUSB2_MASK_CSR0L_REQPKT);
+
+		return (1); /* Just started */
+
+	}
+
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "IN STATUS csr=0x%02x\n", csr);
+
+	if (csr & MUSB2_MASK_CSR0L_RXPKTRDY) {
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSR0L_RXPKTRDY_CLR);
+		musbotg_channel_free(sc, td);
+		return (0); /* complete */
+	}
+
+	if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
+		csr &= ~ (MUSB2_MASK_CSR0L_STATUSPKT |
+		    MUSB2_MASK_CSR0L_REQPKT);
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+		td->error = 1;
+	}
+
+	/* Failed */
+	if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
+	    MUSB2_MASK_CSR0L_ERROR))
+	{
+		/* Clear status bit */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
+		td->error = 1;
+	}
+
+	if (td->error) {
+		musbotg_channel_free(sc, td);
+		return (0);
+	}
+
+	return (1);			/* Not ready yet */
+}
+
+static uint8_t
+musbotg_host_ctrl_status_tx(struct musbotg_td *td)
+{
+	struct musbotg_softc *sc;
+	uint8_t csr;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 1);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d/%d [%d@%d.%d/%02x]\n", td->channel, td->transaction_started, 
+			td->dev_addr,td->haddr,td->hport, td->transfer_type);
+
+	/* select endpoint 0 */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	/* Not yet */
+	if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
+		return (1);
+
+	/* Failed */
+	if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
+	    MUSB2_MASK_CSR0L_ERROR))
+	{
+		/* Clear status bit */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0); /* complete */
+	}
+
+	if (td->transaction_started) {
+		musbotg_channel_free(sc, td);
+		return (0); /* complete */
+	} 
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, MUSB2_MASK_CSR0H_PING_DIS);
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
+
+	/* TX NAK timeout */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
+
+	td->transaction_started = 1;
+
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSR0L_STATUSPKT | 
+	    MUSB2_MASK_CSR0L_TXPKTRDY);
+
+	return (1);			/* wait for interrupt */
+}
+
+static uint8_t
+musbotg_dev_data_rx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr;
+	uint8_t to;
+	uint8_t got_short;
+
+	to = 8;				/* don't loop forever! */
+	got_short = 0;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 0);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel);
+
+repeat:
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	/* clear overrun */
+	if (csr & MUSB2_MASK_CSRL_RXOVERRUN) {
+		/* make sure we don't clear "RXPKTRDY" */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+		    MUSB2_MASK_CSRL_RXPKTRDY);
+	}
+
+	/* check status */
+	if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY))
+		return (1); /* not complete */
+
+	/* get the packet byte count */
+	count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
+
+	DPRINTFN(4, "count=0x%04x\n", count);
+
+	/*
+	 * Check for short or invalid packet:
+	 */
+	if (count != td->max_frame_size) {
+		if (count < td->max_frame_size) {
+			/* we have a short packet */
+			td->short_pkt = 1;
+			got_short = 1;
+		} else {
+			/* invalid USB packet */
+			td->error = 1;
+			musbotg_channel_free(sc, td);
+			return (0);	/* we are complete */
+		}
+	}
+	/* verify the packet byte count */
+	if (count > td->remainder) {
+		/* invalid USB packet */
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0);		/* we are complete */
+	}
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usbd_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* receive data 4 bytes at a time */
+			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* receive data */
+		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+		    buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* clear status bits */
+	MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0);
+
+	/* check if we are complete */
+	if ((td->remainder == 0) || got_short) {
+		if (td->short_pkt) {
+			/* we are complete */
+			musbotg_channel_free(sc, td);
+			return (0);
+		}
+		/* else need to receive a zero length packet */
+	}
+	if (--to) {
+		goto repeat;
+	}
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_dev_data_tx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr;
+	uint8_t to;
+
+	to = 8;				/* don't loop forever! */
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 1);
+
+	/* EP0 is busy, wait */
+	if (td->channel == -1)
+		return (1);
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel);
+
+repeat:
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (csr & (MUSB2_MASK_CSRL_TXINCOMP |
+	    MUSB2_MASK_CSRL_TXUNDERRUN)) {
+		/* clear status bits */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+	}
+	if (csr & MUSB2_MASK_CSRL_TXPKTRDY) {
+		return (1);		/* not complete */
+	}
+	/* check for short packet */
+	count = td->max_frame_size;
+	if (td->remainder < count) {
+		/* we have a short packet */
+		td->short_pkt = 1;
+		count = td->remainder;
+	}
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usbd_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel),
+				    sc->sc_bounce_buf, temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->channel),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* transmit data 4 bytes at a time */
+			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* transmit data */
+		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+		    buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* Max packet size */
+	MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet);
+
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSRL_TXPKTRDY);
+
+	/* check remainder */
+	if (td->remainder == 0) {
+		if (td->short_pkt) {
+			musbotg_channel_free(sc, td);
+			return (0);	/* complete */
+		}
+		/* else we need to transmit a short packet */
+	}
+	if (--to) {
+		goto repeat;
+	}
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_host_data_rx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr, csrh;
+	uint8_t to;
+	uint8_t got_short;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 0);
+
+	/* No free EPs */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	to = 8;				/* don't loop forever! */
+	got_short = 0;
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel);
+
+repeat:
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (!td->transaction_started) {
+		/* Function address */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(td->channel),
+		    td->dev_addr);
+
+		/* SPLIT transaction */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(td->channel), 
+		    td->haddr);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(td->channel), 
+		    td->hport);
+
+		/* RX NAK timeout */
+		if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC)
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, 0);
+		else
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO);
+
+		/* Protocol, speed, device endpoint */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type);
+
+		/* Max packet size */
+		MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, td->reg_max_packet);
+
+		/* Data Toggle */
+		csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH);
+		DPRINTFN(4, "csrh=0x%02x\n", csrh);
+
+		csrh |= MUSB2_MASK_CSRH_RXDT_WREN;
+		if (td->toggle)
+			csrh |= MUSB2_MASK_CSRH_RXDT_VAL;
+		else
+			csrh &= ~MUSB2_MASK_CSRH_RXDT_VAL;
+
+		/* Set data toggle */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh);
+
+		/* write command */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+		    MUSB2_MASK_CSRL_RXREQPKT);
+
+		td->transaction_started = 1;
+		return (1);
+	}
+
+	/* clear NAK timeout */
+	if (csr & MUSB2_MASK_CSRL_RXNAKTO) {
+		DPRINTFN(4, "NAK Timeout\n");
+		if (csr & MUSB2_MASK_CSRL_RXREQPKT) {
+			csr &= ~MUSB2_MASK_CSRL_RXREQPKT;
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr);
+
+			csr &= ~MUSB2_MASK_CSRL_RXNAKTO;
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr);
+		}
+
+		td->error = 1;
+	}
+
+	if (csr & MUSB2_MASK_CSRL_RXERROR) {
+		DPRINTFN(4, "RXERROR\n");
+		td->error = 1;
+	}
+
+	if (csr & MUSB2_MASK_CSRL_RXSTALL) {
+		DPRINTFN(4, "RXSTALL\n");
+		td->error = 1;
+	}
+
+	if (td->error) {
+		musbotg_channel_free(sc, td);
+		return (0);	/* we are complete */
+	}
+
+	if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) {
+		/* No data available yet */
+		return (1);
+	}
+
+	td->toggle ^= 1;
+	/* get the packet byte count */
+	count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
+	DPRINTFN(4, "count=0x%04x\n", count);
+
+	/*
+	 * Check for short or invalid packet:
+	 */
+	if (count != td->max_frame_size) {
+		if (count < td->max_frame_size) {
+			/* we have a short packet */
+			td->short_pkt = 1;
+			got_short = 1;
+		} else {
+			/* invalid USB packet */
+			td->error = 1;
+			musbotg_channel_free(sc, td);
+			return (0);	/* we are complete */
+		}
+	}
+
+	/* verify the packet byte count */
+	if (count > td->remainder) {
+		/* invalid USB packet */
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0);		/* we are complete */
+	}
+
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usbd_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* receive data 4 bytes at a time */
+			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* receive data */
+		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+		    buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* clear status bits */
+	MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0);
+
+	/* check if we are complete */
+	if ((td->remainder == 0) || got_short) {
+		if (td->short_pkt) {
+			/* we are complete */
+			musbotg_channel_free(sc, td);
+			return (0);
+		}
+		/* else need to receive a zero length packet */
+	}
+
+	/* Reset transaction state and restart */
+	td->transaction_started = 0;
+
+	if (--to)
+		goto repeat;
+
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_host_data_tx(struct musbotg_td *td)
+{
+	struct usb_page_search buf_res;
+	struct musbotg_softc *sc;
+	uint16_t count;
+	uint8_t csr, csrh;
+
+	/* get pointer to softc */
+	sc = MUSBOTG_PC2SC(td->pc);
+
+	if (td->channel == -1)
+		td->channel = musbotg_channel_alloc(sc, td, 1);
+
+	/* No free EPs */
+	if (td->channel == -1)
+		return (1);
+
+	DPRINTFN(1, "ep_no=%d\n", td->channel);
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel);
+
+	/* read out FIFO status */
+	csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+	DPRINTFN(4, "csr=0x%02x\n", csr);
+
+	if (csr & (MUSB2_MASK_CSRL_TXSTALLED |
+	    MUSB2_MASK_CSRL_TXERROR)) {
+		/* clear status bits */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0);	/* complete */
+	}
+
+	if (csr & MUSB2_MASK_CSRL_TXNAKTO) {
+		/* 
+		 * Flush TX FIFO before clearing NAK TO
+		 */
+		if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
+			csr |= MUSB2_MASK_CSRL_TXFFLUSH;
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
+				csr |= MUSB2_MASK_CSRL_TXFFLUSH;
+				MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+				csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			}
+		}
+
+		csr &= ~MUSB2_MASK_CSRL_TXNAKTO;
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
+
+		td->error = 1;
+		musbotg_channel_free(sc, td);
+		return (0);	/* complete */
+	}
+
+	/*
+	 * Wait while FIFO is empty. 
+	 * Do not flush it because it will cause transactions
+	 * with size more then packet size. It might upset
+	 * some devices
+	 */
+	if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY)
+		return (1);
+
+	/* Packet still being processed */
+	if (csr & MUSB2_MASK_CSRL_TXPKTRDY)
+		return (1);
+
+	if (td->transaction_started) {
+		/* check remainder */
+		if (td->remainder == 0) {
+			if (td->short_pkt) {
+				musbotg_channel_free(sc, td);
+				return (0);	/* complete */
+			}
+			/* else we need to transmit a short packet */
+		}
+
+		/* We're not complete - more transactions required */
+		td->transaction_started = 0;
+	}
+
+	/* check for short packet */
+	count = td->max_frame_size;
+	if (td->remainder < count) {
+		/* we have a short packet */
+		td->short_pkt = 1;
+		count = td->remainder;
+	}
+
+	while (count > 0) {
+		uint32_t temp;
+
+		usbd_get_page(td->pc, td->offset, &buf_res);
+
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usbd_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel),
+				    sc->sc_bounce_buf, temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->channel),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
+		/* check if we can optimise */
+		if (buf_res.length >= 4) {
+
+			/* transmit data 4 bytes at a time */
+			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+			    buf_res.length / 4);
+
+			temp = buf_res.length & ~3;
+
+			/* update counters */
+			count -= temp;
+			td->offset += temp;
+			td->remainder -= temp;
+			continue;
+		}
+		/* transmit data */
+		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+		    MUSB2_REG_EPFIFO(td->channel), buf_res.buffer,
+		    buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
+
+	/* Function address */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(td->channel),
+	    td->dev_addr);
+
+	/* SPLIT transaction */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(td->channel), 
+	    td->haddr);
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(td->channel), 
+	    td->hport);
+
+	/* TX NAK timeout */
+	if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC)
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, 0);
+	else
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
+
+	/* Protocol, speed, device endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
+
+	/* Max packet size */
+	MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet);
+
+	if (!td->transaction_started) {
+		csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
+		DPRINTFN(4, "csrh=0x%02x\n", csrh);
+
+		csrh |= MUSB2_MASK_CSRH_TXDT_WREN;
+		if (td->toggle)
+			csrh |= MUSB2_MASK_CSRH_TXDT_VAL;
+		else
+			csrh &= ~MUSB2_MASK_CSRH_TXDT_VAL;
+
+		/* Set data toggle */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
+	}
+
+	/* write command */
+	MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+	    MUSB2_MASK_CSRL_TXPKTRDY);
+
+	/* Update Data Toggle */
+	td->toggle ^= 1;
+	td->transaction_started = 1;
+
+	return (1);			/* not complete */
+}
+
+static uint8_t
+musbotg_xfer_do_fifo(struct usb_xfer *xfer)
+{
+	struct musbotg_softc *sc;
+	struct musbotg_td *td;
+
+	DPRINTFN(8, "\n");
+	sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
+
+	td = xfer->td_transfer_cache;
+	while (1) {
+
+		if ((td->func) (td)) {
+			/* operation in progress */
+			break;
+		}
+
+		if (((void *)td) == xfer->td_transfer_last) {
+			goto done;
+		}
+		if (td->error) {
+			goto done;
+		} else if (td->remainder > 0) {
+			/*
+			 * We had a short transfer. If there is no alternate
+			 * next, stop processing !
+			 */
+			if (!td->alt_next) {
+				goto done;
+			}
+		}
+		/*
+		 * Fetch the next transfer descriptor and transfer
+		 * some flags to the next transfer descriptor
+		 */
+		td = td->obj_next;
+		xfer->td_transfer_cache = td;
+	}
+
+	return (1);			/* not complete */
+done:
+	/* compute all actual lengths */
+	musbotg_standard_done(xfer);
+
+	return (0);			/* complete */
+}
+
+static void
+musbotg_interrupt_poll(struct musbotg_softc *sc)
+{
+	struct usb_xfer *xfer;
+
+repeat:
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+		if (!musbotg_xfer_do_fifo(xfer)) {
+			/* queue has been modified */
+			goto repeat;
+		}
+	}
+}
+
+void
+musbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on)
+{
+	DPRINTFN(4, "vbus = %u\n", is_on);
+
+	USB_BUS_LOCK(&sc->sc_bus);
+	if (is_on) {
+		if (!sc->sc_flags.status_vbus) {
+			sc->sc_flags.status_vbus = 1;
+
+			/* complete root HUB interrupt endpoint */
+			musbotg_root_intr(sc);
+		}
+	} else {
+		if (sc->sc_flags.status_vbus) {
+			sc->sc_flags.status_vbus = 0;
+			sc->sc_flags.status_bus_reset = 0;
+			sc->sc_flags.status_suspend = 0;
+			sc->sc_flags.change_suspend = 0;
+			sc->sc_flags.change_connect = 1;
+
+			/* complete root HUB interrupt endpoint */
+			musbotg_root_intr(sc);
+		}
+	}
+
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
+void
+musbotg_connect_interrupt(struct musbotg_softc *sc)
+{
+	USB_BUS_LOCK(&sc->sc_bus);
+	sc->sc_flags.change_connect = 1;
+
+	/* complete root HUB interrupt endpoint */
+	musbotg_root_intr(sc);
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
+void
+musbotg_interrupt(struct musbotg_softc *sc,
+    uint16_t rxstat, uint16_t txstat, uint8_t stat)
+{
+	uint16_t rx_status;
+	uint16_t tx_status;
+	uint8_t usb_status;
+	uint8_t temp;
+	uint8_t to = 2;
+
+	USB_BUS_LOCK(&sc->sc_bus);
+
+repeat:
+
+	/* read all interrupt registers */
+	usb_status = MUSB2_READ_1(sc, MUSB2_REG_INTUSB);
+
+	/* read all FIFO interrupts */
+	rx_status = MUSB2_READ_2(sc, MUSB2_REG_INTRX);
+	tx_status = MUSB2_READ_2(sc, MUSB2_REG_INTTX);
+	rx_status |= rxstat;
+	tx_status |= txstat;
+	usb_status |= stat;
+
+	/* Clear platform flags after first time */
+	rxstat = 0;
+	txstat = 0;
+	stat = 0;
+
+	/* check for any bus state change interrupts */
+
+	if (usb_status & (MUSB2_MASK_IRESET |
+	    MUSB2_MASK_IRESUME | MUSB2_MASK_ISUSP | 
+	    MUSB2_MASK_ICONN | MUSB2_MASK_IDISC |
+	    MUSB2_MASK_IVBUSERR)) {
+
+		DPRINTFN(4, "real bus interrupt 0x%08x\n", usb_status);
+
+		if (usb_status & MUSB2_MASK_IRESET) {
+
+			/* set correct state */
+			sc->sc_flags.status_bus_reset = 1;
+			sc->sc_flags.status_suspend = 0;
+			sc->sc_flags.change_suspend = 0;
+			sc->sc_flags.change_connect = 1;
+
+			/* determine line speed */
+			temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+			if (temp & MUSB2_MASK_HSMODE)
+				sc->sc_flags.status_high_speed = 1;
+			else
+				sc->sc_flags.status_high_speed = 0;
+
+			/*
+			 * After reset all interrupts are on and we need to
+			 * turn them off!
+			 */
+			temp = MUSB2_MASK_IRESET;
+			/* disable resume interrupt */
+			temp &= ~MUSB2_MASK_IRESUME;
+			/* enable suspend interrupt */
+			temp |= MUSB2_MASK_ISUSP;
+			MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp);
+			/* disable TX and RX interrupts */
+			MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0);
+			MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0);
+		}
+		/*
+	         * If RXRSM and RXSUSP is set at the same time we interpret
+	         * that like RESUME. Resume is set when there is at least 3
+	         * milliseconds of inactivity on the USB BUS.
+	         */
+		if (usb_status & MUSB2_MASK_IRESUME) {
+			if (sc->sc_flags.status_suspend) {
+				sc->sc_flags.status_suspend = 0;
+				sc->sc_flags.change_suspend = 1;
+
+				temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE);
+				/* disable resume interrupt */
+				temp &= ~MUSB2_MASK_IRESUME;
+				/* enable suspend interrupt */
+				temp |= MUSB2_MASK_ISUSP;
+				MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp);
+			}
+		} else if (usb_status & MUSB2_MASK_ISUSP) {
+			if (!sc->sc_flags.status_suspend) {
+				sc->sc_flags.status_suspend = 1;
+				sc->sc_flags.change_suspend = 1;
+
+				temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE);
+				/* disable suspend interrupt */
+				temp &= ~MUSB2_MASK_ISUSP;
+				/* enable resume interrupt */
+				temp |= MUSB2_MASK_IRESUME;
+				MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp);
+			}
+		}
+		if (usb_status & 
+		    (MUSB2_MASK_ICONN | MUSB2_MASK_IDISC))
+			sc->sc_flags.change_connect = 1;
+
+		/* 
+		 * Host Mode: There is no IRESET so assume bus is 
+		 * always in reset state once device is connected.
+		 */
+		if (sc->sc_mode == MUSB2_HOST_MODE) {
+		    /* check for VBUS error in USB host mode */
+		    if (usb_status & MUSB2_MASK_IVBUSERR) {
+			temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL);
+			temp |= MUSB2_MASK_SESS;
+			MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp);
+		    }
+		    if (usb_status & MUSB2_MASK_ICONN)
+			sc->sc_flags.status_bus_reset = 1;
+		    if (usb_status & MUSB2_MASK_IDISC)
+			sc->sc_flags.status_bus_reset = 0;
+		}
+
+		/* complete root HUB interrupt endpoint */
+		musbotg_root_intr(sc);
+	}
+	/* check for any endpoint interrupts */
+
+	if (rx_status || tx_status) {
+		DPRINTFN(4, "real endpoint interrupt "
+		    "rx=0x%04x, tx=0x%04x\n", rx_status, tx_status);
+	}
+	/* poll one time regardless of FIFO status */
+
+	musbotg_interrupt_poll(sc);
+
+	if (--to)
+		goto repeat;
+
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
+static void
+musbotg_setup_standard_chain_sub(struct musbotg_std_temp *temp)
+{
+	struct musbotg_td *td;
+
+	/* get current Transfer Descriptor */
+	td = temp->td_next;
+	temp->td = td;
+
+	/* prepare for next TD */
+	temp->td_next = td->obj_next;
+
+	/* fill out the Transfer Descriptor */
+	td->func = temp->func;
+	td->pc = temp->pc;
+	td->offset = temp->offset;
+	td->remainder = temp->len;
+	td->error = 0;
+	td->transaction_started = 0;
+	td->did_stall = temp->did_stall;
+	td->short_pkt = temp->short_pkt;
+	td->alt_next = temp->setup_alt_next;
+	td->channel = temp->channel;
+	td->dev_addr = temp->dev_addr;
+	td->haddr = temp->haddr;
+	td->hport = temp->hport;
+	td->transfer_type = temp->transfer_type;
+}
+
+static void
+musbotg_setup_standard_chain(struct usb_xfer *xfer)
+{
+	struct musbotg_std_temp temp;
+	struct musbotg_softc *sc;
+	struct musbotg_td *td;
+	uint32_t x;
+	uint8_t ep_no;
+	uint8_t xfer_type;
+	enum usb_dev_speed speed;
+	int tx;
+	int dev_addr;
+
+	DPRINTFN(8, "addr=%d endpt=%d sumlen=%d speed=%d\n",
+	    xfer->address, UE_GET_ADDR(xfer->endpointno),
+	    xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
+
+	sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
+	ep_no = (xfer->endpointno & UE_ADDR);
+
+	temp.max_frame_size = xfer->max_frame_size;
+
+	td = xfer->td_start[0];
+	xfer->td_transfer_first = td;
+	xfer->td_transfer_cache = td;
+
+	/* setup temp */
+	dev_addr = xfer->address;
+
+	xfer_type = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE;
+
+	temp.pc = NULL;
+	temp.td = NULL;
+	temp.td_next = xfer->td_start[0];
+	temp.offset = 0;
+	temp.setup_alt_next = xfer->flags_int.short_frames_ok ||
+	    xfer->flags_int.isochronous_xfr;
+	temp.did_stall = !xfer->flags_int.control_stall;
+	temp.channel = -1;
+	temp.dev_addr = dev_addr;
+	temp.haddr = xfer->xroot->udev->hs_hub_addr;
+	temp.hport = xfer->xroot->udev->hs_port_no;
+
+	if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
+		speed =  usbd_get_speed(xfer->xroot->udev);
+
+		switch (speed) {
+			case USB_SPEED_LOW:
+				temp.transfer_type = MUSB2_MASK_TI_SPEED_LO;
+				break;
+			case USB_SPEED_FULL:
+				temp.transfer_type = MUSB2_MASK_TI_SPEED_FS;
+				break;
+			case USB_SPEED_HIGH:
+				temp.transfer_type = MUSB2_MASK_TI_SPEED_HS;
+				break;
+			default:
+				temp.transfer_type = 0;
+				DPRINTFN(-1, "Invalid USB speed: %d\n", speed);
+				break;
+		}
+
+		switch (xfer_type) {
+			case UE_CONTROL:
+				temp.transfer_type |= MUSB2_MASK_TI_PROTO_CTRL;
+				break;
+			case UE_ISOCHRONOUS:
+				temp.transfer_type |= MUSB2_MASK_TI_PROTO_ISOC;
+				break;
+			case UE_BULK:
+				temp.transfer_type |= MUSB2_MASK_TI_PROTO_BULK;
+				break;
+			case UE_INTERRUPT:
+				temp.transfer_type |= MUSB2_MASK_TI_PROTO_INTR;
+				break;
+			default:
+				DPRINTFN(-1, "Invalid USB transfer type: %d\n",
+						xfer_type);
+				break;
+		}
+
+		temp.transfer_type |= ep_no;
+		td->toggle = xfer->endpoint->toggle_next;
+	}
+
+	/* check if we should prepend a setup message */
+
+	if (xfer->flags_int.control_xfr) {
+		if (xfer->flags_int.control_hdr) {
+
+			if (xfer->flags_int.usb_mode == USB_MODE_DEVICE)
+				temp.func = &musbotg_dev_ctrl_setup_rx;
+			else
+				temp.func = &musbotg_host_ctrl_setup_tx;
+
+			temp.len = xfer->frlengths[0];
+			temp.pc = xfer->frbuffers + 0;
+			temp.short_pkt = temp.len ? 1 : 0;
+
+			musbotg_setup_standard_chain_sub(&temp);
+		}
+		x = 1;
+	} else {
+		x = 0;
+	}
+
+	tx = 0;
+
+	if (x != xfer->nframes) {
+		if (xfer->endpointno & UE_DIR_IN)
+		    	tx = 1;
+
+		if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
+			tx = !tx;
+
+			if (tx) {
+				if (xfer->flags_int.control_xfr)
+					temp.func = &musbotg_host_ctrl_data_tx;
+				else
+					temp.func = &musbotg_host_data_tx;
+			} else {
+				if (xfer->flags_int.control_xfr)
+					temp.func = &musbotg_host_ctrl_data_rx;
+				else
+					temp.func = &musbotg_host_data_rx;
+			}
+
+		} else {
+			if (tx) {
+				if (xfer->flags_int.control_xfr)
+					temp.func = &musbotg_dev_ctrl_data_tx;
+				else
+					temp.func = &musbotg_dev_data_tx;
+			} else {
+				if (xfer->flags_int.control_xfr)
+					temp.func = &musbotg_dev_ctrl_data_rx;
+				else
+					temp.func = &musbotg_dev_data_rx;
+			}
+		}
+
+		/* setup "pc" pointer */
+		temp.pc = xfer->frbuffers + x;
+	}
+	while (x != xfer->nframes) {
+
+		/* DATA0 / DATA1 message */
+
+		temp.len = xfer->frlengths[x];
+
+		x++;
+
+		if (x == xfer->nframes) {
+			if (xfer->flags_int.control_xfr) {
+				if (xfer->flags_int.control_act) {
+					temp.setup_alt_next = 0;
+				}
+			} else {
+				temp.setup_alt_next = 0;
+			}
+		}
+		if (temp.len == 0) {
+
+			/* make sure that we send an USB packet */
+
+			temp.short_pkt = 0;
+
+		} else {
+
+			if (xfer->flags_int.isochronous_xfr) {
+				/* isochronous data transfer */
+				/* don't force short */
+				temp.short_pkt = 1;
+			} else {
+				/* regular data transfer */
+				temp.short_pkt = (xfer->flags.force_short_xfer ? 0 : 1);
+			}
+		}
+
+		musbotg_setup_standard_chain_sub(&temp);
+
+		if (xfer->flags_int.isochronous_xfr) {
+			temp.offset += temp.len;
+		} else {
+			/* get next Page Cache pointer */
+			temp.pc = xfer->frbuffers + x;
+		}
+	}
+
+	/* check for control transfer */
+	if (xfer->flags_int.control_xfr) {
+
+		/* always setup a valid "pc" pointer for status and sync */
+		temp.pc = xfer->frbuffers + 0;
+		temp.len = 0;
+		temp.short_pkt = 0;
+		temp.setup_alt_next = 0;
+
+		/* check if we should append a status stage */
+		if (!xfer->flags_int.control_act) {
+			/*
+			 * Send a DATA1 message and invert the current
+			 * endpoint direction.
+			 */
+			if (sc->sc_mode == MUSB2_DEVICE_MODE)
+				temp.func = &musbotg_dev_ctrl_status;
+			else {
+				if (xfer->endpointno & UE_DIR_IN)
+					temp.func = musbotg_host_ctrl_status_tx;
+				else
+					temp.func = musbotg_host_ctrl_status_rx;
+			}
+			musbotg_setup_standard_chain_sub(&temp);
+		}
+	}
+	/* must have at least one frame! */
+	td = temp.td;
+	xfer->td_transfer_last = td;
+}
+
+static void
+musbotg_timeout(void *arg)
+{
+	struct usb_xfer *xfer = arg;
+
+	DPRINTFN(1, "xfer=%p\n", xfer);
+
+	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
+
+	/* transfer is transferred */
+	musbotg_device_done(xfer, USB_ERR_TIMEOUT);
+}
+
+static void
+musbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on)
+{
+	uint16_t temp;
+
+	/*
+	 * Only enable the endpoint interrupt when we are
+	 * actually waiting for data, hence we are dealing
+	 * with level triggered interrupts !
+	 */
+	DPRINTFN(1, "ep_no=%d, on=%d\n", channel, on);
+
+	if (channel == -1)
+		return;
+
+	if (channel == 0) {
+		temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE);
+		if (on)
+			temp |= MUSB2_MASK_EPINT(0);
+		else
+			temp &= ~MUSB2_MASK_EPINT(0);
+
+		MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp);
+	} else {
+		temp = MUSB2_READ_2(sc, MUSB2_REG_INTRXE);
+		if (on)
+			temp |= MUSB2_MASK_EPINT(channel);
+		else
+			temp &= ~MUSB2_MASK_EPINT(channel);
+		MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, temp);
+
+		temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE);
+		if (on)
+			temp |= MUSB2_MASK_EPINT(channel);
+		else
+			temp &= ~MUSB2_MASK_EPINT(channel);
+		MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp);
+	}
+
+	if (sc->sc_ep_int_set)
+		sc->sc_ep_int_set(sc, channel, on);
+}
+
+static void
+musbotg_start_standard_chain(struct usb_xfer *xfer)
+{
+	DPRINTFN(8, "\n");
+
+	/* poll one time */
+	if (musbotg_xfer_do_fifo(xfer)) {
+
+		DPRINTFN(14, "enabled interrupts on endpoint\n");
+
+		/* put transfer on interrupt queue */
+		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
+
+		/* start timeout, if any */
+		if (xfer->timeout != 0) {
+			usbd_transfer_timeout_ms(xfer,
+			    &musbotg_timeout, xfer->timeout);
+		}
+	}
+}
+
+static void
+musbotg_root_intr(struct musbotg_softc *sc)
+{
+	DPRINTFN(8, "\n");
+
+	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
+
+	/* set port bit */
+	sc->sc_hub_idata[0] = 0x02;	/* we only have one port */
+
+	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
+	    sizeof(sc->sc_hub_idata));
+}
+
+static usb_error_t
+musbotg_standard_done_sub(struct usb_xfer *xfer)
+{
+	struct musbotg_td *td;
+	uint32_t len;
+	uint8_t error;
+
+	DPRINTFN(8, "\n");
+
+	td = xfer->td_transfer_cache;
+
+	do {
+		len = td->remainder;
+
+		xfer->endpoint->toggle_next = td->toggle;
+
+		if (xfer->aframes != xfer->nframes) {
+			/*
+		         * Verify the length and subtract
+		         * the remainder from "frlengths[]":
+		         */
+			if (len > xfer->frlengths[xfer->aframes]) {
+				td->error = 1;
+			} else {
+				xfer->frlengths[xfer->aframes] -= len;
+			}
+		}
+		/* Check for transfer error */
+		if (td->error) {
+			/* the transfer is finished */
+			error = 1;
+			td = NULL;
+			break;
+		}
+		/* Check for short transfer */
+		if (len > 0) {
+			if (xfer->flags_int.short_frames_ok ||
+			    xfer->flags_int.isochronous_xfr) {
+				/* follow alt next */
+				if (td->alt_next) {
+					td = td->obj_next;
+				} else {
+					td = NULL;
+				}
+			} else {
+				/* the transfer is finished */
+				td = NULL;
+			}
+			error = 0;
+			break;
+		}
+		td = td->obj_next;
+
+		/* this USB frame is complete */
+		error = 0;
+		break;
+
+	} while (0);
+
+	/* update transfer cache */
+
+	xfer->td_transfer_cache = td;
+
+	return (error ?
+	    USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
+}
+
+static void
+musbotg_standard_done(struct usb_xfer *xfer)
+{
+	usb_error_t err = 0;
+
+	DPRINTFN(12, "xfer=%p endpoint=%p transfer done\n",
+	    xfer, xfer->endpoint);
+
+	/* reset scanner */
+
+	xfer->td_transfer_cache = xfer->td_transfer_first;
+
+	if (xfer->flags_int.control_xfr) {
+
+		if (xfer->flags_int.control_hdr) {
+
+			err = musbotg_standard_done_sub(xfer);
+		}
+		xfer->aframes = 1;
+
+		if (xfer->td_transfer_cache == NULL) {
+			goto done;
+		}
+	}
+	while (xfer->aframes != xfer->nframes) {
+
+		err = musbotg_standard_done_sub(xfer);
+		xfer->aframes++;
+
+		if (xfer->td_transfer_cache == NULL) {
+			goto done;
+		}
+	}
+
+	if (xfer->flags_int.control_xfr &&
+	    !xfer->flags_int.control_act) {
+
+		err = musbotg_standard_done_sub(xfer);
+	}
+done:
+	musbotg_device_done(xfer, err);
+}
+
+/*------------------------------------------------------------------------*
+ *	musbotg_device_done
+ *
+ * NOTE: this function can be called more than one time on the
+ * same USB transfer!
+ *------------------------------------------------------------------------*/
+static void
+musbotg_device_done(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct musbotg_td *td;
+	struct musbotg_softc *sc;
+
+	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
+
+	DPRINTFN(1, "xfer=%p, endpoint=%p, error=%d\n",
+	    xfer, xfer->endpoint, error);
+
+	DPRINTFN(14, "disabled interrupts on endpoint\n");
+
+	sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
+	td = xfer->td_transfer_cache;
+
+	if (td && (td->channel != -1))
+		musbotg_channel_free(sc, td);
+
+	/* dequeue transfer and start next transfer */
+	usbd_transfer_done(xfer, error);
+}
+
+static void
+musbotg_xfer_stall(struct usb_xfer *xfer)
+{
+	musbotg_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+musbotg_set_stall(struct usb_device *udev,
+    struct usb_endpoint *ep, uint8_t *did_stall)
+{
+	struct musbotg_softc *sc;
+	uint8_t ep_no;
+
+	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
+
+	DPRINTFN(4, "endpoint=%p\n", ep);
+
+	/* set FORCESTALL */
+	sc = MUSBOTG_BUS2SC(udev->bus);
+
+	ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
+
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no);
+
+	if (ep->edesc->bEndpointAddress & UE_DIR_IN) {
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSRL_TXSENDSTALL);
+	} else {
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+		    MUSB2_MASK_CSRL_RXSENDSTALL);
+	}
+}
+
+static void
+musbotg_clear_stall_sub(struct musbotg_softc *sc, uint16_t wMaxPacket,
+    uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)
+{
+	uint16_t mps;
+	uint16_t temp;
+	uint8_t csr;
+
+	if (ep_type == UE_CONTROL) {
+		/* clearing stall is not needed */
+		return;
+	}
+	/* select endpoint */
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no);
+
+	/* compute max frame size */
+	mps = wMaxPacket & 0x7FF;
+	switch ((wMaxPacket >> 11) & 3) {
+	case 1:
+		mps *= 2;
+		break;
+	case 2:
+		mps *= 3;
+		break;
+	default:
+		break;
+	}
+
+	if (ep_dir == UE_DIR_IN) {
+
+		temp = 0;
+
+		/* Configure endpoint */
+		switch (ep_type) {
+		case UE_INTERRUPT:
+			MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH,
+			    MUSB2_MASK_CSRH_TXMODE | temp);
+			break;
+		case UE_ISOCHRONOUS:
+			MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH,
+			    MUSB2_MASK_CSRH_TXMODE |
+			    MUSB2_MASK_CSRH_TXISO | temp);
+			break;
+		case UE_BULK:
+			MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH,
+			    MUSB2_MASK_CSRH_TXMODE | temp);
+			break;
+		default:
+			break;
+		}
+
+		/* Need to flush twice in case of double bufring */
+		csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+		if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+			    MUSB2_MASK_CSRL_TXFFLUSH);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
+				MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+				    MUSB2_MASK_CSRL_TXFFLUSH);
+				csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+			}
+		}
+		/* reset data toggle */
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
+		    MUSB2_MASK_CSRL_TXDT_CLR);
+		MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+		csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+
+		/* set double/single buffering */
+		temp = MUSB2_READ_2(sc, MUSB2_REG_TXDBDIS);
+		if (mps <= (sc->sc_hw_ep_profile[ep_no].
+		    max_in_frame_size / 2)) {
+			/* double buffer */
+			temp &= ~(1 << ep_no);
+		} else {
+			/* single buffer */
+			temp |= (1 << ep_no);
+		}
+		MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, temp);
+
+		/* clear sent stall */
+		if (csr & MUSB2_MASK_CSRL_TXSENTSTALL) {
+			MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
+		}
+	} else {
+
+		temp = 0;
+
+		/* Configure endpoint */
+		switch (ep_type) {
+		case UE_INTERRUPT:
+			MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH,
+			    MUSB2_MASK_CSRH_RXNYET | temp);
+			break;
+		case UE_ISOCHRONOUS:
+			MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH,
+			    MUSB2_MASK_CSRH_RXNYET |
+			    MUSB2_MASK_CSRH_RXISO | temp);
+			break;
+		case UE_BULK:
+			MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket);
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, temp);
+			break;
+		default:
+			break;
+		}
+
+		/* Need to flush twice in case of double bufring */
+		csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+		if (csr & MUSB2_MASK_CSRL_RXPKTRDY) {
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+			    MUSB2_MASK_CSRL_RXFFLUSH);
+			csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+			if (csr & MUSB2_MASK_CSRL_RXPKTRDY) {
+				MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+				    MUSB2_MASK_CSRL_RXFFLUSH);
+				csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+			}
+		}
+		/* reset data toggle */
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
+		    MUSB2_MASK_CSRL_RXDT_CLR);
+		MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0);
+		csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
+
+		/* set double/single buffering */
+		temp = MUSB2_READ_2(sc, MUSB2_REG_RXDBDIS);
+		if (mps <= (sc->sc_hw_ep_profile[ep_no].
+		    max_out_frame_size / 2)) {
+			/* double buffer */
+			temp &= ~(1 << ep_no);
+		} else {
+			/* single buffer */
+			temp |= (1 << ep_no);
+		}
+		MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, temp);
+
+		/* clear sent stall */
+		if (csr & MUSB2_MASK_CSRL_RXSENTSTALL) {
+			MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0);
+		}
+	}
+}
+
+static void
+musbotg_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
+{
+	struct musbotg_softc *sc;
+	struct usb_endpoint_descriptor *ed;
+
+	DPRINTFN(4, "endpoint=%p\n", ep);
+
+	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
+
+	/* check mode */
+	if (udev->flags.usb_mode != USB_MODE_DEVICE) {
+		/* not supported */
+		return;
+	}
+	/* get softc */
+	sc = MUSBOTG_BUS2SC(udev->bus);
+
+	/* get endpoint descriptor */
+	ed = ep->edesc;
+
+	/* reset endpoint */
+	musbotg_clear_stall_sub(sc,
+	    UGETW(ed->wMaxPacketSize),
+	    (ed->bEndpointAddress & UE_ADDR),
+	    (ed->bmAttributes & UE_XFERTYPE),
+	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
+}
+
+usb_error_t
+musbotg_init(struct musbotg_softc *sc)
+{
+	struct usb_hw_ep_profile *pf;
+	uint16_t offset;
+	uint8_t nrx;
+	uint8_t ntx;
+	uint8_t temp;
+	uint8_t fsize;
+	uint8_t frx;
+	uint8_t ftx;
+	uint8_t dynfifo;
+
+	DPRINTFN(1, "start\n");
+
+	/* set up the bus structure */
+	sc->sc_bus.usbrev = USB_REV_2_0;
+	sc->sc_bus.methods = &musbotg_bus_methods;
+
+	USB_BUS_LOCK(&sc->sc_bus);
+
+	/* turn on clocks */
+
+	if (sc->sc_clocks_on) {
+		(sc->sc_clocks_on) (sc->sc_clocks_arg);
+	}
+
+	/* wait a little for things to stabilise */
+	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000);
+
+	/* disable all interrupts */
+
+	temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL);
+	DPRINTF("pre-DEVCTL=0x%02x\n", temp);
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0);
+	MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0);
+	MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0);
+
+	/* disable pullup */
+
+	musbotg_pull_common(sc, 0);
+
+	/* wait a little bit (10ms) */
+	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);
+
+
+	/* disable double packet buffering */
+	MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, 0xFFFF);
+	MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, 0xFFFF);
+
+	/* enable HighSpeed and ISO Update flags */
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_POWER,
+	    MUSB2_MASK_HSENAB | MUSB2_MASK_ISOUPD);
+
+	if (sc->sc_mode == MUSB2_DEVICE_MODE) {
+		/* clear Session bit, if set */
+		temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL);
+		temp &= ~MUSB2_MASK_SESS;
+		MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp);
+	} else {
+		/* Enter session for Host mode */
+		temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL);
+		temp |= MUSB2_MASK_SESS;
+		MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp);
+	}
+
+	/* wait a little for things to stabilise */
+	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 10);
+
+	DPRINTF("DEVCTL=0x%02x\n", temp);
+
+	/* disable testmode */
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_TESTMODE, 0);
+
+	/* set default value */
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_MISC, 0);
+
+	/* select endpoint index 0 */
+
+	MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
+
+	/* read out number of endpoints */
+
+	nrx =
+	    (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) / 16);
+
+	ntx =
+	    (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) % 16);
+
+	/* these numbers exclude the control endpoint */
+
+	DPRINTFN(2, "RX/TX endpoints: %u/%u\n", nrx, ntx);
+
+	sc->sc_ep_max = (nrx > ntx) ? nrx : ntx;
+	if (sc->sc_ep_max == 0) {
+		DPRINTFN(2, "ERROR: Looks like the clocks are off!\n");
+	}
+	/* read out configuration data */
+
+	sc->sc_conf_data = MUSB2_READ_1(sc, MUSB2_REG_CONFDATA);
+
+	DPRINTFN(2, "Config Data: 0x%02x\n",
+	    sc->sc_conf_data);
+
+	dynfifo = (sc->sc_conf_data & MUSB2_MASK_CD_DYNFIFOSZ) ? 1 : 0;
+
+	if (dynfifo) {
+		device_printf(sc->sc_bus.bdev, "Dynamic FIFO sizing detected, "
+		    "assuming 16Kbytes of FIFO RAM\n");
+	}
+
+	DPRINTFN(2, "HW version: 0x%04x\n",
+	    MUSB2_READ_1(sc, MUSB2_REG_HWVERS));
+
+	/* initialise endpoint profiles */
+
+	offset = 0;
+
+	for (temp = 1; temp <= sc->sc_ep_max; temp++) {
+		pf = sc->sc_hw_ep_profile + temp;
+
+		/* select endpoint */
+		MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, temp);
+
+		fsize = MUSB2_READ_1(sc, MUSB2_REG_FSIZE);
+		frx = (fsize & MUSB2_MASK_RX_FSIZE) / 16;
+		ftx = (fsize & MUSB2_MASK_TX_FSIZE);
+
+		DPRINTF("Endpoint %u FIFO size: IN=%u, OUT=%u, DYN=%d\n",
+		    temp, ftx, frx, dynfifo);
+
+		if (dynfifo) {
+			if (frx && (temp <= nrx)) {
+				if (temp == 1) {
+					frx = 12;	/* 4K */
+					MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 
+					    MUSB2_VAL_FIFOSZ_4096 |
+					    MUSB2_MASK_FIFODB);
+				} else if (temp < 8) {
+					frx = 10;	/* 1K */
+					MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 
+					    MUSB2_VAL_FIFOSZ_512 |
+					    MUSB2_MASK_FIFODB);
+				} else {
+					frx = 7;	/* 128 bytes */
+					MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 
+					    MUSB2_VAL_FIFOSZ_128);
+				}
+
+				MUSB2_WRITE_2(sc, MUSB2_REG_RXFIFOADD,
+				    offset >> 3);
+
+				offset += (1 << frx);
+			}
+			if (ftx && (temp <= ntx)) {
+				if (temp == 1) {
+					ftx = 12;	/* 4K */
+					MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ,
+	 				    MUSB2_VAL_FIFOSZ_4096 |
+	 				    MUSB2_MASK_FIFODB);
+				} else if (temp < 8) {
+					ftx = 10;	/* 1K */
+					MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ,
+	 				    MUSB2_VAL_FIFOSZ_512 |
+	 				    MUSB2_MASK_FIFODB);
+				} else {
+					ftx = 7;	/* 128 bytes */
+					MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ,
+	 				    MUSB2_VAL_FIFOSZ_128);
+				}
+
+				MUSB2_WRITE_2(sc, MUSB2_REG_TXFIFOADD,
+				    offset >> 3);
+
+				offset += (1 << ftx);
+			}
+		}
+
+		if (frx && ftx && (temp <= nrx) && (temp <= ntx)) {
+			pf->max_in_frame_size = 1 << ftx;
+			pf->max_out_frame_size = 1 << frx;
+			pf->is_simplex = 0;	/* duplex */
+			pf->support_multi_buffer = 1;
+			pf->support_bulk = 1;
+			pf->support_interrupt = 1;
+			pf->support_isochronous = 1;
+			pf->support_in = 1;
+			pf->support_out = 1;
+		} else if (frx && (temp <= nrx)) {
+			pf->max_out_frame_size = 1 << frx;
+			pf->max_in_frame_size = 0;
+			pf->is_simplex = 1;	/* simplex */
+			pf->support_multi_buffer = 1;
+			pf->support_bulk = 1;
+			pf->support_interrupt = 1;
+			pf->support_isochronous = 1;
+			pf->support_out = 1;
+		} else if (ftx && (temp <= ntx)) {
+			pf->max_in_frame_size = 1 << ftx;
+			pf->max_out_frame_size = 0;
+			pf->is_simplex = 1;	/* simplex */
+			pf->support_multi_buffer = 1;
+			pf->support_bulk = 1;
+			pf->support_interrupt = 1;
+			pf->support_isochronous = 1;
+			pf->support_in = 1;
+		}
+	}
+
+	DPRINTFN(2, "Dynamic FIFO size = %d bytes\n", offset);
+
+	/* turn on default interrupts */
+
+	if (sc->sc_mode == MUSB2_HOST_MODE)
+		MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0xff);
+	else
+		MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE,
+		    MUSB2_MASK_IRESET);
+
+	musbotg_clocks_off(sc);
+
+	USB_BUS_UNLOCK(&sc->sc_bus);
+
+	/* catch any lost interrupts */
+
+	musbotg_do_poll(&sc->sc_bus);
+
+	return (0);			/* success */
+}
+
+void
+musbotg_uninit(struct musbotg_softc *sc)
+{
+	USB_BUS_LOCK(&sc->sc_bus);
+
+	/* disable all interrupts */
+	MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0);
+	MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0);
+	MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0);
+
+	sc->sc_flags.port_powered = 0;
+	sc->sc_flags.status_vbus = 0;
+	sc->sc_flags.status_bus_reset = 0;
+	sc->sc_flags.status_suspend = 0;
+	sc->sc_flags.change_suspend = 0;
+	sc->sc_flags.change_connect = 1;
+
+	musbotg_pull_down(sc);
+	musbotg_clocks_off(sc);
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
+static void
+musbotg_do_poll(struct usb_bus *bus)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus);
+
+	USB_BUS_LOCK(&sc->sc_bus);
+	musbotg_interrupt_poll(sc);
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
+/*------------------------------------------------------------------------*
+ * musbotg bulk support
+ *------------------------------------------------------------------------*/
+static void
+musbotg_device_bulk_open(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_bulk_close(struct usb_xfer *xfer)
+{
+	musbotg_device_done(xfer, USB_ERR_CANCELLED);
+}
+
+static void
+musbotg_device_bulk_enter(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_bulk_start(struct usb_xfer *xfer)
+{
+	/* setup TDs */
+	musbotg_setup_standard_chain(xfer);
+	musbotg_start_standard_chain(xfer);
+}
+
+static const struct usb_pipe_methods musbotg_device_bulk_methods =
+{
+	.open = musbotg_device_bulk_open,
+	.close = musbotg_device_bulk_close,
+	.enter = musbotg_device_bulk_enter,
+	.start = musbotg_device_bulk_start,
+};
+
+/*------------------------------------------------------------------------*
+ * musbotg control support
+ *------------------------------------------------------------------------*/
+static void
+musbotg_device_ctrl_open(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_ctrl_close(struct usb_xfer *xfer)
+{
+	musbotg_device_done(xfer, USB_ERR_CANCELLED);
+}
+
+static void
+musbotg_device_ctrl_enter(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_ctrl_start(struct usb_xfer *xfer)
+{
+	/* setup TDs */
+	musbotg_setup_standard_chain(xfer);
+	musbotg_start_standard_chain(xfer);
+}
+
+static const struct usb_pipe_methods musbotg_device_ctrl_methods =
+{
+	.open = musbotg_device_ctrl_open,
+	.close = musbotg_device_ctrl_close,
+	.enter = musbotg_device_ctrl_enter,
+	.start = musbotg_device_ctrl_start,
+};
+
+/*------------------------------------------------------------------------*
+ * musbotg interrupt support
+ *------------------------------------------------------------------------*/
+static void
+musbotg_device_intr_open(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_intr_close(struct usb_xfer *xfer)
+{
+	musbotg_device_done(xfer, USB_ERR_CANCELLED);
+}
+
+static void
+musbotg_device_intr_enter(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_intr_start(struct usb_xfer *xfer)
+{
+	/* setup TDs */
+	musbotg_setup_standard_chain(xfer);
+	musbotg_start_standard_chain(xfer);
+}
+
+static const struct usb_pipe_methods musbotg_device_intr_methods =
+{
+	.open = musbotg_device_intr_open,
+	.close = musbotg_device_intr_close,
+	.enter = musbotg_device_intr_enter,
+	.start = musbotg_device_intr_start,
+};
+
+/*------------------------------------------------------------------------*
+ * musbotg full speed isochronous support
+ *------------------------------------------------------------------------*/
+static void
+musbotg_device_isoc_open(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_device_isoc_close(struct usb_xfer *xfer)
+{
+	musbotg_device_done(xfer, USB_ERR_CANCELLED);
+}
+
+static void
+musbotg_device_isoc_enter(struct usb_xfer *xfer)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
+	uint32_t temp;
+	uint32_t nframes;
+	uint32_t fs_frames;
+
+	DPRINTFN(5, "xfer=%p next=%d nframes=%d\n",
+	    xfer, xfer->endpoint->isoc_next, xfer->nframes);
+
+	/* get the current frame index */
+
+	nframes = MUSB2_READ_2(sc, MUSB2_REG_FRAME);
+
+	/*
+	 * check if the frame index is within the window where the frames
+	 * will be inserted
+	 */
+	temp = (nframes - xfer->endpoint->isoc_next) & MUSB2_MASK_FRAME;
+
+	if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) {
+		fs_frames = (xfer->nframes + 7) / 8;
+	} else {
+		fs_frames = xfer->nframes;
+	}
+
+	if ((xfer->endpoint->is_synced == 0) ||
+	    (temp < fs_frames)) {
+		/*
+		 * If there is data underflow or the pipe queue is
+		 * empty we schedule the transfer a few frames ahead
+		 * of the current frame position. Else two isochronous
+		 * transfers might overlap.
+		 */
+		xfer->endpoint->isoc_next = (nframes + 3) & MUSB2_MASK_FRAME;
+		xfer->endpoint->is_synced = 1;
+		DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next);
+	}
+	/*
+	 * compute how many milliseconds the insertion is ahead of the
+	 * current frame position:
+	 */
+	temp = (xfer->endpoint->isoc_next - nframes) & MUSB2_MASK_FRAME;
+
+	/*
+	 * pre-compute when the isochronous transfer will be finished:
+	 */
+	xfer->isoc_time_complete =
+	    usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
+	    fs_frames;
+
+	/* compute frame number for next insertion */
+	xfer->endpoint->isoc_next += fs_frames;
+
+	/* setup TDs */
+	musbotg_setup_standard_chain(xfer);
+}
+
+static void
+musbotg_device_isoc_start(struct usb_xfer *xfer)
+{
+	/* start TD chain */
+	musbotg_start_standard_chain(xfer);
+}
+
+static const struct usb_pipe_methods musbotg_device_isoc_methods =
+{
+	.open = musbotg_device_isoc_open,
+	.close = musbotg_device_isoc_close,
+	.enter = musbotg_device_isoc_enter,
+	.start = musbotg_device_isoc_start,
+};
+
+/*------------------------------------------------------------------------*
+ * musbotg root control support
+ *------------------------------------------------------------------------*
+ * Simulate a hardware HUB by handling all the necessary requests.
+ *------------------------------------------------------------------------*/
+
+static const struct usb_device_descriptor musbotg_devd = {
+	.bLength = sizeof(struct usb_device_descriptor),
+	.bDescriptorType = UDESC_DEVICE,
+	.bcdUSB = {0x00, 0x02},
+	.bDeviceClass = UDCLASS_HUB,
+	.bDeviceSubClass = UDSUBCLASS_HUB,
+	.bDeviceProtocol = UDPROTO_HSHUBSTT,
+	.bMaxPacketSize = 64,
+	.bcdDevice = {0x00, 0x01},
+	.iManufacturer = 1,
+	.iProduct = 2,
+	.bNumConfigurations = 1,
+};
+
+static const struct usb_device_qualifier musbotg_odevd = {
+	.bLength = sizeof(struct usb_device_qualifier),
+	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
+	.bcdUSB = {0x00, 0x02},
+	.bDeviceClass = UDCLASS_HUB,
+	.bDeviceSubClass = UDSUBCLASS_HUB,
+	.bDeviceProtocol = UDPROTO_FSHUB,
+	.bMaxPacketSize0 = 0,
+	.bNumConfigurations = 0,
+};
+
+static const struct musbotg_config_desc musbotg_confd = {
+	.confd = {
+		.bLength = sizeof(struct usb_config_descriptor),
+		.bDescriptorType = UDESC_CONFIG,
+		.wTotalLength[0] = sizeof(musbotg_confd),
+		.bNumInterface = 1,
+		.bConfigurationValue = 1,
+		.iConfiguration = 0,
+		.bmAttributes = UC_SELF_POWERED,
+		.bMaxPower = 0,
+	},
+	.ifcd = {
+		.bLength = sizeof(struct usb_interface_descriptor),
+		.bDescriptorType = UDESC_INTERFACE,
+		.bNumEndpoints = 1,
+		.bInterfaceClass = UICLASS_HUB,
+		.bInterfaceSubClass = UISUBCLASS_HUB,
+		.bInterfaceProtocol = 0,
+	},
+	.endpd = {
+		.bLength = sizeof(struct usb_endpoint_descriptor),
+		.bDescriptorType = UDESC_ENDPOINT,
+		.bEndpointAddress = (UE_DIR_IN | MUSBOTG_INTR_ENDPT),
+		.bmAttributes = UE_INTERRUPT,
+		.wMaxPacketSize[0] = 8,
+		.bInterval = 255,
+	},
+};
+
+#define	HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
+
+static const struct usb_hub_descriptor_min musbotg_hubd = {
+	.bDescLength = sizeof(musbotg_hubd),
+	.bDescriptorType = UDESC_HUB,
+	.bNbrPorts = 1,
+	HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
+	.bPwrOn2PwrGood = 50,
+	.bHubContrCurrent = 0,
+	.DeviceRemovable = {0},		/* port is removable */
+};
+
+#define	STRING_VENDOR \
+  "M\0e\0n\0t\0o\0r\0 \0G\0r\0a\0p\0h\0i\0c\0s"
+
+#define	STRING_PRODUCT \
+  "O\0T\0G\0 \0R\0o\0o\0t\0 \0H\0U\0B"
+
+USB_MAKE_STRING_DESC(STRING_VENDOR, musbotg_vendor);
+USB_MAKE_STRING_DESC(STRING_PRODUCT, musbotg_product);
+
+static usb_error_t
+musbotg_roothub_exec(struct usb_device *udev,
+    struct usb_device_request *req, const void **pptr, uint16_t *plength)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus);
+	const void *ptr;
+	uint16_t len;
+	uint16_t value;
+	uint16_t index;
+	uint8_t reg;
+	usb_error_t err;
+
+	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
+
+	/* buffer reset */
+	ptr = (const void *)&sc->sc_hub_temp;
+	len = 0;
+	err = 0;
+
+	value = UGETW(req->wValue);
+	index = UGETW(req->wIndex);
+
+	/* demultiplex the control request */
+
+	switch (req->bmRequestType) {
+	case UT_READ_DEVICE:
+		switch (req->bRequest) {
+		case UR_GET_DESCRIPTOR:
+			goto tr_handle_get_descriptor;
+		case UR_GET_CONFIG:
+			goto tr_handle_get_config;
+		case UR_GET_STATUS:
+			goto tr_handle_get_status;
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_WRITE_DEVICE:
+		switch (req->bRequest) {
+		case UR_SET_ADDRESS:
+			goto tr_handle_set_address;
+		case UR_SET_CONFIG:
+			goto tr_handle_set_config;
+		case UR_CLEAR_FEATURE:
+			goto tr_valid;	/* nop */
+		case UR_SET_DESCRIPTOR:
+			goto tr_valid;	/* nop */
+		case UR_SET_FEATURE:
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_WRITE_ENDPOINT:
+		switch (req->bRequest) {
+		case UR_CLEAR_FEATURE:
+			switch (UGETW(req->wValue)) {
+			case UF_ENDPOINT_HALT:
+				goto tr_handle_clear_halt;
+			case UF_DEVICE_REMOTE_WAKEUP:
+				goto tr_handle_clear_wakeup;
+			default:
+				goto tr_stalled;
+			}
+			break;
+		case UR_SET_FEATURE:
+			switch (UGETW(req->wValue)) {
+			case UF_ENDPOINT_HALT:
+				goto tr_handle_set_halt;
+			case UF_DEVICE_REMOTE_WAKEUP:
+				goto tr_handle_set_wakeup;
+			default:
+				goto tr_stalled;
+			}
+			break;
+		case UR_SYNCH_FRAME:
+			goto tr_valid;	/* nop */
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_READ_ENDPOINT:
+		switch (req->bRequest) {
+		case UR_GET_STATUS:
+			goto tr_handle_get_ep_status;
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_WRITE_INTERFACE:
+		switch (req->bRequest) {
+		case UR_SET_INTERFACE:
+			goto tr_handle_set_interface;
+		case UR_CLEAR_FEATURE:
+			goto tr_valid;	/* nop */
+		case UR_SET_FEATURE:
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_READ_INTERFACE:
+		switch (req->bRequest) {
+		case UR_GET_INTERFACE:
+			goto tr_handle_get_interface;
+		case UR_GET_STATUS:
+			goto tr_handle_get_iface_status;
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_WRITE_CLASS_INTERFACE:
+	case UT_WRITE_VENDOR_INTERFACE:
+		/* XXX forward */
+		break;
+
+	case UT_READ_CLASS_INTERFACE:
+	case UT_READ_VENDOR_INTERFACE:
+		/* XXX forward */
+		break;
+
+	case UT_WRITE_CLASS_DEVICE:
+		switch (req->bRequest) {
+		case UR_CLEAR_FEATURE:
+			goto tr_valid;
+		case UR_SET_DESCRIPTOR:
+		case UR_SET_FEATURE:
+			break;
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_WRITE_CLASS_OTHER:
+		switch (req->bRequest) {
+		case UR_CLEAR_FEATURE:
+			goto tr_handle_clear_port_feature;
+		case UR_SET_FEATURE:
+			goto tr_handle_set_port_feature;
+		case UR_CLEAR_TT_BUFFER:
+		case UR_RESET_TT:
+		case UR_STOP_TT:
+			goto tr_valid;
+
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_READ_CLASS_OTHER:
+		switch (req->bRequest) {
+		case UR_GET_TT_STATE:
+			goto tr_handle_get_tt_state;
+		case UR_GET_STATUS:
+			goto tr_handle_get_port_status;
+		default:
+			goto tr_stalled;
+		}
+		break;
+
+	case UT_READ_CLASS_DEVICE:
+		switch (req->bRequest) {
+		case UR_GET_DESCRIPTOR:
+			goto tr_handle_get_class_descriptor;
+		case UR_GET_STATUS:
+			goto tr_handle_get_class_status;
+
+		default:
+			goto tr_stalled;
+		}
+		break;
+	default:
+		goto tr_stalled;
+	}
+	goto tr_valid;
+
+tr_handle_get_descriptor:
+	switch (value >> 8) {
+	case UDESC_DEVICE:
+		if (value & 0xff) {
+			goto tr_stalled;
+		}
+		len = sizeof(musbotg_devd);
+		ptr = (const void *)&musbotg_devd;
+		goto tr_valid;
+	case UDESC_DEVICE_QUALIFIER:
+		if (value & 0xff) {
+			goto tr_stalled;
+		}
+		len = sizeof(musbotg_odevd);
+		ptr = (const void *)&musbotg_odevd;
+		goto tr_valid;
+	case UDESC_CONFIG:
+		if (value & 0xff) {
+			goto tr_stalled;
+		}
+		len = sizeof(musbotg_confd);
+		ptr = (const void *)&musbotg_confd;
+		goto tr_valid;
+	case UDESC_STRING:
+		switch (value & 0xff) {
+		case 0:		/* Language table */
+			len = sizeof(usb_string_lang_en);
+			ptr = (const void *)&usb_string_lang_en;
+			goto tr_valid;
+
+		case 1:		/* Vendor */
+			len = sizeof(musbotg_vendor);
+			ptr = (const void *)&musbotg_vendor;
+			goto tr_valid;
+
+		case 2:		/* Product */
+			len = sizeof(musbotg_product);
+			ptr = (const void *)&musbotg_product;
+			goto tr_valid;
+		default:
+			break;
+		}
+		break;
+	default:
+		goto tr_stalled;
+	}
+	goto tr_stalled;
+
+tr_handle_get_config:
+	len = 1;
+	sc->sc_hub_temp.wValue[0] = sc->sc_conf;
+	goto tr_valid;
+
+tr_handle_get_status:
+	len = 2;
+	USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
+	goto tr_valid;
+
+tr_handle_set_address:
+	if (value & 0xFF00) {
+		goto tr_stalled;
+	}
+	sc->sc_rt_addr = value;
+	goto tr_valid;
+
+tr_handle_set_config:
+	if (value >= 2) {
+		goto tr_stalled;
+	}
+	sc->sc_conf = value;
+	goto tr_valid;
+
+tr_handle_get_interface:
+	len = 1;
+	sc->sc_hub_temp.wValue[0] = 0;
+	goto tr_valid;
+
+tr_handle_get_tt_state:
+tr_handle_get_class_status:
+tr_handle_get_iface_status:
+tr_handle_get_ep_status:
+	len = 2;
+	USETW(sc->sc_hub_temp.wValue, 0);
+	goto tr_valid;
+
+tr_handle_set_halt:
+tr_handle_set_interface:
+tr_handle_set_wakeup:
+tr_handle_clear_wakeup:
+tr_handle_clear_halt:
+	goto tr_valid;
+
+tr_handle_clear_port_feature:
+	if (index != 1) {
+		goto tr_stalled;
+	}
+	DPRINTFN(8, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
+
+	switch (value) {
+	case UHF_PORT_SUSPEND:
+		if (sc->sc_mode == MUSB2_HOST_MODE)
+			musbotg_wakeup_host(sc);
+		else
+			musbotg_wakeup_peer(sc);
+		break;
+
+	case UHF_PORT_ENABLE:
+		sc->sc_flags.port_enabled = 0;
+		break;
+
+	case UHF_C_PORT_ENABLE:
+		sc->sc_flags.change_enabled = 0;
+		break;
+
+	case UHF_C_PORT_OVER_CURRENT:
+		sc->sc_flags.change_over_current = 0;
+		break;
+
+	case UHF_C_PORT_RESET:
+		sc->sc_flags.change_reset = 0;
+		break;
+
+	case UHF_PORT_TEST:
+	case UHF_PORT_INDICATOR:
+		/* nops */
+		break;
+
+	case UHF_PORT_POWER:
+		sc->sc_flags.port_powered = 0;
+		musbotg_pull_down(sc);
+		musbotg_clocks_off(sc);
+		break;
+	case UHF_C_PORT_CONNECTION:
+		sc->sc_flags.change_connect = 0;
+		break;
+	case UHF_C_PORT_SUSPEND:
+		sc->sc_flags.change_suspend = 0;
+		break;
+	default:
+		err = USB_ERR_IOERROR;
+		goto done;
+	}
+	goto tr_valid;
+
+tr_handle_set_port_feature:
+	if (index != 1) {
+		goto tr_stalled;
+	}
+	DPRINTFN(8, "UR_SET_PORT_FEATURE\n");
+
+	switch (value) {
+	case UHF_PORT_ENABLE:
+		sc->sc_flags.port_enabled = 1;
+		break;
+	case UHF_PORT_SUSPEND:
+		if (sc->sc_mode == MUSB2_HOST_MODE)
+			musbotg_suspend_host(sc);
+		break;
+
+	case UHF_PORT_RESET:
+		if (sc->sc_mode == MUSB2_HOST_MODE) {
+			reg = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+			reg |= MUSB2_MASK_RESET;
+			MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg);
+
+			/* Wait for 20 msec */
+			usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 5);
+
+			reg = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+			reg &= ~MUSB2_MASK_RESET;
+			MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg);
+
+			/* determine line speed */
+			reg = MUSB2_READ_1(sc, MUSB2_REG_POWER);
+			if (reg & MUSB2_MASK_HSMODE)
+				sc->sc_flags.status_high_speed = 1;
+			else
+				sc->sc_flags.status_high_speed = 0;
+
+			sc->sc_flags.change_reset = 1;
+		} else
+			err = USB_ERR_IOERROR;
+		break;
+
+	case UHF_PORT_TEST:
+	case UHF_PORT_INDICATOR:
+		/* nops */
+		break;
+	case UHF_PORT_POWER:
+		sc->sc_flags.port_powered = 1;
+		break;
+	default:
+		err = USB_ERR_IOERROR;
+		goto done;
+	}
+	goto tr_valid;
+
+tr_handle_get_port_status:
+
+	DPRINTFN(8, "UR_GET_PORT_STATUS\n");
+
+	if (index != 1) {
+		goto tr_stalled;
+	}
+	if (sc->sc_flags.status_vbus) {
+		musbotg_clocks_on(sc);
+		musbotg_pull_up(sc);
+	} else {
+		musbotg_pull_down(sc);
+		musbotg_clocks_off(sc);
+	}
+
+	/* Select Device Side Mode */
+	if (sc->sc_mode == MUSB2_DEVICE_MODE)
+		value = UPS_PORT_MODE_DEVICE;
+	else
+		value = 0;
+
+	if (sc->sc_flags.status_high_speed) {
+		value |= UPS_HIGH_SPEED;
+	}
+	if (sc->sc_flags.port_powered) {
+		value |= UPS_PORT_POWER;
+	}
+	if (sc->sc_flags.port_enabled) {
+		value |= UPS_PORT_ENABLED;
+	}
+
+	if (sc->sc_flags.port_over_current)
+		value |= UPS_OVERCURRENT_INDICATOR;
+
+	if (sc->sc_flags.status_vbus &&
+	    sc->sc_flags.status_bus_reset) {
+		value |= UPS_CURRENT_CONNECT_STATUS;
+	}
+	if (sc->sc_flags.status_suspend) {
+		value |= UPS_SUSPEND;
+	}
+	USETW(sc->sc_hub_temp.ps.wPortStatus, value);
+
+	value = 0;
+
+	if (sc->sc_flags.change_connect) {
+		value |= UPS_C_CONNECT_STATUS;
+
+		if (sc->sc_mode == MUSB2_DEVICE_MODE) {
+			if (sc->sc_flags.status_vbus &&
+			    sc->sc_flags.status_bus_reset) {
+				/* reset EP0 state */
+				sc->sc_ep0_busy = 0;
+				sc->sc_ep0_cmd = 0;
+			}
+		}
+	}
+	if (sc->sc_flags.change_suspend)
+		value |= UPS_C_SUSPEND;
+	if (sc->sc_flags.change_reset)
+		value |= UPS_C_PORT_RESET;
+	if (sc->sc_flags.change_over_current)
+		value |= UPS_C_OVERCURRENT_INDICATOR;
+
+	USETW(sc->sc_hub_temp.ps.wPortChange, value);
+	len = sizeof(sc->sc_hub_temp.ps);
+	goto tr_valid;
+
+tr_handle_get_class_descriptor:
+	if (value & 0xFF) {
+		goto tr_stalled;
+	}
+	ptr = (const void *)&musbotg_hubd;
+	len = sizeof(musbotg_hubd);
+	goto tr_valid;
+
+tr_stalled:
+	err = USB_ERR_STALLED;
+tr_valid:
+done:
+	*plength = len;
+	*pptr = ptr;
+	return (err);
+}
+
+static void
+musbotg_xfer_setup(struct usb_setup_params *parm)
+{
+	struct musbotg_softc *sc;
+	struct usb_xfer *xfer;
+	void *last_obj;
+	uint32_t ntd;
+	uint32_t n;
+	uint8_t ep_no;
+
+	sc = MUSBOTG_BUS2SC(parm->udev->bus);
+	xfer = parm->curr_xfer;
+
+	/*
+	 * NOTE: This driver does not use any of the parameters that
+	 * are computed from the following values. Just set some
+	 * reasonable dummies:
+	 */
+	parm->hc_max_packet_size = 0x400;
+	parm->hc_max_frame_size = 0xc00;
+
+	if ((parm->methods == &musbotg_device_isoc_methods) ||
+	    (parm->methods == &musbotg_device_intr_methods))
+		parm->hc_max_packet_count = 3;
+	else
+		parm->hc_max_packet_count = 1;
+
+	usbd_transfer_setup_sub(parm);
+
+	/*
+	 * compute maximum number of TDs
+	 */
+	if (parm->methods == &musbotg_device_ctrl_methods) {
+
+		ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ;
+
+	} else if (parm->methods == &musbotg_device_bulk_methods) {
+
+		ntd = xfer->nframes + 1 /* SYNC */ ;
+
+	} else if (parm->methods == &musbotg_device_intr_methods) {
+
+		ntd = xfer->nframes + 1 /* SYNC */ ;
+
+	} else if (parm->methods == &musbotg_device_isoc_methods) {
+
+		ntd = xfer->nframes + 1 /* SYNC */ ;
+
+	} else {
+
+		ntd = 0;
+	}
+
+	/*
+	 * check if "usbd_transfer_setup_sub" set an error
+	 */
+	if (parm->err) {
+		return;
+	}
+	/*
+	 * allocate transfer descriptors
+	 */
+	last_obj = NULL;
+
+	ep_no = xfer->endpointno & UE_ADDR;
+
+	/*
+	 * Check for a valid endpoint profile in USB device mode:
+	 */
+	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
+		const struct usb_hw_ep_profile *pf;
+
+		musbotg_get_hw_ep_profile(parm->udev, &pf, ep_no);
+
+		if (pf == NULL) {
+			/* should not happen */
+			parm->err = USB_ERR_INVAL;
+			return;
+		}
+	}
+
+	/* align data */
+	parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
+
+	for (n = 0; n != ntd; n++) {
+
+		struct musbotg_td *td;
+
+		if (parm->buf) {
+
+			td = USB_ADD_BYTES(parm->buf, parm->size[0]);
+
+			/* init TD */
+			td->max_frame_size = xfer->max_frame_size;
+			td->reg_max_packet = xfer->max_packet_size |
+			    ((xfer->max_packet_count - 1) << 11);
+			td->ep_no = ep_no;
+			td->obj_next = last_obj;
+
+			last_obj = td;
+		}
+		parm->size[0] += sizeof(*td);
+	}
+
+	xfer->td_start[0] = last_obj;
+}
+
+static void
+musbotg_xfer_unsetup(struct usb_xfer *xfer)
+{
+	return;
+}
+
+static void
+musbotg_get_dma_delay(struct usb_device *udev, uint32_t *pus)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus);
+
+	if (sc->sc_mode == MUSB2_HOST_MODE)
+	        *pus = 2000;                   /* microseconds */
+	else
+		*pus = 0;
+}
+
+static void
+musbotg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
+    struct usb_endpoint *ep)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus);
+
+	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
+	    ep, udev->address,
+	    edesc->bEndpointAddress, udev->flags.usb_mode,
+	    sc->sc_rt_addr);
+
+	if (udev->device_index != sc->sc_rt_addr) {
+		switch (edesc->bmAttributes & UE_XFERTYPE) {
+		case UE_CONTROL:
+			ep->methods = &musbotg_device_ctrl_methods;
+			break;
+		case UE_INTERRUPT:
+			ep->methods = &musbotg_device_intr_methods;
+			break;
+		case UE_ISOCHRONOUS:
+			ep->methods = &musbotg_device_isoc_methods;
+			break;
+		case UE_BULK:
+			ep->methods = &musbotg_device_bulk_methods;
+			break;
+		default:
+			/* do nothing */
+			break;
+		}
+	}
+}
+
+static void
+musbotg_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
+{
+	struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus);
+
+	switch (state) {
+	case USB_HW_POWER_SUSPEND:
+		musbotg_uninit(sc);
+		break;
+	case USB_HW_POWER_SHUTDOWN:
+		musbotg_uninit(sc);
+		break;
+	case USB_HW_POWER_RESUME:
+		musbotg_init(sc);
+		break;
+	default:
+		break;
+	}
+}
+
+static const struct usb_bus_methods musbotg_bus_methods =
+{
+	.endpoint_init = &musbotg_ep_init,
+	.get_dma_delay = &musbotg_get_dma_delay,
+	.xfer_setup = &musbotg_xfer_setup,
+	.xfer_unsetup = &musbotg_xfer_unsetup,
+	.get_hw_ep_profile = &musbotg_get_hw_ep_profile,
+	.xfer_stall = &musbotg_xfer_stall,
+	.set_stall = &musbotg_set_stall,
+	.clear_stall = &musbotg_clear_stall,
+	.roothub_exec = &musbotg_roothub_exec,
+	.xfer_poll = &musbotg_do_poll,
+	.set_hw_power_sleep = &musbotg_set_hw_power_sleep,
+};
diff --git a/freebsd/sys/dev/usb/controller/musb_otg.h b/freebsd/sys/dev/usb/controller/musb_otg.h
new file mode 100644
index 0000000..7fe19a7
--- /dev/null
+++ b/freebsd/sys/dev/usb/controller/musb_otg.h
@@ -0,0 +1,435 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * This header file defines the registers of the Mentor Graphics USB OnTheGo
+ * Inventra chip.
+ */
+
+#ifndef _MUSB2_OTG_H_
+#define	_MUSB2_OTG_H_
+
+#define	MUSB2_MAX_DEVICES USB_MAX_DEVICES
+
+/* Common registers */
+
+#define	MUSB2_REG_FADDR 0x0000		/* function address register */
+#define	MUSB2_MASK_FADDR 0x7F
+
+#define	MUSB2_REG_POWER 0x0001		/* power register */
+#define	MUSB2_MASK_SUSPM_ENA 0x01
+#define	MUSB2_MASK_SUSPMODE 0x02
+#define	MUSB2_MASK_RESUME 0x04
+#define	MUSB2_MASK_RESET 0x08
+#define	MUSB2_MASK_HSMODE 0x10
+#define	MUSB2_MASK_HSENAB 0x20
+#define	MUSB2_MASK_SOFTC 0x40
+#define	MUSB2_MASK_ISOUPD 0x80
+
+/* Endpoint interrupt handling */
+
+#define	MUSB2_REG_INTTX 0x0002		/* transmit interrupt register */
+#define	MUSB2_REG_INTRX 0x0004		/* receive interrupt register */
+#define	MUSB2_REG_INTTXE 0x0006		/* transmit interrupt enable register */
+#define	MUSB2_REG_INTRXE 0x0008		/* receive interrupt enable register */
+#define	MUSB2_MASK_EPINT(epn) (1 << (epn))	/* epn = [0..15] */
+
+/* Common interrupt handling */
+
+#define	MUSB2_REG_INTUSB 0x000A		/* USB interrupt register */
+#define	MUSB2_MASK_ISUSP 0x01
+#define	MUSB2_MASK_IRESUME 0x02
+#define	MUSB2_MASK_IRESET 0x04
+#define	MUSB2_MASK_IBABBLE 0x04
+#define	MUSB2_MASK_ISOF 0x08
+#define	MUSB2_MASK_ICONN 0x10
+#define	MUSB2_MASK_IDISC 0x20
+#define	MUSB2_MASK_ISESSRQ 0x40
+#define	MUSB2_MASK_IVBUSERR 0x80
+
+#define	MUSB2_REG_INTUSBE 0x000B	/* USB interrupt enable register */
+#define	MUSB2_REG_FRAME 0x000C		/* USB frame register */
+#define	MUSB2_MASK_FRAME 0x3FF		/* 0..1023 */
+
+#define	MUSB2_REG_EPINDEX 0x000E	/* endpoint index register */
+#define	MUSB2_MASK_EPINDEX 0x0F
+
+#define	MUSB2_REG_TESTMODE 0x000F	/* test mode register */
+#define	MUSB2_MASK_TSE0_NAK 0x01
+#define	MUSB2_MASK_TJ 0x02
+#define	MUSB2_MASK_TK 0x04
+#define	MUSB2_MASK_TPACKET 0x08
+#define	MUSB2_MASK_TFORCE_HS 0x10
+#define	MUSB2_MASK_TFORCE_LS 0x20
+#define	MUSB2_MASK_TFIFO_ACC 0x40
+#define	MUSB2_MASK_TFORCE_HC 0x80
+
+#define	MUSB2_REG_INDEXED_CSR 0x0010	/* EP control status register offset */
+
+#define	MUSB2_REG_TXMAXP (0x0000 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_REG_RXMAXP (0x0004 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_PKTSIZE 0x03FF	/* in bytes, should be even */
+#define	MUSB2_MASK_PKTMULT 0xFC00	/* HS packet multiplier: 0..2 */
+
+#define	MUSB2_REG_TXCSRL (0x0002 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_CSRL_TXPKTRDY 0x01
+#define	MUSB2_MASK_CSRL_TXFIFONEMPTY 0x02
+#define	MUSB2_MASK_CSRL_TXUNDERRUN 0x04	/* Device Mode */
+#define	MUSB2_MASK_CSRL_TXERROR 0x04	/* Host Mode */
+#define	MUSB2_MASK_CSRL_TXFFLUSH 0x08
+#define	MUSB2_MASK_CSRL_TXSENDSTALL 0x10/* Device Mode */
+#define	MUSB2_MASK_CSRL_TXSETUPPKT 0x10	/* Host Mode */
+#define	MUSB2_MASK_CSRL_TXSENTSTALL 0x20/* Device Mode */
+#define	MUSB2_MASK_CSRL_TXSTALLED 0x20	/* Host Mode */
+#define	MUSB2_MASK_CSRL_TXDT_CLR 0x40
+#define	MUSB2_MASK_CSRL_TXINCOMP 0x80 /* Device mode */
+#define	MUSB2_MASK_CSRL_TXNAKTO 0x80 /* Host mode */
+
+/* Device Side Mode */
+#define	MUSB2_MASK_CSR0L_RXPKTRDY 0x01
+#define	MUSB2_MASK_CSR0L_TXPKTRDY 0x02
+#define	MUSB2_MASK_CSR0L_SENTSTALL 0x04
+#define	MUSB2_MASK_CSR0L_DATAEND 0x08
+#define	MUSB2_MASK_CSR0L_SETUPEND 0x10
+#define	MUSB2_MASK_CSR0L_SENDSTALL 0x20
+#define	MUSB2_MASK_CSR0L_RXPKTRDY_CLR 0x40
+#define	MUSB2_MASK_CSR0L_SETUPEND_CLR 0x80
+
+/* Host Side Mode */
+#define	MUSB2_MASK_CSR0L_TXFIFONEMPTY 0x02
+#define	MUSB2_MASK_CSR0L_RXSTALL 0x04
+#define	MUSB2_MASK_CSR0L_SETUPPKT 0x08
+#define	MUSB2_MASK_CSR0L_ERROR 0x10
+#define	MUSB2_MASK_CSR0L_REQPKT 0x20
+#define	MUSB2_MASK_CSR0L_STATUSPKT 0x40
+#define	MUSB2_MASK_CSR0L_NAKTIMO 0x80
+
+#define	MUSB2_REG_TXCSRH (0x0003 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_CSRH_TXDT_VAL 0x01	/* Host Mode */
+#define	MUSB2_MASK_CSRH_TXDT_WREN 0x02	/* Host Mode */
+#define	MUSB2_MASK_CSRH_TXDMAREQMODE 0x04
+#define	MUSB2_MASK_CSRH_TXDT_SWITCH 0x08
+#define	MUSB2_MASK_CSRH_TXDMAREQENA 0x10
+#define	MUSB2_MASK_CSRH_RXMODE 0x00
+#define	MUSB2_MASK_CSRH_TXMODE 0x20
+#define	MUSB2_MASK_CSRH_TXISO 0x40	/* Device Mode */
+#define	MUSB2_MASK_CSRH_TXAUTOSET 0x80
+
+#define	MUSB2_MASK_CSR0H_FFLUSH 0x01	/* Device Side flush FIFO */
+#define	MUSB2_MASK_CSR0H_DT 0x02	/* Host Side data toggle */
+#define	MUSB2_MASK_CSR0H_DT_WREN 0x04	/* Host Side */
+#define	MUSB2_MASK_CSR0H_PING_DIS 0x08	/* Host Side */
+
+#define	MUSB2_REG_RXCSRL (0x0006 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_CSRL_RXPKTRDY 0x01
+#define	MUSB2_MASK_CSRL_RXFIFOFULL 0x02
+#define	MUSB2_MASK_CSRL_RXOVERRUN 0x04 /* Device Mode */
+#define	MUSB2_MASK_CSRL_RXERROR 0x04 /* Host Mode */
+#define	MUSB2_MASK_CSRL_RXDATAERR 0x08 /* Device Mode */
+#define	MUSB2_MASK_CSRL_RXNAKTO 0x08 /* Host Mode */
+#define	MUSB2_MASK_CSRL_RXFFLUSH 0x10
+#define	MUSB2_MASK_CSRL_RXSENDSTALL 0x20/* Device Mode */
+#define	MUSB2_MASK_CSRL_RXREQPKT 0x20	/* Host Mode */
+#define	MUSB2_MASK_CSRL_RXSENTSTALL 0x40/* Device Mode */
+#define	MUSB2_MASK_CSRL_RXSTALL 0x40	/* Host Mode */
+#define	MUSB2_MASK_CSRL_RXDT_CLR 0x80
+
+#define	MUSB2_REG_RXCSRH (0x0007 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_CSRH_RXINCOMP 0x01
+#define	MUSB2_MASK_CSRH_RXDT_VAL 0x02	/* Host Mode */
+#define	MUSB2_MASK_CSRH_RXDT_WREN 0x04	/* Host Mode */
+#define	MUSB2_MASK_CSRH_RXDMAREQMODE 0x08
+#define	MUSB2_MASK_CSRH_RXNYET 0x10
+#define	MUSB2_MASK_CSRH_RXDMAREQENA 0x20
+#define	MUSB2_MASK_CSRH_RXISO 0x40	/* Device Mode */
+#define	MUSB2_MASK_CSRH_RXAUTOREQ 0x40	/* Host Mode */
+#define	MUSB2_MASK_CSRH_RXAUTOCLEAR 0x80
+
+#define	MUSB2_REG_RXCOUNT (0x0008 + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_RXCOUNT 0xFFFF
+
+#define	MUSB2_REG_TXTI (0x000A + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_REG_RXTI (0x000C + MUSB2_REG_INDEXED_CSR)
+
+/* Host Mode */
+#define	MUSB2_MASK_TI_SPEED 0xC0
+#define	MUSB2_MASK_TI_SPEED_LO 0xC0
+#define	MUSB2_MASK_TI_SPEED_FS 0x80
+#define	MUSB2_MASK_TI_SPEED_HS 0x40
+#define	MUSB2_MASK_TI_PROTO_CTRL 0x00
+#define	MUSB2_MASK_TI_PROTO_ISOC 0x10
+#define	MUSB2_MASK_TI_PROTO_BULK 0x20
+#define	MUSB2_MASK_TI_PROTO_INTR 0x30
+#define	MUSB2_MASK_TI_EP_NUM 0x0F
+
+#define	MUSB2_REG_TXNAKLIMIT (0x000B /* EPN=0 */ + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_REG_RXNAKLIMIT (0x000D /* EPN=0 */ + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_NAKLIMIT 0xFF
+
+#define	MUSB2_REG_FSIZE (0x000F + MUSB2_REG_INDEXED_CSR)
+#define	MUSB2_MASK_RX_FSIZE 0xF0	/* 3..13, 2**n bytes */
+#define	MUSB2_MASK_TX_FSIZE 0x0F	/* 3..13, 2**n bytes */
+
+#define	MUSB2_REG_EPFIFO(n) (0x0020 + (4*(n)))
+
+#define	MUSB2_REG_CONFDATA (0x000F + MUSB2_REG_INDEXED_CSR)	/* EPN=0 */
+#define	MUSB2_MASK_CD_UTMI_DW 0x01
+#define	MUSB2_MASK_CD_SOFTCONE 0x02
+#define	MUSB2_MASK_CD_DYNFIFOSZ 0x04
+#define	MUSB2_MASK_CD_HBTXE 0x08
+#define	MUSB2_MASK_CD_HBRXE 0x10
+#define	MUSB2_MASK_CD_BIGEND 0x20
+#define	MUSB2_MASK_CD_MPTXE 0x40
+#define	MUSB2_MASK_CD_MPRXE 0x80
+
+/* Various registers */
+
+#define	MUSB2_REG_DEVCTL 0x0060
+#define	MUSB2_MASK_SESS 0x01
+#define	MUSB2_MASK_HOSTREQ 0x02
+#define	MUSB2_MASK_HOSTMD 0x04
+#define	MUSB2_MASK_VBUS0 0x08
+#define	MUSB2_MASK_VBUS1 0x10
+#define	MUSB2_MASK_LSDEV 0x20
+#define	MUSB2_MASK_FSDEV 0x40
+#define	MUSB2_MASK_BDEV 0x80
+
+#define	MUSB2_REG_MISC 0x0061
+#define	MUSB2_MASK_RXEDMA 0x01
+#define	MUSB2_MASK_TXEDMA 0x02
+
+#define	MUSB2_REG_TXFIFOSZ 0x0062
+#define	MUSB2_REG_RXFIFOSZ 0x0063
+#define	MUSB2_MASK_FIFODB 0x10		/* set if double buffering, r/w */
+#define	MUSB2_MASK_FIFOSZ 0x0F
+#define	MUSB2_VAL_FIFOSZ_8 0
+#define	MUSB2_VAL_FIFOSZ_16 1
+#define	MUSB2_VAL_FIFOSZ_32 2
+#define	MUSB2_VAL_FIFOSZ_64 3
+#define	MUSB2_VAL_FIFOSZ_128 4
+#define	MUSB2_VAL_FIFOSZ_256 5
+#define	MUSB2_VAL_FIFOSZ_512 6
+#define	MUSB2_VAL_FIFOSZ_1024 7
+#define	MUSB2_VAL_FIFOSZ_2048 8
+#define	MUSB2_VAL_FIFOSZ_4096 9
+
+#define	MUSB2_REG_TXFIFOADD 0x0064
+#define	MUSB2_REG_RXFIFOADD 0x0066
+#define	MUSB2_MASK_FIFOADD 0xFFF	/* unit is 8-bytes */
+
+#define	MUSB2_REG_VSTATUS 0x0068
+#define	MUSB2_REG_VCONTROL 0x0068
+#define	MUSB2_REG_HWVERS 0x006C
+#define	MUSB2_REG_ULPI_BASE 0x0070
+
+#define	MUSB2_REG_EPINFO 0x0078
+#define	MUSB2_MASK_NRXEP 0xF0
+#define	MUSB2_MASK_NTXEP 0x0F
+
+#define	MUSB2_REG_RAMINFO 0x0079
+#define	MUSB2_REG_LINKINFO 0x007A
+
+#define	MUSB2_REG_VPLEN 0x007B
+#define	MUSB2_MASK_VPLEN 0xFF
+
+#define	MUSB2_REG_HS_EOF1 0x007C
+#define	MUSB2_REG_FS_EOF1 0x007D
+#define	MUSB2_REG_LS_EOF1 0x007E
+#define	MUSB2_REG_SOFT_RST 0x007F
+#define	MUSB2_MASK_SRST 0x01
+#define	MUSB2_MASK_SRSTX 0x02
+
+#define	MUSB2_REG_RQPKTCOUNT(n) (0x0300 + (4*(n))
+#define	MUSB2_REG_RXDBDIS 0x0340
+#define	MUSB2_REG_TXDBDIS 0x0342
+#define	MUSB2_MASK_DB(n) (1 << (n))	/* disable double buffer, n = [0..15] */
+
+#define	MUSB2_REG_CHIRPTO 0x0344
+#define	MUSB2_REG_HSRESUM 0x0346
+
+/* Host Mode only registers */
+
+#define	MUSB2_REG_TXFADDR(n) (0x0080 + (8*(n)))
+#define	MUSB2_REG_TXHADDR(n) (0x0082 + (8*(n)))
+#define	MUSB2_REG_TXHUBPORT(n) (0x0083 + (8*(n)))
+#define	MUSB2_REG_RXFADDR(n) (0x0084 + (8*(n)))
+#define	MUSB2_REG_RXHADDR(n) (0x0086 + (8*(n)))
+#define	MUSB2_REG_RXHUBPORT(n) (0x0087 + (8*(n)))
+
+#define	MUSB2_EP_MAX 16			/* maximum number of endpoints */
+
+#define	MUSB2_DEVICE_MODE	0
+#define	MUSB2_HOST_MODE		1
+
+#define	MUSB2_READ_2(sc, reg) \
+  bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
+
+#define	MUSB2_WRITE_2(sc, reg, data)	\
+  bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)
+
+#define	MUSB2_READ_1(sc, reg) \
+  bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
+
+#define	MUSB2_WRITE_1(sc, reg, data)	\
+  bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)
+
+struct musbotg_td;
+struct musbotg_softc;
+
+typedef uint8_t (musbotg_cmd_t)(struct musbotg_td *td);
+
+struct musbotg_dma {
+	struct musbotg_softc *sc;
+	uint32_t dma_chan;
+	uint8_t	busy:1;
+	uint8_t	complete:1;
+	uint8_t	error:1;
+};
+
+struct musbotg_td {
+	struct musbotg_td *obj_next;
+	musbotg_cmd_t *func;
+	struct usb_page_cache *pc;
+	uint32_t offset;
+	uint32_t remainder;
+	uint16_t max_frame_size;	/* packet_size * mult */
+	uint16_t reg_max_packet;
+	uint8_t	ep_no;
+	uint8_t	transfer_type;
+	uint8_t	error:1;
+	uint8_t	alt_next:1;
+	uint8_t	short_pkt:1;
+	uint8_t	support_multi_buffer:1;
+	uint8_t	did_stall:1;
+	uint8_t	dma_enabled:1;
+	uint8_t	transaction_started:1;
+	uint8_t dev_addr;
+	uint8_t toggle;
+	int8_t channel;
+	uint8_t haddr;
+	uint8_t hport;
+};
+
+struct musbotg_std_temp {
+	musbotg_cmd_t *func;
+	struct usb_page_cache *pc;
+	struct musbotg_td *td;
+	struct musbotg_td *td_next;
+	uint32_t len;
+	uint32_t offset;
+	uint16_t max_frame_size;
+	uint8_t	short_pkt;
+	/*
+         * short_pkt = 0: transfer should be short terminated
+         * short_pkt = 1: transfer should not be short terminated
+         */
+	uint8_t	setup_alt_next;
+	uint8_t did_stall;
+	uint8_t dev_addr;
+	int8_t channel;
+	uint8_t haddr;
+	uint8_t hport;
+	uint8_t	transfer_type;
+};
+
+struct musbotg_config_desc {
+	struct usb_config_descriptor confd;
+	struct usb_interface_descriptor ifcd;
+	struct usb_endpoint_descriptor endpd;
+} __packed;
+
+union musbotg_hub_temp {
+	uWord	wValue;
+	struct usb_port_status ps;
+};
+
+struct musbotg_flags {
+	uint8_t	change_connect:1;
+	uint8_t	change_suspend:1;
+	uint8_t	change_reset:1;
+	uint8_t	change_over_current:1;
+	uint8_t	change_enabled:1;
+	uint8_t	status_suspend:1;	/* set if suspended */
+	uint8_t	status_vbus:1;		/* set if present */
+	uint8_t	status_bus_reset:1;	/* set if reset complete */
+	uint8_t	status_high_speed:1;	/* set if High Speed is selected */
+	uint8_t	remote_wakeup:1;
+	uint8_t	self_powered:1;
+	uint8_t	clocks_off:1;
+	uint8_t	port_powered:1;
+	uint8_t	port_enabled:1;
+	uint8_t	port_over_current:1;
+	uint8_t	d_pulled_up:1;
+};
+
+struct musbotg_softc {
+	struct usb_bus sc_bus;
+	union musbotg_hub_temp sc_hub_temp;
+	struct usb_hw_ep_profile sc_hw_ep_profile[MUSB2_EP_MAX];
+
+	struct usb_device *sc_devices[MUSB2_MAX_DEVICES];
+	struct resource *sc_io_res;
+	struct resource *sc_irq_res;
+	void   *sc_intr_hdl;
+	bus_size_t sc_io_size;
+	bus_space_tag_t sc_io_tag;
+	bus_space_handle_t sc_io_hdl;
+
+	void    (*sc_clocks_on) (void *arg);
+	void    (*sc_clocks_off) (void *arg);
+	void    (*sc_ep_int_set) (struct musbotg_softc *sc, int ep, int on);
+	void   *sc_clocks_arg;
+
+	uint32_t sc_bounce_buf[(1024 * 3) / 4];	/* bounce buffer */
+
+	uint8_t	sc_ep_max;		/* maximum number of RX and TX
+					 * endpoints supported */
+	uint8_t	sc_rt_addr;		/* root HUB address */
+	uint8_t	sc_dv_addr;		/* device address */
+	uint8_t	sc_conf;		/* root HUB config */
+	uint8_t	sc_ep0_busy;		/* set if ep0 is busy */
+	uint8_t	sc_ep0_cmd;		/* pending commands */
+	uint8_t	sc_conf_data;		/* copy of hardware register */
+
+	uint8_t	sc_hub_idata[1];
+	uint16_t sc_channel_mask;	/* 16 endpoints */
+
+	struct musbotg_flags sc_flags;
+	uint8_t	sc_id;
+	uint8_t	sc_mode;
+	void *sc_platform_data;
+};
+
+/* prototypes */
+
+usb_error_t musbotg_init(struct musbotg_softc *sc);
+void	musbotg_uninit(struct musbotg_softc *sc);
+void	musbotg_interrupt(struct musbotg_softc *sc,
+    uint16_t rxstat, uint16_t txstat, uint8_t stat);
+void	musbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on);
+void	musbotg_connect_interrupt(struct musbotg_softc *sc);
+
+#endif					/* _MUSB2_OTG_H_ */
diff --git a/freebsd/sys/sys/timeet.h b/freebsd/sys/sys/timeet.h
new file mode 100644
index 0000000..3d50e51
--- /dev/null
+++ b/freebsd/sys/sys/timeet.h
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 2010-2013 Alexander Motin <mav at FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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 ``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 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 _SYS_TIMEEC_H_
+#define	_SYS_TIMEEC_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+/*
+ * `struct eventtimer' is the interface between the hardware which implements
+ * a event timer and the MI code which uses this to receive time events.
+ */
+
+struct eventtimer;
+typedef int et_start_t(struct eventtimer *et,
+    sbintime_t first, sbintime_t period);
+typedef int et_stop_t(struct eventtimer *et);
+typedef void et_event_cb_t(struct eventtimer *et, void *arg);
+typedef int et_deregister_cb_t(struct eventtimer *et, void *arg);
+
+struct eventtimer {
+	SLIST_ENTRY(eventtimer)	et_all;
+		/* Pointer to the next event timer. */
+	const char		*et_name;
+		/* Name of the event timer. */
+	int			et_flags;
+		/* Set of capabilities flags: */
+#define ET_FLAGS_PERIODIC	1
+#define ET_FLAGS_ONESHOT	2
+#define ET_FLAGS_PERCPU		4
+#define ET_FLAGS_C3STOP		8
+#define ET_FLAGS_POW2DIV	16
+	int			et_quality;
+		/*
+		 * Used to determine if this timecounter is better than
+		 * another timecounter. Higher means better.
+		 */
+	int			et_active;
+	u_int64_t		et_frequency;
+		/* Base frequency in Hz. */
+	sbintime_t		et_min_period;
+	sbintime_t		et_max_period;
+	et_start_t		*et_start;
+	et_stop_t		*et_stop;
+	et_event_cb_t		*et_event_cb;
+	et_deregister_cb_t	*et_deregister_cb;
+	void 			*et_arg;
+	void			*et_priv;
+	struct sysctl_oid	*et_sysctl;
+		/* Pointer to the event timer's private parts. */
+};
+
+extern struct mtx	et_eventtimers_mtx;
+#define	ET_LOCK()	mtx_lock(&et_eventtimers_mtx)
+#define	ET_UNLOCK()	mtx_unlock(&et_eventtimers_mtx)
+
+/* Driver API */
+int	et_register(struct eventtimer *et);
+int	et_deregister(struct eventtimer *et);
+void	et_change_frequency(struct eventtimer *et, uint64_t newfreq);
+/* Consumer API  */
+struct eventtimer *et_find(const char *name, int check, int want);
+int	et_init(struct eventtimer *et, et_event_cb_t *event,
+    et_deregister_cb_t *deregister, void *arg);
+int	et_start(struct eventtimer *et, sbintime_t first, sbintime_t period);
+int	et_stop(struct eventtimer *et);
+int	et_ban(struct eventtimer *et);
+int	et_free(struct eventtimer *et);
+
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_kern_eventtimer);
+#endif
+#endif /* !_SYS_TIMETC_H_ */
+
diff --git a/freebsd/sys/sys/watchdog.h b/freebsd/sys/sys/watchdog.h
new file mode 100644
index 0000000..92c47de
--- /dev/null
+++ b/freebsd/sys/sys/watchdog.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2003 Poul-Henning Kamp
+ * Copyright (c) 2013 iXsystems.com,
+ *                    author: Alfred Perlstein <alfred at freebsd.org>
+ *
+ * All rights reserved.
+ *
+ * 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 _SYS_WATCHDOG_H
+#define	_SYS_WATCHDOG_H
+
+#include <sys/ioccom.h>
+
+#define	_PATH_WATCHDOG	"fido"
+
+#define WDIOCPATPAT	_IOW('W', 42, u_int)	/* pat the watchdog */
+#define WDIOC_SETTIMEOUT    _IOW('W', 43, int)	/* set/reset the timer */
+#define WDIOC_GETTIMEOUT    _IOR('W', 44, int)	/* get total timeout */
+#define WDIOC_GETTIMELEFT   _IOR('W', 45, int)	/* get time left */
+#define WDIOC_GETPRETIMEOUT _IOR('W', 46, int)	/* get the pre-timeout */
+#define WDIOC_SETPRETIMEOUT _IOW('W', 47, int)	/* set the pre-timeout */
+/* set the action when a pre-timeout occurs see: WD_SOFT_* */
+#define WDIOC_SETPRETIMEOUTACT _IOW('W', 48, int)
+
+/* use software watchdog instead of hardware */
+#define WDIOC_SETSOFT	_IOW('W', 49, int)
+#define WDIOC_SETSOFTTIMEOUTACT	_IOW('W', 50, int)
+
+#define WD_ACTIVE	0x8000000
+	/* 
+	 * Watchdog reset, timeout set to value in WD_INTERVAL field.
+	 * The kernel will arm the watchdog and unless the userland
+	 * program calls WDIOCPATPAT again before the timer expires
+	 * the system will reinitialize.
+	 */
+
+#define WD_PASSIVE	0x0400000
+	/*
+	 * Set the watchdog in passive mode.
+	 * The kernel will chose an appropriate timeout duration and
+	 * periodically reset the timer provided everything looks all
+	 * right to the kernel.
+ 	 */
+
+#define WD_LASTVAL	0x0200000
+	/*
+	 * Use the already last used timeout value.
+	 * The kernel will use as timeout the last valid timeout provided.
+ 	 */
+
+#define WD_INTERVAL	0x00000ff
+	/*
+	 * Mask for duration bits.
+	 * The watchdog will have a nominal patience of 2^N * nanoseconds.
+	 * Example:  N == 30 gives a patience of 2^30 nanoseconds ~= 1 second.
+	 * NB: Expect variance in the +/- 10-20% range.
+	 */
+
+/* Handy macros for humans not used to power of two nanoseconds */
+#define WD_TO_NEVER	0
+#define WD_TO_1MS	20
+#define WD_TO_125MS	27
+#define WD_TO_250MS	28
+#define WD_TO_500MS	29
+#define WD_TO_1SEC	30
+#define WD_TO_2SEC	31
+#define WD_TO_4SEC	32
+#define WD_TO_8SEC	33
+#define WD_TO_16SEC	34
+#define WD_TO_32SEC	35
+#define WD_TO_64SEC	36
+#define WD_TO_128SEC	37
+
+/* action on pre-timeout trigger */
+#define	WD_SOFT_PANIC	0x01	/* panic */
+#define	WD_SOFT_DDB	0x02	/* enter debugger */
+#define	WD_SOFT_LOG	0x04	/* log(9) */
+#define	WD_SOFT_PRINTF	0x08	/* printf(9) */
+#define WD_SOFT_MASK	0x0f	/* all of the above */
+
+#ifdef _KERNEL
+
+#include <sys/eventhandler.h>
+
+typedef void (*watchdog_fn)(void *, u_int, int *);
+
+EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
+
+u_int	wdog_kern_last_timeout(void);
+int	wdog_kern_pat(u_int utim);
+#endif
+
+#endif /* _SYS_WATCHDOG_H */



More information about the vc mailing list