summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/arm
diff options
context:
space:
mode:
authorSichen Zhao <1473996754@qq.com>2017-07-13 10:24:04 +0800
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-07-13 07:30:02 +0200
commitbd3c01a1260ced850ee348809712be1f2db24772 (patch)
treea0e615dbc5eb71b3f8d43f77db523498af105e77 /freebsd/sys/arm
parenttermios: Interrupt server API changes (diff)
downloadrtems-libbsd-bd3c01a1260ced850ee348809712be1f2db24772.tar.bz2
Import am335x usb driver file from FreeBSD.
Diffstat (limited to 'freebsd/sys/arm')
-rw-r--r--freebsd/sys/arm/ti/am335x/am335x_musb.c421
-rw-r--r--freebsd/sys/arm/ti/am335x/am335x_prcm.c857
-rw-r--r--freebsd/sys/arm/ti/am335x/am335x_scm.h49
-rw-r--r--freebsd/sys/arm/ti/am335x/am335x_usbss.c226
-rw-r--r--freebsd/sys/arm/ti/ti_cpuid.h83
-rw-r--r--freebsd/sys/arm/ti/ti_prcm.c357
-rw-r--r--freebsd/sys/arm/ti/ti_prcm.h207
-rw-r--r--freebsd/sys/arm/ti/ti_scm.c176
-rw-r--r--freebsd/sys/arm/ti/ti_scm.h56
-rw-r--r--freebsd/sys/arm/ti/tivar.h41
10 files changed, 2473 insertions, 0 deletions
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 00000000..52d799ce
--- /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@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 00000000..1d10f7f2
--- /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@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 00000000..6116be06
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/am335x_scm.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@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 00000000..8369171d
--- /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@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 00000000..715f080e
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_cpuid.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2011
+ * Ben Gray <ben.r.gray@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 00000000..b4dd03fb
--- /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@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 00000000..61b69607
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_prcm.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2010
+ * Ben Gray <ben.r.gray@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 00000000..2e54262e
--- /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@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 00000000..1342ddc6
--- /dev/null
+++ b/freebsd/sys/arm/ti/ti_scm.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010
+ * Ben Gray <ben.r.gray@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 00000000..248ad901
--- /dev/null
+++ b/freebsd/sys/arm/ti/tivar.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010
+ * Ben Gray <ben.r.gray@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_ */