summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2012-08-15 06:31:32 +0000
committergonzo <gonzo@FreeBSD.org>2012-08-15 06:31:32 +0000
commit8ebd91847c4e2a98c80b6f8c8dd615f37ba49ce8 (patch)
treefcda3fb41be4ba1e10ed13e32009c67ce545b238
parent2b1b507d3c867484eac653ff9dfa6bd4d0159426 (diff)
downloadFreeBSD-src-8ebd91847c4e2a98c80b6f8c8dd615f37ba49ce8.zip
FreeBSD-src-8ebd91847c4e2a98c80b6f8c8dd615f37ba49ce8.tar.gz
Merging of projects/armv6, part 10
- Support for Texas Instruments SoCs: - AM335x - OMAP4 - Kernel configs, DTS for Beaglebone and Pandaboard Submitted by: Ben Gray, Damjan Marion
-rw-r--r--sys/arm/conf/BEAGLEBONE126
-rw-r--r--sys/arm/conf/PANDABOARD144
-rw-r--r--sys/arm/conf/PANDABOARD.hints61
-rw-r--r--sys/arm/ti/aintc.c179
-rw-r--r--sys/arm/ti/am335x/am335x_dmtimer.c385
-rw-r--r--sys/arm/ti/am335x/am335x_pmic.c176
-rw-r--r--sys/arm/ti/am335x/am335x_prcm.c568
-rw-r--r--sys/arm/ti/am335x/am335x_reg.h41
-rw-r--r--sys/arm/ti/am335x/am335x_scm_padconf.c373
-rw-r--r--sys/arm/ti/am335x/files.am335x9
-rw-r--r--sys/arm/ti/am335x/files.beaglebone3
-rw-r--r--sys/arm/ti/am335x/std.am335x21
-rw-r--r--sys/arm/ti/am335x/std.beaglebone4
-rw-r--r--sys/arm/ti/bus_space.c113
-rw-r--r--sys/arm/ti/common.c98
-rw-r--r--sys/arm/ti/cpsw/if_cpsw.c1251
-rw-r--r--sys/arm/ti/cpsw/if_cpswreg.h107
-rw-r--r--sys/arm/ti/cpsw/if_cpswvar.h124
-rw-r--r--sys/arm/ti/files.ti25
-rw-r--r--sys/arm/ti/omap3/omap3_reg.h780
-rw-r--r--sys/arm/ti/omap4/files.omap419
-rw-r--r--sys/arm/ti/omap4/omap4_l2cache.c39
-rw-r--r--sys/arm/ti/omap4/omap4_mp.c87
-rw-r--r--sys/arm/ti/omap4/omap4_prcm_clks.c1418
-rw-r--r--sys/arm/ti/omap4/omap4_reg.h586
-rw-r--r--sys/arm/ti/omap4/omap4_scm_padconf.c405
-rw-r--r--sys/arm/ti/omap4/omap4_smc.h52
-rw-r--r--sys/arm/ti/omap4/omap4var.h91
-rw-r--r--sys/arm/ti/omap4/pandaboard/files.pandaboard3
-rw-r--r--sys/arm/ti/omap4/pandaboard/pandaboard.c210
-rw-r--r--sys/arm/ti/omap4/pandaboard/std.pandaboard4
-rw-r--r--sys/arm/ti/omap4/std.omap421
-rw-r--r--sys/arm/ti/std.ti5
-rw-r--r--sys/arm/ti/ti_cpuid.c285
-rw-r--r--sys/arm/ti/ti_cpuid.h77
-rw-r--r--sys/arm/ti/ti_edma3.c424
-rw-r--r--sys/arm/ti/ti_edma3.h81
-rw-r--r--sys/arm/ti/ti_gpio.c802
-rw-r--r--sys/arm/ti/ti_i2c.c1179
-rw-r--r--sys/arm/ti/ti_i2c.h115
-rw-r--r--sys/arm/ti/ti_machdep.c618
-rw-r--r--sys/arm/ti/ti_mmchs.c1839
-rw-r--r--sys/arm/ti/ti_mmchs.h170
-rw-r--r--sys/arm/ti/ti_prcm.c309
-rw-r--r--sys/arm/ti/ti_prcm.h185
-rw-r--r--sys/arm/ti/ti_scm.c493
-rw-r--r--sys/arm/ti/ti_scm.h84
-rw-r--r--sys/arm/ti/ti_sdma.c1246
-rw-r--r--sys/arm/ti/ti_sdma.h111
-rw-r--r--sys/arm/ti/ti_sdmareg.h133
-rw-r--r--sys/arm/ti/ti_smc.S37
-rw-r--r--sys/arm/ti/ti_smc.h33
-rw-r--r--sys/arm/ti/tivar.h41
-rw-r--r--sys/arm/ti/twl/twl.c464
-rw-r--r--sys/arm/ti/twl/twl.h39
-rw-r--r--sys/arm/ti/twl/twl_clks.c675
-rw-r--r--sys/arm/ti/twl/twl_clks.h38
-rw-r--r--sys/arm/ti/twl/twl_vreg.c1053
-rw-r--r--sys/arm/ti/twl/twl_vreg.h36
-rw-r--r--sys/arm/ti/usb/omap_ehci.c1024
-rw-r--r--sys/arm/ti/usb/omap_usb.h264
-rw-r--r--sys/boot/fdt/dts/beaglebone.dts197
-rw-r--r--sys/boot/fdt/dts/pandaboard.dts184
-rw-r--r--sys/dev/mmc/mmc.c1
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/cpsw/Makefile8
66 files changed, 19775 insertions, 0 deletions
diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE
new file mode 100644
index 0000000..1a6426d
--- /dev/null
+++ b/sys/arm/conf/BEAGLEBONE
@@ -0,0 +1,126 @@
+# BEAGLEBONE -- Custom configuration for the BeagleBone ARM development
+# platform, check out http://www.beagleboard.org/bone
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident BEAGLEBONE
+
+include "../ti/am335x/std.beaglebone"
+
+makeoptions MODULES_OVERRIDE=""
+makeoptions WITHOUT_MODULES="ahc"
+
+options HZ=100
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options INET6 #IPv6 communications protocols
+options FFS #Berkeley Fast Filesystem
+options SOFTUPDATES #Enable FFS soft updates support
+options UFS_ACL #Support for access control lists
+options UFS_DIRHASH #Improve performance on big directories
+options MSDOSFS #MSDOS Filesystem
+options CD9660 #ISO 9660 Filesystem
+options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+options PREEMPTION
+
+# Debugging
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+options BREAK_TO_DEBUGGER
+#options VERBOSE_SYSINIT #Enable verbose sysinit messages
+options KDB
+options DDB #Enable the kernel debugger
+options INVARIANTS #Enable calls of extra sanity checking
+options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+options WITNESS #Enable checks to detect deadlocks and cycles
+options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
+#options DIAGNOSTIC
+
+# NFS support
+#options NFSCL
+#options NFSSERVER #Network Filesystem Server
+#options NFSCLIENT #Network Filesystem Client
+
+# Uncomment this for NFS root
+#options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+#options BOOTP_NFSROOT
+#options BOOTP_COMPAT
+#options BOOTP
+#options BOOTP_NFSV3
+#options BOOTP_WIRED_TO=cpsw0
+
+
+# MMC/SD/SDIO card slot support
+device mmc # mmc/sd bus
+device mmcsd # mmc/sd flash cards
+
+# Boot device is 2nd slice on MMC/SD card
+options ROOTDEVNAME=\"ufs:mmcsd0s2\"
+
+# Console and misc
+device uart
+device uart_ns8250
+device pty
+device snp
+device md
+device random # Entropy device
+
+# I2C support
+device iicbus
+device iic
+device ti_i2c
+device am335x_pmic # AM335x Power Management IC (TPC65217)
+
+# GPIO
+device gpio
+
+# USB support
+device usb
+options USB_DEBUG
+#options USB_REQ_DEBUG
+#options USB_VERBOSE
+device musb
+device umass
+device scbus # SCSI bus (required for SCSI)
+device da # Direct Access (disks)
+
+# Ethernet
+device loop
+device ether
+device mii
+device smscphy
+device cpsw
+device bpf
+
+# USB ethernet support, requires miibus
+device miibus
+device axe # ASIX Electronics USB Ethernet
+
+# Flattened Device Tree
+options FDT
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=beaglebone.dts
+
diff --git a/sys/arm/conf/PANDABOARD b/sys/arm/conf/PANDABOARD
new file mode 100644
index 0000000..7a4f474
--- /dev/null
+++ b/sys/arm/conf/PANDABOARD
@@ -0,0 +1,144 @@
+# PANDABOARD -- Custom configuration for the PandaBoard ARM development
+# platform, check out www.pandaboard.org
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident PANDABOARD
+
+
+
+# This probably wants to move somewhere else. Maybe we can create a basic
+# OMAP4340 config, then make a PANDABOARD config that includes the basic one,
+# adds the start addresses and custom devices plus pulls in this hints file.
+
+hints "PANDABOARD.hints"
+
+include "../ti/omap4/pandaboard/std.pandaboard"
+
+#To statically compile in device wiring instead of /boot/device.hints
+makeoptions MODULES_OVERRIDE=""
+makeoptions WITHOUT_MODULES="ahc"
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+options HZ=100
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+#options INET6 #IPv6 communications protocols
+options FFS #Berkeley Fast Filesystem
+options SOFTUPDATES #Enable FFS soft updates support
+options UFS_ACL #Support for access control lists
+options UFS_DIRHASH #Improve performance on big directories
+options NFSCLIENT #Network Filesystem Client
+device snp
+#options NFSCL
+#options NFSSERVER #Network Filesystem Server
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+options BREAK_TO_DEBUGGER
+options BOOTP_NFSROOT
+options BOOTP_COMPAT
+options BOOTP
+options BOOTP_NFSV3
+options BOOTP_WIRED_TO=ue0
+options MSDOSFS #MSDOS Filesystem
+#options CD9660 #ISO 9660 Filesystem
+#options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+
+options PREEMPTION
+
+# MMC/SD/SDIO Card slot support
+device mmc # mmc/sd bus
+device mmcsd # mmc/sd flash cards
+
+# I2C support
+device iicbus
+device iic
+device ti_i2c
+
+device loop
+device ether
+device mii
+device smc
+device smcphy
+device uart
+device uart_ns8250
+
+device gpio
+
+device pty
+
+device pl310 # PL310 L2 cache controller
+# Debugging for use in -current
+#options VERBOSE_SYSINIT #Enable verbose sysinit messages
+options KDB
+options DDB #Enable the kernel debugger
+#options INVARIANTS #Enable calls of extra sanity checking
+#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+#options WITNESS #Enable checks to detect deadlocks and cycles
+#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
+#options DIAGNOSTIC
+
+device md
+
+# The following enables MFS as root, this seems similar to an initramfs or initrd
+# as used in Linux.
+# options MD_ROOT
+# options MD_ROOT_SIZE=7560
+
+device random # Entropy device
+
+# USB support
+device usb
+options USB_DEBUG
+#options USB_REQ_DEBUG
+#options USB_VERBOSE
+device ohci
+device ehci
+device umass
+device scbus # SCSI bus (required for SCSI)
+device da # Direct Access (disks)
+
+
+# USB Ethernet support, requires miibus
+device miibus
+# device axe # ASIX Electronics USB Ethernet
+device smsc # SMSC LAN95xx USB Ethernet
+
+
+# OMAP-specific devices
+device ti_sdma
+device twl
+device twl_vreg
+device twl_clks
+
+# Flattened Device Tree
+options FDT
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=pandaboard.dts
+
+# device vfp # vfp/neon
+# options ARM_VFP_SUPPORT # vfp/neon
diff --git a/sys/arm/conf/PANDABOARD.hints b/sys/arm/conf/PANDABOARD.hints
new file mode 100644
index 0000000..1aef3af
--- /dev/null
+++ b/sys/arm/conf/PANDABOARD.hints
@@ -0,0 +1,61 @@
+# $FreeBSD$
+
+# USB ECHI
+
+#
+# TI OMAP Power Management and System Companion Device sitting on the I2C bus
+# hint.tps65950.0.at="iicbus0"
+# hint.tps65950.0.addr=0xd0
+
+
+#
+# Defines the GPIO pin used to detect the Write Protect stat of the MMC/SD card.
+#hint.omap_mmc.0.wp_gpio="23"
+
+
+#
+# If 'phy_reset" is set, then the accompaning PHY is reset using one of the
+# GPIO pins. If the reset GPIO pin is not -1 then the pin will be toggled when
+# the USB driver is loaded.
+hint.ehci.0.phy_reset="0"
+
+#
+# Sets the PHY mode for the individual ports, the following values are allowed
+# - EHCI_HCD_OMAP3_MODE_UNKNOWN 0
+# - EHCI_HCD_OMAP3_MODE_PHY 1
+# - EHCI_HCD_OMAP3_MODE_TLL 2
+hint.ehci.0.phy_mode_0="1"
+hint.ehci.0.phy_mode_1="0"
+hint.ehci.0.phy_mode_2="0"
+
+#
+# If specified the value indicates a pin that is toggled as a heart-beat. The
+# heart beat pusle is triggered every 500ms using the system tick timer.
+hint.omap_clk.0.heartbeat_gpio="150"
+
+
+#
+# Padconf (pinmux) settings - typically this would be set by the boot-loader
+# but can be overridden here. These hints are applied to the H/W when the
+# SCM module is initialised.
+#
+# The format is:
+# hint.omap_scm.0.padconf.<padname>=<muxmode:options>
+#
+# Where the options can be one of the following:
+# output, input, input_pullup, input_pulldown
+#
+
+# Setup the pin settings for the HS USB Host (PHY mode)
+hint.omap4.0.padconf.ag19="usbb1_ulpiphy_stp:output"
+hint.omap4.0.padconf.ae18="usbb1_ulpiphy_clk:input_pulldown"
+hint.omap4.0.padconf.af19="usbb1_ulpiphy_dir:input_pulldown"
+hint.omap4.0.padconf.ae19="usbb1_ulpiphy_nxt:input_pulldown"
+hint.omap4.0.padconf.af18="usbb1_ulpiphy_dat0:input_pulldown"
+hint.omap4.0.padconf.ag18="usbb1_ulpiphy_dat1:input_pulldown"
+hint.omap4.0.padconf.ae17="usbb1_ulpiphy_dat2:input_pulldown"
+hint.omap4.0.padconf.af17="usbb1_ulpiphy_dat3:input_pulldown"
+hint.omap4.0.padconf.ah17="usbb1_ulpiphy_dat4:input_pulldown"
+hint.omap4.0.padconf.ae16="usbb1_ulpiphy_dat5:input_pulldown"
+hint.omap4.0.padconf.af16="usbb1_ulpiphy_dat6:input_pulldown"
+hint.omap4.0.padconf.ag16="usbb1_ulpiphy_dat7:input_pulldown"
diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c
new file mode 100644
index 0000000..eb66492
--- /dev/null
+++ b/sys/arm/ti/aintc.c
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ * All rights reserved.
+ *
+ * Based on OMAP3 INTC code by Ben Gray
+ *
+ * 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/ktr.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#define INTC_REVISION 0x00
+#define INTC_SYSCONFIG 0x10
+#define INTC_SYSSTATUS 0x14
+#define INTC_SIR_IRQ 0x40
+#define INTC_CONTROL 0x48
+#define INTC_THRESHOLD 0x68
+#define INTC_MIR_CLEAR(x) (0x88 + ((x) * 0x20))
+#define INTC_MIR_SET(x) (0x8C + ((x) * 0x20))
+#define INTC_ISR_SET(x) (0x90 + ((x) * 0x20))
+#define INTC_ISR_CLEAR(x) (0x94 + ((x) * 0x20))
+
+struct ti_aintc_softc {
+ device_t sc_dev;
+ struct resource * aintc_res[3];
+ bus_space_tag_t aintc_bst;
+ bus_space_handle_t aintc_bsh;
+ uint8_t ver;
+};
+
+static struct resource_spec ti_aintc_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+
+static struct ti_aintc_softc *ti_aintc_sc = NULL;
+
+#define aintc_read_4(reg) \
+ bus_space_read_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg)
+#define aintc_write_4(reg, val) \
+ bus_space_write_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg, val)
+
+
+static int
+ti_aintc_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,aintc"))
+ return (ENXIO);
+ device_set_desc(dev, "TI AINTC Interrupt Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ti_aintc_attach(device_t dev)
+{
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+ uint32_t x;
+
+ sc->sc_dev = dev;
+
+ if (ti_aintc_sc)
+ return (ENXIO);
+
+ if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]);
+ sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]);
+
+ ti_aintc_sc = sc;
+
+ x = aintc_read_4(INTC_REVISION);
+ device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF);
+
+ /* SoftReset */
+ aintc_write_4(INTC_SYSCONFIG, 2);
+
+ /* Wait for reset to complete */
+ while(!(aintc_read_4(INTC_SYSSTATUS) & 1));
+
+ /*Set Priority Threshold */
+ aintc_write_4(INTC_THRESHOLD, 0xFF);
+
+ return (0);
+}
+
+static device_method_t ti_aintc_methods[] = {
+ DEVMETHOD(device_probe, ti_aintc_probe),
+ DEVMETHOD(device_attach, ti_aintc_attach),
+ { 0, 0 }
+};
+
+static driver_t ti_aintc_driver = {
+ "aintc",
+ ti_aintc_methods,
+ sizeof(struct ti_aintc_softc),
+};
+
+static devclass_t ti_aintc_devclass;
+
+DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0);
+
+int
+arm_get_next_irq(int last_irq)
+{
+ uint32_t active_irq;
+
+ if (last_irq != -1) {
+ aintc_write_4(INTC_ISR_CLEAR(last_irq >> 5),
+ 1UL << (last_irq & 0x1F));
+ aintc_write_4(INTC_CONTROL,1);
+ }
+
+ /* Get the next active interrupt */
+ active_irq = aintc_read_4(INTC_SIR_IRQ);
+
+ /* Check for spurious interrupt */
+ if ((active_irq & 0xffffff80)) {
+ device_printf(ti_aintc_sc->sc_dev,
+ "Spurious interrupt detected (0x%08x)\n", active_irq);
+ return -1;
+ }
+
+ if (active_irq != last_irq)
+ return active_irq;
+ else
+ return -1;
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+ aintc_write_4(INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F)));
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+ aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
+}
diff --git a/sys/arm/ti/am335x/am335x_dmtimer.c b/sys/arm/ti/am335x/am335x_dmtimer.c
new file mode 100644
index 0000000..c2d0139
--- /dev/null
+++ b/sys/arm/ti/am335x/am335x_dmtimer.c
@@ -0,0 +1,385 @@
+/*-
+ * 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/frame.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/ti/ti_prcm.h>
+
+#define AM335X_NUM_TIMERS 8
+
+#define DMTIMER_TIDR 0x00 /* Identification Register */
+#define DMTIMER_TIOCP_CFG 0x10 /* Timer OCP Configuration Reg */
+#define DMTIMER_IQR_EOI 0x20 /* Timer IRQ End-Of-Interrupt Reg */
+#define DMTIMER_IRQSTATUS_RAW 0x24 /* Timer IRQSTATUS Raw Reg */
+#define DMTIMER_IRQSTATUS 0x28 /* Timer IRQSTATUS Reg */
+#define DMTIMER_IRQENABLE_SET 0x2c /* Timer IRQSTATUS Set Reg */
+#define DMTIMER_IRQENABLE_CLR 0x30 /* Timer IRQSTATUS Clear Reg */
+#define DMTIMER_IRQWAKEEN 0x34 /* Timer IRQ Wakeup Enable Reg */
+#define DMTIMER_TCLR 0x38 /* Timer Control Register */
+#define DMTIMER_TCRR 0x3C /* Timer Counter Register */
+#define DMTIMER_TLDR 0x40 /* Timer Load Reg */
+#define DMTIMER_TTGR 0x44 /* Timer Trigger Reg */
+#define DMTIMER_TWPS 0x48 /* Timer Write Posted Status Reg */
+#define DMTIMER_TMAR 0x4C /* Timer Match Reg */
+#define DMTIMER_TCAR1 0x50 /* Timer Capture Reg */
+#define DMTIMER_TSICR 0x54 /* Timer Synchr. Interface Control Reg */
+#define DMTIMER_TCAR2 0x48 /* Timer Capture Reg */
+
+
+struct am335x_dmtimer_softc {
+ struct resource * tmr_mem_res[AM335X_NUM_TIMERS];
+ struct resource * tmr_irq_res[AM335X_NUM_TIMERS];
+ uint32_t sysclk_freq;
+ struct am335x_dmtimer {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ struct eventtimer et;
+ } t[AM335X_NUM_TIMERS];
+};
+
+static struct resource_spec am335x_dmtimer_mem_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE },
+ { SYS_RES_MEMORY, 4, RF_ACTIVE },
+ { SYS_RES_MEMORY, 5, RF_ACTIVE },
+ { SYS_RES_MEMORY, 6, RF_ACTIVE },
+ { SYS_RES_MEMORY, 7, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+static struct resource_spec am335x_dmtimer_irq_spec[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { SYS_RES_IRQ, 3, RF_ACTIVE },
+ { SYS_RES_IRQ, 4, RF_ACTIVE },
+ { SYS_RES_IRQ, 5, RF_ACTIVE },
+ { SYS_RES_IRQ, 6, RF_ACTIVE },
+ { SYS_RES_IRQ, 7, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+static struct am335x_dmtimer *am335x_dmtimer_tc_tmr = NULL;
+
+/* Read/Write macros for Timer used as timecounter */
+#define am335x_dmtimer_tc_read_4(reg) \
+ bus_space_read_4(am335x_dmtimer_tc_tmr->bst, \
+ am335x_dmtimer_tc_tmr->bsh, reg)
+
+#define am335x_dmtimer_tc_write_4(reg, val) \
+ bus_space_write_4(am335x_dmtimer_tc_tmr->bst, \
+ am335x_dmtimer_tc_tmr->bsh, reg, val)
+
+/* Read/Write macros for Timer used as eventtimer */
+#define am335x_dmtimer_et_read_4(reg) \
+ bus_space_read_4(tmr->bst, tmr->bsh, reg)
+
+#define am335x_dmtimer_et_write_4(reg, val) \
+ bus_space_write_4(tmr->bst, tmr->bsh, reg, val)
+
+static unsigned am335x_dmtimer_tc_get_timecount(struct timecounter *);
+
+static struct timecounter am335x_dmtimer_tc = {
+ .tc_name = "AM335x Timecouter",
+ .tc_get_timecount = am335x_dmtimer_tc_get_timecount,
+ .tc_poll_pps = NULL,
+ .tc_counter_mask = ~0u,
+ .tc_frequency = 0,
+ .tc_quality = 1000,
+};
+
+static unsigned
+am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
+{
+ return am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+}
+
+static int
+am335x_dmtimer_start(struct eventtimer *et, struct bintime *first,
+ struct bintime *period)
+{
+ struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
+ uint32_t load, count;
+ uint32_t tclr = 0;
+
+ if (period != NULL) {
+ load = (et->et_frequency * (period->frac >> 32)) >> 32;
+ if (period->sec > 0)
+ load += et->et_frequency * period->sec;
+ tclr |= 2; /* autoreload bit */
+ panic("periodic timer not implemented\n");
+ } else {
+ load = 0;
+ }
+
+ if (first != NULL) {
+ count = (tmr->et.et_frequency * (first->frac >> 32)) >> 32;
+ if (first->sec != 0)
+ count += tmr->et.et_frequency * first->sec;
+ } else {
+ count = load;
+ }
+
+ /* Reset Timer */
+ am335x_dmtimer_et_write_4(DMTIMER_TSICR, 2);
+
+ /* Wait for reset to complete */
+ while (am335x_dmtimer_et_read_4(DMTIMER_TIOCP_CFG) & 1);
+
+ /* set load value */
+ am335x_dmtimer_et_write_4(DMTIMER_TLDR, 0xFFFFFFFE - load);
+
+ /* set counter value */
+ am335x_dmtimer_et_write_4(DMTIMER_TCRR, 0xFFFFFFFE - count);
+
+ /* enable overflow interrupt */
+ am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_SET, 2);
+
+ /* start timer(ST) */
+ tclr |= 1;
+ am335x_dmtimer_et_write_4(DMTIMER_TCLR, tclr);
+
+ return (0);
+}
+
+static int
+am335x_dmtimer_stop(struct eventtimer *et)
+{
+ struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
+
+ /* Disable all interrupts */
+ am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_CLR, 7);
+
+ /* Stop Timer */
+ am335x_dmtimer_et_write_4(DMTIMER_TCLR, 0);
+
+ return (0);
+}
+
+static int
+am335x_dmtimer_intr(void *arg)
+{
+ struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)arg;
+
+ /* Ack interrupt */
+ am335x_dmtimer_et_write_4(DMTIMER_IRQSTATUS, 7);
+ if (tmr->et.et_active)
+ tmr->et.et_event_cb(&tmr->et, tmr->et.et_arg);
+
+ return (FILTER_HANDLED);
+}
+
+static int
+am335x_dmtimer_probe(device_t dev)
+{
+ struct am335x_dmtimer_softc *sc;
+ sc = (struct am335x_dmtimer_softc *)device_get_softc(dev);
+
+ if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) {
+ device_set_desc(dev, "AM335x DMTimer");
+ return(BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+am335x_dmtimer_attach(device_t dev)
+{
+ struct am335x_dmtimer_softc *sc = device_get_softc(dev);
+ void *ihl;
+ int err;
+ int i;
+
+ if (am335x_dmtimer_tc_tmr != NULL)
+ return (EINVAL);
+
+ /* Get the base clock frequency */
+ err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq);
+ if (err) {
+ device_printf(dev, "Error: could not get sysclk frequency\n");
+ return (ENXIO);
+ }
+
+ /* Request the memory resources */
+ err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec,
+ sc->tmr_mem_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate mem resources\n");
+ return (ENXIO);
+ }
+
+ /* Request the IRQ resources */
+ err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec,
+ sc->tmr_irq_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate irq resources\n");
+ return (ENXIO);
+ }
+
+ for(i=0;i<AM335X_NUM_TIMERS;i++) {
+ sc->t[i].bst = rman_get_bustag(sc->tmr_mem_res[i]);
+ sc->t[i].bsh = rman_get_bushandle(sc->tmr_mem_res[i]);
+ }
+
+ /* Configure DMTimer2 and DMTimer3 source and enable them */
+ err = ti_prcm_clk_set_source(DMTIMER2_CLK, SYSCLK_CLK);
+ err |= ti_prcm_clk_enable(DMTIMER2_CLK);
+ err |= ti_prcm_clk_set_source(DMTIMER3_CLK, SYSCLK_CLK);
+ err |= ti_prcm_clk_enable(DMTIMER3_CLK);
+ if (err) {
+ device_printf(dev, "Error: could not setup timer clock\n");
+ return (ENXIO);
+ }
+
+ /* Take DMTimer2 for TC */
+ am335x_dmtimer_tc_tmr = &sc->t[2];
+
+ /* Reset Timer */
+ am335x_dmtimer_tc_write_4(DMTIMER_TSICR, 2);
+
+ /* Wait for reset to complete */
+ while (am335x_dmtimer_tc_read_4(DMTIMER_TIOCP_CFG) & 1);
+
+ /* set load value */
+ am335x_dmtimer_tc_write_4(DMTIMER_TLDR, 0);
+
+ /* set counter value */
+ am335x_dmtimer_tc_write_4(DMTIMER_TCRR, 0);
+
+ /* Set Timer autoreload(AR) and start timer(ST) */
+ am335x_dmtimer_tc_write_4(DMTIMER_TCLR, 3);
+
+ am335x_dmtimer_tc.tc_frequency = sc->sysclk_freq;
+ tc_init(&am335x_dmtimer_tc);
+
+ /* Register DMTimer3 as ET */
+
+ /* Setup and enable the timer */
+ if (bus_setup_intr(dev, sc->tmr_irq_res[3], INTR_TYPE_CLK,
+ am335x_dmtimer_intr, NULL, &sc->t[3], &ihl) != 0) {
+ bus_release_resources(dev, am335x_dmtimer_irq_spec,
+ sc->tmr_irq_res);
+ device_printf(dev, "Unable to setup the clock irq handler.\n");
+ return (ENXIO);
+ }
+
+ sc->t[3].et.et_name = "AM335x Eventtimer0";
+ sc->t[3].et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
+ sc->t[3].et.et_quality = 1000;
+ sc->t[3].et.et_frequency = sc->sysclk_freq;
+ sc->t[3].et.et_min_period.sec = 0;
+ sc->t[3].et.et_min_period.frac =
+ ((0x00000002LLU << 32) / sc->t[3].et.et_frequency) << 32;
+ sc->t[3].et.et_max_period.sec = 0xfffffff0U / sc->t[3].et.et_frequency;
+ sc->t[3].et.et_max_period.frac =
+ ((0xfffffffeLLU << 32) / sc->t[3].et.et_frequency) << 32;
+ sc->t[3].et.et_start = am335x_dmtimer_start;
+ sc->t[3].et.et_stop = am335x_dmtimer_stop;
+ sc->t[3].et.et_priv = &sc->t[3];
+ et_register(&sc->t[3].et);
+
+ return (0);
+}
+
+static device_method_t am335x_dmtimer_methods[] = {
+ DEVMETHOD(device_probe, am335x_dmtimer_probe),
+ DEVMETHOD(device_attach, am335x_dmtimer_attach),
+ { 0, 0 }
+};
+
+static driver_t am335x_dmtimer_driver = {
+ "am335x_dmtimer",
+ am335x_dmtimer_methods,
+ sizeof(struct am335x_dmtimer_softc),
+};
+
+static devclass_t am335x_dmtimer_devclass;
+
+DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0);
+MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1);
+
+void
+cpu_initclocks(void)
+{
+ cpu_initclocks_bsp();
+}
+
+void
+DELAY(int usec)
+{
+ int32_t counts;
+ uint32_t first, last;
+
+ if (am335x_dmtimer_tc_tmr == NULL) {
+ for (; usec > 0; usec--)
+ for (counts = 200; counts > 0; counts--)
+ /* Prevent gcc from optimizing out the loop */
+ cpufunc_nullop();
+ return;
+ }
+
+ /* Get the number of times to count */
+ counts = usec * ((am335x_dmtimer_tc.tc_frequency / 1000000) + 1);;
+
+ first = am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+
+ while (counts > 0) {
+ last = am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+ if (last>first) {
+ counts -= (int32_t)(last - first);
+ } else {
+ counts -= (int32_t)((0xFFFFFFFF - first) + last);
+ }
+ first = last;
+ }
+}
+
diff --git a/sys/arm/ti/am335x/am335x_pmic.c b/sys/arm/ti/am335x/am335x_pmic.c
new file mode 100644
index 0000000..eab400a
--- /dev/null
+++ b/sys/arm/ti/am335x/am335x_pmic.c
@@ -0,0 +1,176 @@
+/*-
+ * 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$");
+/*
+* TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus
+*/
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/clock.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "iicbus_if.h"
+
+#define TPS65217A 0x7
+#define TPS65217B 0xF
+
+/* TPS65217 Reisters */
+#define TPS65217_CHIPID_REG 0x00
+#define TPS65217_STATUS_REG 0x0A
+
+#define MAX_IIC_DATA_SIZE 2
+
+
+struct am335x_pmic_softc {
+ device_t sc_dev;
+ uint32_t sc_addr;
+ struct intr_config_hook enum_hook;
+};
+
+static int
+am335x_pmic_read(device_t dev, uint8_t addr, uint8_t *data, uint8_t size)
+{
+ struct am335x_pmic_softc *sc = device_get_softc(dev);
+ struct iic_msg msg[] = {
+ { sc->sc_addr, IIC_M_WR, 1, &addr },
+ { sc->sc_addr, IIC_M_RD, size, data },
+ };
+ return (iicbus_transfer(dev, msg, 2));
+}
+
+#ifdef notyet
+static int
+am335x_pmic_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size)
+{
+ uint8_t buffer[MAX_IIC_DATA_SIZE + 1];
+ struct am335x_pmic_softc *sc = device_get_softc(dev);
+ struct iic_msg msg[] = {
+ { sc->sc_addr, IIC_M_WR, size + 1, buffer },
+ };
+
+ if (size > MAX_IIC_DATA_SIZE)
+ return (ENOMEM);
+
+ buffer[0] = address;
+ memcpy(buffer + 1, data, size);
+
+ return (iicbus_transfer(dev, msg, 1));
+}
+#endif
+
+static int
+am335x_pmic_probe(device_t dev)
+{
+ struct am335x_pmic_softc *sc;
+
+ if (!ofw_bus_is_compatible(dev, "ti,am335x-pmic"))
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ sc->sc_addr = iicbus_get_addr(dev);
+
+ device_set_desc(dev, "TI TPS65217 Power Management IC");
+
+ return (0);
+}
+
+static void
+am335x_pmic_start(void *xdev)
+{
+ struct am335x_pmic_softc *sc;
+ device_t dev = (device_t)xdev;
+ uint8_t reg;
+ char name[20];
+ char pwr[4][11] = {"Unknown", "USB", "AC", "USB and AC"};
+
+ sc = device_get_softc(dev);
+
+ am335x_pmic_read(dev, TPS65217_CHIPID_REG, &reg, 1);
+ switch (reg>>4) {
+ case TPS65217A:
+ sprintf(name, "TPS65217A ver 1.%u", reg & 0xF);
+ break;
+ case TPS65217B:
+ sprintf(name, "TPS65217B ver 1.%u", reg & 0xF);
+ break;
+ default:
+ sprintf(name, "Unknown PMIC");
+ }
+
+ am335x_pmic_read(dev, TPS65217_STATUS_REG, &reg, 1);
+ device_printf(dev, "%s powered by %s\n", name, pwr[(reg>>2)&0x03]);
+
+ config_intrhook_disestablish(&sc->enum_hook);
+}
+
+static int
+am335x_pmic_attach(device_t dev)
+{
+ struct am335x_pmic_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ sc->enum_hook.ich_func = am335x_pmic_start;
+ sc->enum_hook.ich_arg = dev;
+
+ if (config_intrhook_establish(&sc->enum_hook) != 0)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static device_method_t am335x_pmic_methods[] = {
+ DEVMETHOD(device_probe, am335x_pmic_probe),
+ DEVMETHOD(device_attach, am335x_pmic_attach),
+ {0, 0},
+};
+
+static driver_t am335x_pmic_driver = {
+ "am335x_pmic",
+ am335x_pmic_methods,
+ sizeof(struct am335x_pmic_softc),
+};
+
+static devclass_t am335x_pmic_devclass;
+
+DRIVER_MODULE(am335x_pmic, iicbus, am335x_pmic_driver, am335x_pmic_devclass, 0, 0);
+MODULE_VERSION(am335x_pmic, 1);
+MODULE_DEPEND(am335x_pmic, iicbus, 1, 1, 1);
diff --git a/sys/arm/ti/am335x/am335x_prcm.c b/sys/arm/ti/am335x/am335x_prcm.c
new file mode 100644
index 0000000..abc37e6
--- /dev/null
+++ b/sys/arm/ti/am335x/am335x_prcm.c
@@ -0,0 +1,568 @@
+/*-
+ * 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/frame.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.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_USB0_CLKCTRL (CM_PER + 0x01C)
+#define CM_PER_TPTC0_CLKCTRL (CM_PER + 0x024)
+#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_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_L3_INSTR_CLKCTRL (CM_PER + 0x0DC)
+#define CM_PER_L3_CLKCTRL (CM_PER + 0x0E0)
+#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_OCPWP_L3_CLKSTCTRL (CM_PER + 0x12C)
+#define CM_PER_OCPWP_CLKCTRL (CM_PER + 0x130)
+#define CM_PER_CPSW_CLKSTCTRL (CM_PER + 0x144)
+
+#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_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C)
+#define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8)
+
+#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 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_generic_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
+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 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);
+
+#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 \
+ }
+
+#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 \
+ }
+
+#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 \
+ }
+
+struct ti_clock_dev ti_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,
+ },
+ /* 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,
+ },
+ /* 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,
+ },
+
+ /* 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,
+ },
+
+ /* DMTimer */
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK),
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK),
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK),
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK),
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK),
+ AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK),
+
+ /* GPIO */
+ AM335X_GPIO_CLOCK_DEV(GPIO0_CLK),
+ AM335X_GPIO_CLOCK_DEV(GPIO1_CLK),
+ AM335X_GPIO_CLOCK_DEV(GPIO2_CLK),
+ AM335X_GPIO_CLOCK_DEV(GPIO3_CLK),
+
+ /* I2C */
+ AM335X_GENERIC_CLOCK_DEV(I2C0_CLK),
+ AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
+ AM335X_GENERIC_CLOCK_DEV(I2C2_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(MMC0_CLK),
+ AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
+ AM335X_MMCHS_CLOCK_DEV(MMC2_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[] = {
+
+ /* DMTimer modules */
+ _CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
+ _CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
+ _CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
+ _CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
+ _CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
+ _CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
+
+ /* GPIO modules */
+ _CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
+ _CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0),
+ _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0),
+ _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0),
+
+ /* I2C modules */
+ _CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
+ _CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
+ _CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_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*/
+ _CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0),
+ _CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0),
+ _CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_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_is_compatible(dev, "am335x,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;
+
+ am335x_clk_get_sysclk_freq(NULL, &sysclk);
+ am335x_clk_get_arm_fclk_freq(NULL, &fclk);
+ device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
+ sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
+
+ 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_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_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_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_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 */
+ /* control_status reg (0x40) */
+ if (ti_scm_reg_read_4(0x40, &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);
+}
+
+static int
+am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+ uint32_t reg;
+ uint32_t sysclk;
+#define DPLL_BYP_CLKSEL(reg) ((reg>>23) & 1)
+#define DPLL_DIV(reg) ((reg & 0x7f)+1)
+#define DPLL_MULT(reg) ((reg>>8) & 0x7FF)
+
+ 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 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);
+}
+
+
diff --git a/sys/arm/ti/am335x/am335x_reg.h b/sys/arm/ti/am335x/am335x_reg.h
new file mode 100644
index 0000000..ca617e3
--- /dev/null
+++ b/sys/arm/ti/am335x/am335x_reg.h
@@ -0,0 +1,41 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AM335X_REG_H_
+#define _AM335X_REG_H_
+
+#define AM335X_L4_WKUP_BASE 0x44C00000
+#define AM335X_L4_WKUP_SIZE 0x400000
+
+#define AM335X_CONTROL_BASE AM335X_L4_WKUP_BASE + 0x210000
+#define AM335X_CONTROL_SIZE 0x2000
+#define AM335X_CONTROL_DEVICE_ID 0x0600
+#define AM335X_CONTROL_DEV_FEATURE 0x0604
+
+#endif
+
diff --git a/sys/arm/ti/am335x/am335x_scm_padconf.c b/sys/arm/ti/am335x/am335x_scm_padconf.c
new file mode 100644
index 0000000..4ed63a3
--- /dev/null
+++ b/sys/arm/ti/am335x/am335x_scm_padconf.c
@@ -0,0 +1,373 @@
+/*-
+ * 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/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <sys/gpio.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+
+#define _PIN(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \
+ { .reg_off = r, \
+ .gpio_pin = gp, \
+ .gpio_mode = gm, \
+ .ballname = b, \
+ .muxmodes[0] = m0, \
+ .muxmodes[1] = m1, \
+ .muxmodes[2] = m2, \
+ .muxmodes[3] = m3, \
+ .muxmodes[4] = m4, \
+ .muxmodes[5] = m5, \
+ .muxmodes[6] = m6, \
+ .muxmodes[7] = m7, \
+ }
+
+#define SLEWCTRL (0x01 << 6) /* faster(0) or slower(1) slew rate. */
+#define RXACTIVE (0x01 << 5) /* Input enable value for the Pad */
+#define PULLTYPESEL (0x01 << 4) /* Pad pullup/pulldown type selection */
+#define PULLUDEN (0x01 << 3) /* Pullup/pulldown disabled */
+
+#define PADCONF_OUTPUT (0)
+#define PADCONF_OUTPUT_PULLUP (PULLTYPESEL)
+#define PADCONF_INPUT (RXACTIVE | PULLUDEN)
+#define PADCONF_INPUT_PULLUP (RXACTIVE | PULLTYPESEL)
+#define PADCONF_INPUT_PULLDOWN (RXACTIVE)
+#define PADCONF_INPUT_PULLUP_SLOW (PADCONF_INPUT_PULLUP | SLEWCTRL)
+
+const struct ti_scm_padstate ti_padstate_devmap[] = {
+ {"output", PADCONF_OUTPUT },
+ {"output_pullup", PADCONF_OUTPUT_PULLUP },
+ {"input", PADCONF_INPUT },
+ {"input_pulldown", PADCONF_INPUT_PULLDOWN },
+ {"input_pullup", PADCONF_INPUT_PULLUP },
+ {"i2c", PADCONF_INPUT_PULLUP_SLOW },
+ { .state = NULL }
+};
+
+const struct ti_scm_padconf ti_padconf_devmap[] = {
+ _PIN(0x800, "GPMC_AD0", 32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"),
+ _PIN(0x804, "GPMC_AD1", 33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"),
+ _PIN(0x808, "GPMC_AD2", 34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"),
+ _PIN(0x80C, "GPMC_AD3", 35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"),
+ _PIN(0x810, "GPMC_AD4", 36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"),
+ _PIN(0x814, "GPMC_AD5", 37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"),
+ _PIN(0x818, "GPMC_AD6", 38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"),
+ _PIN(0x81C, "GPMC_AD7", 39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"),
+#if 0 /* Incomplete Entries - fill with data from table 2-7 in datasheet */
+ _PIN(0x820, "gpmc_ad8", 0, 0, "gpmc_ad8", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x824, "gpmc_ad9", 0, 0, "gpmc_ad9", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x828, "gpmc_ad10", 0, 0, "gpmc_ad10", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x82C, "gpmc_ad11", 0, 0, "gpmc_ad11", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x830, "gpmc_ad12", 0, 0, "gpmc_ad12", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x834, "gpmc_ad13", 0, 0, "gpmc_ad13", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x838, "gpmc_ad14", 0, 0, "gpmc_ad14", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x83C, "gpmc_ad15", 0, 0, "gpmc_ad15", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x840, "gpmc_a0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x844, "gpmc_a1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x848, "gpmc_a2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x84C, "gpmc_a3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x850, "gpmc_a4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0x854, "GPMC_A5", 53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"),
+ _PIN(0x858, "GPMC_A6", 54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"),
+ _PIN(0x85C, "GPMC_A7", 55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"),
+ _PIN(0x860, "GPMC_A8", 56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"),
+#if 0
+ _PIN(0x864, "gpmc_a9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x868, "gpmc_a10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x86C, "gpmc_a11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x870, "gpmc_wait0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x874, "gpmc_wpn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x878, "gpmc_be1n", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x87c, "gpmc_csn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x880, "gpmc_csn1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x884, "gpmc_csn2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x888, "gpmc_csn3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x88c, "gpmc_clk", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x890, "gpmc_advn_ale", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x894, "gpmc_oen_ren", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x898, "gpmc_wen", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x89c, "gpmc_be0n_cle", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8a0, "lcd_data0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8a4, "lcd_data1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8a8, "lcd_data2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8ac, "lcd_data3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8b0, "lcd_data4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8b4, "lcd_data5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8b8, "lcd_data6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8bc, "lcd_data7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8c0, "lcd_data8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8c4, "lcd_data9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8c8, "lcd_data10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8cc, "lcd_data11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8d0, "lcd_data12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8d4, "lcd_data13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8d8, "lcd_data14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8dc, "lcd_data15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8e0, "lcd_vsync", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8e4, "lcd_hsync", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8e8, "lcd_pclk", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x8ec, "lcd_ac_bias_en", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0x8f0, "MMC0_DAT3", 90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"),
+ _PIN(0x8f4, "MMC0_DAT2", 91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"),
+ _PIN(0x8f8, "MMC0_DAT1", 92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"),
+ _PIN(0x8fc, "MMC0_DAT0", 93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"),
+ _PIN(0x900, "MMC0_CLK", 94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"),
+ _PIN(0x904, "MMC0_CMD", 95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"),
+ _PIN(0x908, "MII1_COL", 96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"),
+ _PIN(0x90c, "MII1_CRS", 97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"),
+ _PIN(0x910, "MII1_RX_ER", 98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"),
+ _PIN(0x914, "MII1_TX_EN", 99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"),
+ _PIN(0x918, "MII1_RX_DV", 100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"),
+ _PIN(0x91c, "MII1_TXD3", 16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"),
+ _PIN(0x920, "MII1_TXD2", 17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"),
+ _PIN(0x924, "MII1_TXD1", 21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"),
+ _PIN(0x928, "MII1_TXD0", 28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"),
+ _PIN(0x92c, "MII1_TX_CLK", 105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"),
+ _PIN(0x930, "MII1_RX_CLK", 106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"),
+ _PIN(0x934, "MII1_RXD3", 82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"),
+ _PIN(0x938, "MII1_RXD2", 83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"),
+ _PIN(0x93c, "MII1_RXD1", 84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"),
+ _PIN(0x940, "MII1_RXD0", 85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"),
+ _PIN(0x944, "RMII1_REF_CLK", 29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"),
+ _PIN(0x948, "MDIO", 0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"),
+ _PIN(0x94c, "MDC", 1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"),
+#if 0 /* Incomplete Entries - fill with data from table 2-7 in datasheet */
+ _PIN(0x950, "spi0_sclk", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x954, "spi0_d0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0x958, "spi0_d1", 4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"),
+ _PIN(0x95c, "spi0_cs0", 5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"),
+#if 0
+ _PIN(0x960, "spi0_cs1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x964, "ecap0_in_pwm0_out",0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x968, "uart0_ctsn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x96c, "uart0_rtsn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x970, "uart0_rxd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x974, "uart0_txd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0x978, "uart1_ctsn", 12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"),
+ _PIN(0x97c, "uart1_rtsn", 13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n ", "pr1_edc_latch1_in", "gpio0_13"),
+#if 0
+ _PIN(0x980, "uart1_rxd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x984, "uart1_txd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0x988, "I2C0_SDA", 101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"),
+ _PIN(0x98c, "I2C0_SCL", 102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"),
+#if 0
+ _PIN(0x990, "mcasp0_aclkx", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x994, "mcasp0_fsx", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x998, "mcasp0_axr0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x99c, "mcasp0_ahclkr", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9a0, "mcasp0_aclkr", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9a4, "mcasp0_fsr", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9a8, "mcasp0_axr1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9ac, "mcasp0_ahclkx", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9b0, "xdma_event_intr0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9b4, "xdma_event_intr1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9b8, "nresetin_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9bc, "porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9c0, "nnmi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9c4, "osc0_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9c8, "osc0_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9cc, "osc0_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9d0, "tms", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9d4, "tdi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9d8, "tdo", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9dc, "tck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9e0, "ntrst", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9e4, "emu0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9e8, "emu1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9ec, "osc1_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9f0, "osc1_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9f4, "osc1_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9f8, "rtc_porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0x9fc, "pmic_power_en", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa00, "ext_wakeup", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa04, "enz_kaldo_1p8v", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ _PIN(0xa08, "USB0_DM", 0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa0c, "USB0_DP", 0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa10, "USB0_CE", 0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa14, "USB0_ID", 0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa18, "USB0_VBUS", 0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa1c, "USB0_DRVVBUS", 18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"),
+ _PIN(0xa20, "USB1_DM", 0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa24, "USB1_DP", 0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa28, "USB1_CE", 0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa2c, "USB1_ID", 0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa30, "USB1_VBUS", 0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa34, "USB1_DRVVBUS", 109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"),
+#if 0
+ _PIN(0xa38, "ddr_resetn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa3c, "ddr_csn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa40, "ddr_cke", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa44, "ddr_ck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa48, "ddr_nck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa4c, "ddr_casn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa50, "ddr_rasn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa54, "ddr_wen", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa58, "ddr_ba0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa5c, "ddr_ba1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa60, "ddr_ba2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa64, "ddr_a0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa68, "ddr_a1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa6c, "ddr_a2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa70, "ddr_a3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa74, "ddr_a4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa78, "ddr_a5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa7c, "ddr_a6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa80, "ddr_a7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa84, "ddr_a8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa88, "ddr_a9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa8c, "ddr_a10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa90, "ddr_a11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa94, "ddr_a12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa98, "ddr_a13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xa9c, "ddr_a14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaa0, "ddr_a15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaa4, "ddr_odt", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaa8, "ddr_d0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaac, "ddr_d1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xab0, "ddr_d2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xab4, "ddr_d3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xab8, "ddr_d4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xabc, "ddr_d5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xac0, "ddr_d6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xac4, "ddr_d7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xac8, "ddr_d8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xacc, "ddr_d9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xad0, "ddr_d10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xad4, "ddr_d11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xad8, "ddr_d12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xadc, "ddr_d13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xae0, "ddr_d14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xae4, "ddr_d15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xae8, "ddr_dqm0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaec, "ddr_dqm1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaf0, "ddr_dqs0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaf4, "ddr_dqsn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xaf8, "ddr_dqs1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xafc, "ddr_dqsn1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb00, "ddr_vref", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb04, "ddr_vtp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb08, "ddr_strben0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb0c, "ddr_strben1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb2c, "ain0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb28, "ain1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb24, "ain2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb20, "ain3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb1c, "ain4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb18, "ain5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb14, "ain6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb10, "ain7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb30, "vrefp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb34, "vrefn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb38, "avdd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb3c, "avss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb40, "iforce", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb44, "vsense", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PIN(0xb48, "testout", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+ { .ballname = NULL },
+};
+
+const struct ti_scm_device ti_scm_dev = {
+ .padconf_muxmode_mask = 0x7,
+ .padconf_sate_mask = 0x78,
+ .padstate = (struct ti_scm_padstate *) &ti_padstate_devmap,
+ .padconf = (struct ti_scm_padconf *) &ti_padconf_devmap,
+};
+
+int
+ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags)
+{
+ unsigned int state = 0;
+ if (flags & GPIO_PIN_OUTPUT) {
+ if (flags & GPIO_PIN_PULLUP)
+ state = PADCONF_OUTPUT_PULLUP;
+ else
+ state = PADCONF_OUTPUT;
+ } else if (flags & GPIO_PIN_INPUT) {
+ if (flags & GPIO_PIN_PULLUP)
+ state = PADCONF_INPUT_PULLUP;
+ else if (flags & GPIO_PIN_PULLDOWN)
+ state = PADCONF_INPUT_PULLDOWN;
+ else
+ state = PADCONF_INPUT;
+ }
+ return ti_scm_padconf_set_gpiomode(gpio, state);
+}
+
+void
+ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags)
+{
+ unsigned int state;
+ if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0)
+ *flags = 0;
+ else {
+ switch (state) {
+ case PADCONF_OUTPUT:
+ *flags = GPIO_PIN_OUTPUT;
+ break;
+ case PADCONF_OUTPUT_PULLUP:
+ *flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP;
+ break;
+ case PADCONF_INPUT:
+ *flags = GPIO_PIN_INPUT;
+ break;
+ case PADCONF_INPUT_PULLUP:
+ *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+ break;
+ case PADCONF_INPUT_PULLDOWN:
+ *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN;
+ break;
+ default:
+ *flags = 0;
+ break;
+ }
+ }
+}
+
diff --git a/sys/arm/ti/am335x/files.am335x b/sys/arm/ti/am335x/files.am335x
new file mode 100644
index 0000000..e4e7aa1
--- /dev/null
+++ b/sys/arm/ti/am335x/files.am335x
@@ -0,0 +1,9 @@
+#$FreeBSD$
+
+arm/ti/aintc.c standard
+arm/ti/am335x/am335x_prcm.c standard
+arm/ti/am335x/am335x_dmtimer.c standard
+arm/ti/am335x/am335x_scm_padconf.c standard
+arm/ti/ti_edma3.c standard
+arm/ti/ti_mmchs.c optional mmc
+arm/ti/cpsw/if_cpsw.c optional cpsw
diff --git a/sys/arm/ti/am335x/files.beaglebone b/sys/arm/ti/am335x/files.beaglebone
new file mode 100644
index 0000000..ff527ce
--- /dev/null
+++ b/sys/arm/ti/am335x/files.beaglebone
@@ -0,0 +1,3 @@
+#$FreeBSD$
+
+arm/ti/am335x/am335x_pmic.c optional am335x_pmic
diff --git a/sys/arm/ti/am335x/std.am335x b/sys/arm/ti/am335x/std.am335x
new file mode 100644
index 0000000..1801cee
--- /dev/null
+++ b/sys/arm/ti/am335x/std.am335x
@@ -0,0 +1,21 @@
+# AM335x generic configuration
+#$FreeBSD$
+files "../ti/am335x/files.am335x"
+include "../ti/std.ti"
+makeoption ARM_LITTLE_ENDIAN
+
+# Physical memory starts at 0x80000000. We assume images are loaded at
+# 0x80200000, e.g. from u-boot with 'fatload mmc 0 0x80200000 kernel.bin'
+#
+#
+options PHYSADDR=0x80000000
+options KERNPHYSADDR=0x80200000
+makeoptions KERNPHYSADDR=0x80200000
+options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
+makeoptions KERNVIRTADDR=0xc0200000
+
+options STARTUP_PAGETABLE_ADDR=0x80000000
+
+options SOC_TI_AM335X
+
+options ARM_L2_PIPT
diff --git a/sys/arm/ti/am335x/std.beaglebone b/sys/arm/ti/am335x/std.beaglebone
new file mode 100644
index 0000000..299e822
--- /dev/null
+++ b/sys/arm/ti/am335x/std.beaglebone
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+files "../ti/am335x/files.beaglebone"
+include "../ti/am335x/std.am335x"
diff --git a/sys/arm/ti/bus_space.c b/sys/arm/ti/bus_space.c
new file mode 100644
index 0000000..4cce820
--- /dev/null
+++ b/sys/arm/ti/bus_space.c
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (C) 2012 FreeBSD Foundation
+ * 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. Neither the name of MARVELL nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space _base_tag = {
+ /* cookie */
+ .bs_cookie = (void *) 0,
+
+ /* mapping/unmapping */
+ .bs_map = generic_bs_map,
+ .bs_unmap = generic_bs_unmap,
+ .bs_subregion = generic_bs_subregion,
+
+ /* allocation/deallocation */
+ .bs_alloc = generic_bs_alloc,
+ .bs_free = generic_bs_free,
+
+ /* barrier */
+ .bs_barrier = generic_bs_barrier,
+
+ /* read (single) */
+ .bs_r_1 = generic_bs_r_1,
+ .bs_r_2 = generic_armv4_bs_r_2,
+ .bs_r_4 = generic_bs_r_4,
+ .bs_r_8 = NULL,
+
+ /* read multiple */
+ .bs_rm_1 = generic_bs_rm_1,
+ .bs_rm_2 = generic_armv4_bs_rm_2,
+ .bs_rm_4 = generic_bs_rm_4,
+ .bs_rm_8 = NULL,
+
+ /* read region */
+ .bs_rr_1 = generic_bs_rr_1,
+ .bs_rr_2 = generic_armv4_bs_rr_2,
+ .bs_rr_4 = generic_bs_rr_4,
+ .bs_rr_8 = NULL,
+
+ /* write (single) */
+ .bs_w_1 = generic_bs_w_1,
+ .bs_w_2 = generic_armv4_bs_w_2,
+ .bs_w_4 = generic_bs_w_4,
+ .bs_w_8 = NULL,
+
+ /* write multiple */
+ .bs_wm_1 = generic_bs_wm_1,
+ .bs_wm_2 = generic_armv4_bs_wm_2,
+ .bs_wm_4 = generic_bs_wm_4,
+ .bs_wm_8 = NULL,
+
+ /* write region */
+ .bs_wr_1 = generic_bs_wr_1,
+ .bs_wr_2 = generic_armv4_bs_wr_2,
+ .bs_wr_4 = generic_bs_wr_4,
+ .bs_wr_8 = NULL,
+
+ /* set multiple */
+ /* XXX not implemented */
+
+ /* set region */
+ .bs_sr_1 = NULL,
+ .bs_sr_2 = generic_armv4_bs_sr_2,
+ .bs_sr_4 = generic_bs_sr_4,
+ .bs_sr_8 = NULL,
+
+ /* copy */
+ .bs_c_1 = NULL,
+ .bs_c_2 = generic_armv4_bs_c_2,
+ .bs_c_4 = NULL,
+ .bs_c_8 = NULL,
+};
+
+bus_space_tag_t fdtbus_bs_tag = &_base_tag;
diff --git a/sys/arm/ti/common.c b/sys/arm/ti/common.c
new file mode 100644
index 0000000..983e6f8
--- /dev/null
+++ b/sys/arm/ti/common.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ */
+
+#include "opt_global.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/vmparam.h>
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+#ifdef SOC_OMAP4
+static int
+fdt_gic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+ int *pol)
+{
+
+ if (!fdt_is_compatible(node, "arm,gic"))
+ return (ENXIO);
+
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+
+ return (0);
+}
+#endif
+
+#ifdef SOC_TI_AM335X
+static int
+fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+ int *pol)
+{
+
+ if (!fdt_is_compatible(node, "ti,aintc"))
+ return (ENXIO);
+
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+
+ return (0);
+}
+#endif
+
+fdt_pic_decode_t fdt_pic_table[] = {
+#ifdef SOC_OMAP4
+ &fdt_gic_decode_ic,
+#endif
+#ifdef SOC_TI_AM335X
+ &fdt_aintc_decode_ic,
+#endif
+ NULL
+};
diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c
new file mode 100644
index 0000000..6863528
--- /dev/null
+++ b/sys/arm/ti/cpsw/if_cpsw.c
@@ -0,0 +1,1251 @@
+/*-
+ * 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.
+ */
+
+/*
+ * TI 3 Port Switch Ethernet (CPSW) Driver
+ * Found in TI8148, AM335x SoCs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/ethernet.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <sys/sockio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/cpsw/if_cpswreg.h>
+#include <arm/ti/cpsw/if_cpswvar.h>
+
+#include <arm/ti/ti_scm.h>
+
+#include "miibus_if.h"
+
+static int cpsw_probe(device_t dev);
+static int cpsw_attach(device_t dev);
+static int cpsw_detach(device_t dev);
+static int cpsw_shutdown(device_t dev);
+static int cpsw_suspend(device_t dev);
+static int cpsw_resume(device_t dev);
+
+static int cpsw_miibus_readreg(device_t dev, int phy, int reg);
+static int cpsw_miibus_writereg(device_t dev, int phy, int reg, int value);
+
+static int cpsw_ifmedia_upd(struct ifnet *ifp);
+static void cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
+
+static void cpsw_init(void *arg);
+static void cpsw_init_locked(void *arg);
+static void cpsw_start(struct ifnet *ifp);
+static void cpsw_start_locked(struct ifnet *ifp);
+static void cpsw_stop(struct cpsw_softc *sc);
+static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
+static int cpsw_allocate_dma(struct cpsw_softc *sc);
+static int cpsw_free_dma(struct cpsw_softc *sc);
+static int cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next);
+static void cpsw_watchdog(struct cpsw_softc *sc);
+
+static void cpsw_intr_rx_thresh(void *arg);
+static void cpsw_intr_rx(void *arg);
+static void cpsw_intr_rx_locked(void *arg);
+static void cpsw_intr_tx(void *arg);
+static void cpsw_intr_tx_locked(void *arg);
+static void cpsw_intr_misc(void *arg);
+
+static void cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
+static void cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
+static int cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac);
+static int cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac);
+#ifdef CPSW_DEBUG
+static void cpsw_ale_dump_table(struct cpsw_softc *sc);
+#endif
+
+static device_method_t cpsw_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cpsw_probe),
+ DEVMETHOD(device_attach, cpsw_attach),
+ DEVMETHOD(device_detach, cpsw_detach),
+ DEVMETHOD(device_shutdown, cpsw_shutdown),
+ DEVMETHOD(device_suspend, cpsw_suspend),
+ DEVMETHOD(device_resume, cpsw_resume),
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, cpsw_miibus_readreg),
+ DEVMETHOD(miibus_writereg, cpsw_miibus_writereg),
+ { 0, 0 }
+};
+
+static driver_t cpsw_driver = {
+ "cpsw",
+ cpsw_methods,
+ sizeof(struct cpsw_softc),
+};
+
+static devclass_t cpsw_devclass;
+
+
+DRIVER_MODULE(cpsw, simplebus, cpsw_driver, cpsw_devclass, 0, 0);
+DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(cpsw, ether, 1, 1, 1);
+MODULE_DEPEND(cpsw, miibus, 1, 1, 1);
+
+static struct resource_spec res_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
+ { SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE },
+ { -1, 0 }
+};
+
+static struct {
+ driver_intr_t *handler;
+ char * description;
+} cpsw_intrs[CPSW_INTR_COUNT + 1] = {
+ { cpsw_intr_rx_thresh,"CPSW RX threshold interrupt" },
+ { cpsw_intr_rx, "CPSW RX interrupt" },
+ { cpsw_intr_tx, "CPSW TX interrupt" },
+ { cpsw_intr_misc,"CPSW misc interrupt" },
+};
+
+/* Locking macros */
+#define CPSW_TX_LOCK(sc) do { \
+ mtx_assert(&(sc)->rx_lock, MA_NOTOWNED); \
+ mtx_lock(&(sc)->tx_lock); \
+} while (0)
+
+#define CPSW_TX_UNLOCK(sc) mtx_unlock(&(sc)->tx_lock)
+#define CPSW_TX_LOCK_ASSERT(sc) mtx_assert(&(sc)->tx_lock, MA_OWNED)
+
+#define CPSW_RX_LOCK(sc) do { \
+ mtx_assert(&(sc)->tx_lock, MA_NOTOWNED); \
+ mtx_lock(&(sc)->rx_lock); \
+} while (0)
+
+#define CPSW_RX_UNLOCK(sc) mtx_unlock(&(sc)->rx_lock)
+#define CPSW_RX_LOCK_ASSERT(sc) mtx_assert(&(sc)->rx_lock, MA_OWNED)
+
+#define CPSW_GLOBAL_LOCK(sc) do { \
+ if ((mtx_owned(&(sc)->tx_lock) ? 1 : 0) != \
+ (mtx_owned(&(sc)->rx_lock) ? 1 : 0)) { \
+ panic("cpsw deadlock possibility detection!"); \
+ } \
+ mtx_lock(&(sc)->tx_lock); \
+ mtx_lock(&(sc)->rx_lock); \
+} while (0)
+
+#define CPSW_GLOBAL_UNLOCK(sc) do { \
+ CPSW_RX_UNLOCK(sc); \
+ CPSW_TX_UNLOCK(sc); \
+} while (0)
+
+#define CPSW_GLOBAL_LOCK_ASSERT(sc) do { \
+ CPSW_TX_LOCK_ASSERT(sc); \
+ CPSW_RX_LOCK_ASSERT(sc); \
+} while (0)
+
+
+static int
+cpsw_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "ti,cpsw"))
+ return (ENXIO);
+
+ device_set_desc(dev, "3-port Switch Ethernet Subsystem");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+cpsw_attach(device_t dev)
+{
+ struct cpsw_softc *sc;
+ struct mii_softc *miisc;
+ struct ifnet *ifp;
+ uint8_t mac_addr[ETHER_ADDR_LEN];
+ int i, error, phy;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ memcpy(sc->mac_addr, mac_addr, ETHER_ADDR_LEN);
+ sc->node = ofw_bus_get_node(dev);
+
+ /* Get phy address from fdt */
+ if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0) {
+ device_printf(dev, "failed to get PHY address from FDT\n");
+ return (ENXIO);
+ }
+ /* Initialize mutexes */
+ mtx_init(&sc->tx_lock, device_get_nameunit(dev),
+ "cpsw TX lock", MTX_DEF);
+ mtx_init(&sc->rx_lock, device_get_nameunit(dev),
+ "cpsw RX lock", MTX_DEF);
+
+ /* Allocate IO and IRQ resources */
+ error = bus_alloc_resources(dev, res_spec, sc->res);
+ if (error) {
+ device_printf(dev, "could not allocate resources\n");
+ cpsw_detach(dev);
+ return (ENXIO);
+ }
+
+ reg = cpsw_read_4(CPSW_SS_IDVER);
+ device_printf(dev, "Version %d.%d (%d)\n", (reg >> 8 & 0x7),
+ reg & 0xFF, (reg >> 11) & 0x1F);
+
+ /* Allocate DMA, buffers, buffer descriptors */
+ error = cpsw_allocate_dma(sc);
+ if (error) {
+ cpsw_detach(dev);
+ return (ENXIO);
+ }
+
+ //cpsw_add_sysctls(sc); TODO
+
+ /* Allocate network interface */
+ ifp = sc->ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(dev, "if_alloc() failed\n");
+ cpsw_detach(dev);
+ return (ENOMEM);
+ }
+
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
+ ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN?
+ ifp->if_capenable = ifp->if_capabilities;
+
+ ifp->if_init = cpsw_init;
+ ifp->if_start = cpsw_start;
+ ifp->if_ioctl = cpsw_ioctl;
+
+ ifp->if_snd.ifq_drv_maxlen = CPSW_MAX_TX_BUFFERS - 1;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+ IFQ_SET_READY(&ifp->if_snd);
+
+ /* Get low part of MAC address from control module (mac_id0_lo) */
+ ti_scm_reg_read_4(0x630, &reg);
+ mac_addr[0] = (reg >> 8) & 0xFF;
+ mac_addr[1] = reg & 0xFF;
+
+ /* Get high part of MAC address from control module (mac_id0_hi) */
+ ti_scm_reg_read_4(0x634, &reg);
+ mac_addr[2] = (reg >> 24) & 0xFF;
+ mac_addr[3] = (reg >> 16) & 0xFF;
+ mac_addr[4] = (reg >> 8) & 0xFF;
+ mac_addr[5] = reg & 0xFF;
+
+ ether_ifattach(ifp, sc->mac_addr);
+ callout_init(&sc->wd_callout, 0);
+
+ /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+ cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
+
+ /* Attach PHY(s) */
+ error = mii_attach(dev, &sc->miibus, ifp, cpsw_ifmedia_upd,
+ cpsw_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
+ if (error) {
+ device_printf(dev, "attaching PHYs failed\n");
+ cpsw_detach(dev);
+ return (error);
+ }
+ sc->mii = device_get_softc(sc->miibus);
+
+ /* Tell the MAC where to find the PHY so autoneg works */
+ miisc = LIST_FIRST(&sc->mii->mii_phys);
+
+ /* Select PHY and enable interrupts */
+ cpsw_write_4(MDIOUSERPHYSEL0, (1 << 6) | (miisc->mii_phy & 0x1F));
+
+ /* Attach interrupt handlers */
+ for (i = 1; i <= CPSW_INTR_COUNT; ++i) {
+ error = bus_setup_intr(dev, sc->res[i],
+ INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, *cpsw_intrs[i - 1].handler,
+ sc, &sc->ih_cookie[i - 1]);
+ if (error) {
+ device_printf(dev, "could not setup %s\n",
+ cpsw_intrs[i].description);
+ cpsw_detach(dev);
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+cpsw_detach(device_t dev)
+{
+ struct cpsw_softc *sc;
+ int error,i;
+
+ sc = device_get_softc(dev);
+
+ /* Stop controller and free TX queue */
+ if (sc->ifp)
+ cpsw_shutdown(dev);
+
+ /* Wait for stopping ticks */
+ callout_drain(&sc->wd_callout);
+
+ /* Stop and release all interrupts */
+ for (i = 0; i < CPSW_INTR_COUNT; ++i) {
+ if (!sc->ih_cookie[i])
+ continue;
+
+ error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]);
+ if (error)
+ device_printf(dev, "could not release %s\n",
+ cpsw_intrs[i + 1].description);
+ }
+
+ /* Detach network interface */
+ if (sc->ifp) {
+ ether_ifdetach(sc->ifp);
+ if_free(sc->ifp);
+ }
+
+ /* Free DMA resources */
+ cpsw_free_dma(sc);
+
+ /* Free IO memory handler */
+ bus_release_resources(dev, res_spec, sc->res);
+
+ /* Destroy mutexes */
+ mtx_destroy(&sc->rx_lock);
+ mtx_destroy(&sc->tx_lock);
+
+ return (0);
+}
+
+static int
+cpsw_suspend(device_t dev)
+{
+
+ device_printf(dev, "%s\n", __FUNCTION__);
+ return (0);
+}
+
+static int
+cpsw_resume(device_t dev)
+{
+
+ device_printf(dev, "%s\n", __FUNCTION__);
+ return (0);
+}
+
+static int
+cpsw_shutdown(device_t dev)
+{
+ struct cpsw_softc *sc = device_get_softc(dev);
+
+ CPSW_GLOBAL_LOCK(sc);
+
+ cpsw_stop(sc);
+
+ CPSW_GLOBAL_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+cpsw_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct cpsw_softc *sc;
+ uint32_t r;
+ uint32_t retries = CPSW_MIIBUS_RETRIES;
+
+ sc = device_get_softc(dev);
+
+ /* Wait until interface is ready by watching GO bit */
+ while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+ DELAY(CPSW_MIIBUS_DELAY);
+ if (!retries)
+ device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+ /* Set GO, phy and reg */
+ cpsw_write_4(MDIOUSERACCESS0, (1 << 31) |
+ ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+ while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+ DELAY(CPSW_MIIBUS_DELAY);
+ if (!retries)
+ device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+ r = cpsw_read_4(MDIOUSERACCESS0);
+ /* Check for ACK */
+ if(r & (1<<29)) {
+ return (r & 0xFFFF);
+ }
+ device_printf(dev, "Failed to read from PHY.\n");
+ return 0;
+}
+
+static int
+cpsw_miibus_writereg(device_t dev, int phy, int reg, int value)
+{
+ struct cpsw_softc *sc;
+ uint32_t retries = CPSW_MIIBUS_RETRIES;
+
+ sc = device_get_softc(dev);
+
+ /* Wait until interface is ready by watching GO bit */
+ while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+ DELAY(CPSW_MIIBUS_DELAY);
+ if (!retries)
+ device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+ /* Set GO, WRITE, phy, reg and value */
+ cpsw_write_4(MDIOUSERACCESS0, (value & 0xFFFF) | (3 << 30) |
+ ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+ while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+ DELAY(CPSW_MIIBUS_DELAY);
+ if (!retries)
+ device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+ /* Check for ACK */
+ if(cpsw_read_4(MDIOUSERACCESS0) & (1<<29)) {
+ return 0;
+ }
+ device_printf(dev, "Failed to write to PHY.\n");
+
+ return 0;
+}
+
+static int
+cpsw_allocate_dma(struct cpsw_softc *sc)
+{
+ int err;
+ int i;
+
+ /* Allocate a busdma tag and DMA safe memory for tx mbufs. */
+ err = bus_dma_tag_create(
+ bus_get_dma_tag(sc->dev), /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filtfunc, filtfuncarg */
+ MCLBYTES, 1, /* maxsize, nsegments */
+ MCLBYTES, 0, /* maxsegsz, flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &sc->mbuf_dtag); /* dmatag */
+
+ if (err)
+ return (ENOMEM);
+ for (i = 0; i < CPSW_MAX_TX_BUFFERS; i++) {
+ if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->tx_dmamap[i])) {
+ if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
+ return (ENOMEM);
+ }
+ }
+
+ for (i = 0; i < CPSW_MAX_RX_BUFFERS; i++) {
+ if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->rx_dmamap[i])) {
+ if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
+ return (ENOMEM);
+ }
+ }
+
+ return (0);
+}
+
+static int
+cpsw_free_dma(struct cpsw_softc *sc)
+{
+ (void)sc; /* UNUSED */
+ // TODO
+ return 0;
+}
+
+static int
+cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next)
+{
+ bus_dma_segment_t seg[1];
+ struct cpsw_cpdma_bd bd;
+ int error;
+ int nsegs;
+
+ if (sc->rx_mbuf[i]) {
+ bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->mbuf_dtag, sc->rx_dmamap[i]);
+ }
+
+ sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (sc->rx_mbuf[i] == NULL)
+ return (ENOBUFS);
+
+ sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len = sc->rx_mbuf[i]->m_ext.ext_size;
+
+ error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->rx_dmamap[i],
+ sc->rx_mbuf[i], seg, &nsegs, BUS_DMA_NOWAIT);
+
+ KASSERT(nsegs == 1, ("Too many segments returned!"));
+ if (nsegs != 1 || error)
+ panic("%s: nsegs(%d), error(%d)",__func__, nsegs, error);
+
+ bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_PREREAD);
+
+ /* Create and submit new rx descriptor*/
+ bd.next = next;
+ bd.bufptr = seg->ds_addr;
+ bd.buflen = MCLBYTES-1;
+ bd.bufoff = 2; /* make IP hdr aligned with 4 */
+ bd.pktlen = 0;
+ bd.flags = CPDMA_BD_OWNER;
+ cpsw_cpdma_write_rxbd(i, &bd);
+
+ return (0);
+}
+
+
+static int
+cpsw_encap(struct cpsw_softc *sc, struct mbuf *m0)
+{
+ bus_dma_segment_t seg[1];
+ struct cpsw_cpdma_bd bd;
+ int error;
+ int nsegs;
+ int idx;
+
+ if (sc->txbd_queue_size == CPSW_MAX_TX_BUFFERS)
+ return (ENOBUFS);
+
+ idx = sc->txbd_head + sc->txbd_queue_size;
+
+ if (idx >= (CPSW_MAX_TX_BUFFERS) )
+ idx -= CPSW_MAX_TX_BUFFERS;
+
+ /* Create mapping in DMA memory */
+ error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->tx_dmamap[idx], m0, seg, &nsegs,
+ BUS_DMA_NOWAIT);
+ sc->tc[idx]++;
+ if (error != 0 || nsegs != 1 ) {
+ bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[idx]);
+ return ((error != 0) ? error : -1);
+ }
+ bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[idx], BUS_DMASYNC_PREWRITE);
+
+ /* Fill descriptor data */
+ bd.next = 0;
+ bd.bufptr = seg->ds_addr;
+ bd.bufoff = 0;
+ bd.buflen = (seg->ds_len < 64 ? 64 : seg->ds_len);
+ bd.pktlen = (seg->ds_len < 64 ? 64 : seg->ds_len);
+ /* Set OWNERSHIP, SOP, EOP */
+ bd.flags = (7<<13);
+
+ /* Write descriptor */
+ cpsw_cpdma_write_txbd(idx, &bd);
+
+ /* Previous descriptor should point to us */
+ cpsw_cpdma_write_txbd_next(((idx-1<0)?(CPSW_MAX_TX_BUFFERS-1):(idx-1)),
+ cpsw_cpdma_txbd_paddr(idx));
+
+ sc->txbd_queue_size++;
+
+ return (0);
+}
+
+static void
+cpsw_start(struct ifnet *ifp)
+{
+ struct cpsw_softc *sc = ifp->if_softc;
+
+ CPSW_TX_LOCK(sc);
+ cpsw_start_locked(ifp);
+ CPSW_TX_UNLOCK(sc);
+}
+
+static void
+cpsw_start_locked(struct ifnet *ifp)
+{
+ struct cpsw_softc *sc = ifp->if_softc;
+ struct mbuf *m0, *mtmp;
+ uint32_t queued = 0;
+
+ CPSW_TX_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING)
+ return;
+
+ for (;;) {
+ /* Get packet from the queue */
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+
+ mtmp = m_defrag(m0, M_DONTWAIT);
+ if (mtmp)
+ m0 = mtmp;
+
+ if (cpsw_encap(sc, m0)) {
+ IF_PREPEND(&ifp->if_snd, m0);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+ queued++;
+ BPF_MTAP(ifp, m0);
+ }
+
+ if (!queued)
+ return;
+
+ if (sc->eoq) {
+ cpsw_write_4(CPSW_CPDMA_TX_HDP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
+ sc->eoq = 0;
+ }
+ sc->wd_timer = 5;
+}
+
+static void
+cpsw_stop(struct cpsw_softc *sc)
+{
+ struct ifnet *ifp;
+
+ ifp = sc->ifp;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ /* Stop tick engine */
+ callout_stop(&sc->wd_callout);
+
+ /* Disable interface */
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ sc->wd_timer = 0;
+
+ /* Disable interrupts TODO */
+
+}
+
+static int
+cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct cpsw_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error;
+ uint32_t flags;
+
+ error = 0;
+
+ // FIXME
+ switch (command) {
+ case SIOCSIFFLAGS:
+ CPSW_GLOBAL_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ flags = ifp->if_flags ^ sc->cpsw_if_flags;
+ if (flags & IFF_PROMISC)
+ printf("%s: SIOCSIFFLAGS "
+ "IFF_PROMISC unimplemented\n",
+ __func__);
+
+ if (flags & IFF_ALLMULTI)
+ printf("%s: SIOCSIFFLAGS "
+ "IFF_ALLMULTI unimplemented\n",
+ __func__);
+ } else {
+ printf("%s: SIOCSIFFLAGS cpsw_init_locked\n", __func__);
+ //cpsw_init_locked(sc);
+ }
+ }
+ else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ cpsw_stop(sc);
+
+ sc->cpsw_if_flags = ifp->if_flags;
+ CPSW_GLOBAL_UNLOCK(sc);
+ break;
+ printf("%s: SIOCSIFFLAGS\n",__func__);
+ break;
+ case SIOCADDMULTI:
+ printf("%s: SIOCADDMULTI\n",__func__);
+ break;
+ case SIOCDELMULTI:
+ printf("%s: SIOCDELMULTI\n",__func__);
+ break;
+ case SIOCSIFCAP:
+ printf("%s: SIOCSIFCAP\n",__func__);
+ break;
+ case SIOCGIFMEDIA: /* fall through */
+ printf("%s: SIOCGIFMEDIA\n",__func__);
+ error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
+ break;
+ case SIOCSIFMEDIA:
+ printf("%s: SIOCSIFMEDIA\n",__func__);
+ error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ }
+ return (error);
+}
+
+static void
+cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct cpsw_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ CPSW_TX_LOCK(sc);
+
+ mii = sc->mii;
+ mii_pollstat(mii);
+
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ CPSW_TX_UNLOCK(sc);
+}
+
+
+static int
+cpsw_ifmedia_upd(struct ifnet *ifp)
+{
+ struct cpsw_softc *sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_UP) {
+ CPSW_GLOBAL_LOCK(sc);
+
+ sc->cpsw_media_status = sc->mii->mii_media.ifm_media;
+ mii_mediachg(sc->mii);
+ cpsw_init_locked(sc);
+
+ CPSW_GLOBAL_UNLOCK(sc);
+ }
+
+ return (0);
+}
+
+static void
+cpsw_intr_rx_thresh(void *arg)
+{
+ (void)arg; /* UNUSED */
+}
+
+static void
+cpsw_intr_rx(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ CPSW_RX_LOCK(sc);
+ cpsw_intr_rx_locked(arg);
+ CPSW_RX_UNLOCK(sc);
+}
+
+static void
+cpsw_intr_rx_locked(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ struct cpsw_cpdma_bd bd;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = sc->ifp;
+
+ i = sc->rxbd_head;
+ cpsw_cpdma_read_rxbd(i, &bd);
+
+ while (bd.flags & CPDMA_BD_SOP) {
+ cpsw_write_4(CPSW_CPDMA_RX_CP(0), cpsw_cpdma_rxbd_paddr(i));
+
+ bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
+
+ /* Fill mbuf */
+ sc->rx_mbuf[i]->m_hdr.mh_data +=2;
+ sc->rx_mbuf[i]->m_len = bd.pktlen-2;
+ sc->rx_mbuf[i]->m_pkthdr.len = bd.pktlen-2;
+ sc->rx_mbuf[i]->m_flags |= M_PKTHDR;
+ sc->rx_mbuf[i]->m_pkthdr.rcvif = ifp;
+
+ if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
+ /* check for valid CRC by looking into pkt_err[5:4] */
+ if ( (bd.flags & CPDMA_BD_PKT_ERR_MASK) == 0 ) {
+ sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+ sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+ sc->rx_mbuf[i]->m_pkthdr.csum_data = 0xffff;
+ }
+ }
+
+ /* Handover packet */
+ CPSW_RX_UNLOCK(sc);
+ (*ifp->if_input)(ifp, sc->rx_mbuf[i]);
+ CPSW_RX_LOCK(sc);
+
+ /* Allocate new buffer for current descriptor */
+ cpsw_new_rxbuf(sc, i, 0);
+
+ /* we are not at tail so old tail BD should point to new one */
+ cpsw_cpdma_write_rxbd_next(sc->rxbd_tail,
+ cpsw_cpdma_rxbd_paddr(i));
+
+ /* Check if EOQ is reached */
+ if (cpsw_cpdma_read_rxbd_flags(sc->rxbd_tail) & CPDMA_BD_EOQ) {
+ cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(i));
+ }
+ sc->rxbd_tail = i;
+
+ /* read next descriptor */
+ if (++i == CPSW_MAX_RX_BUFFERS)
+ i = 0;
+ cpsw_cpdma_read_rxbd(i, &bd);
+ sc->rxbd_head = i;
+ }
+
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+}
+
+static void
+cpsw_intr_tx(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ CPSW_TX_LOCK(sc);
+ cpsw_intr_tx_locked(arg);
+ CPSW_TX_UNLOCK(sc);
+}
+
+static void
+cpsw_intr_tx_locked(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ uint32_t flags;
+
+ if(sc->txbd_head == -1)
+ return;
+
+ if(sc->txbd_queue_size<1) {
+ /* in some casses interrupt happens even when there is no
+ data in transmit queue */
+ return;
+ }
+
+ /* Disable watchdog */
+ sc->wd_timer = 0;
+
+ flags = cpsw_cpdma_read_txbd_flags(sc->txbd_head);
+
+ /* After BD is transmitted CPDMA will set OWNER to 0 */
+ if (flags & CPDMA_BD_OWNER)
+ return;
+
+ if(flags & CPDMA_BD_EOQ)
+ sc->eoq=1;
+
+ /* release dmamap and mbuf */
+ bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head],
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head]);
+ m_freem(sc->tx_mbuf[sc->txbd_head]);
+
+ cpsw_write_4(CPSW_CPDMA_TX_CP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
+
+ if (++sc->txbd_head == CPSW_MAX_TX_BUFFERS)
+ sc->txbd_head = 0;
+
+ --sc->txbd_queue_size;
+
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+}
+
+static void
+cpsw_intr_misc(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ uint32_t stat = cpsw_read_4(CPSW_WR_C_MISC_STAT(0));
+ printf("%s: stat=%x\n",__func__,stat);
+ /* EOI_RX_PULSE */
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
+}
+
+static void
+cpsw_tick(void *msc)
+{
+ struct cpsw_softc *sc = msc;
+
+ /* Check for TX timeout */
+ cpsw_watchdog(sc);
+
+ mii_tick(sc->mii);
+
+ /* Check for media type change */
+ if(sc->cpsw_media_status != sc->mii->mii_media.ifm_media) {
+ printf("%s: media type changed (ifm_media=%x)\n",__func__,
+ sc->mii->mii_media.ifm_media);
+ cpsw_ifmedia_upd(sc->ifp);
+ }
+
+ /* Schedule another timeout one second from now */
+ callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
+}
+
+static void
+cpsw_watchdog(struct cpsw_softc *sc)
+{
+ struct ifnet *ifp;
+
+ ifp = sc->ifp;
+
+ CPSW_GLOBAL_LOCK(sc);
+
+ if (sc->wd_timer == 0 || --sc->wd_timer) {
+ CPSW_GLOBAL_UNLOCK(sc);
+ return;
+ }
+
+ ifp->if_oerrors++;
+ if_printf(ifp, "watchdog timeout\n");
+
+ cpsw_stop(sc);
+ cpsw_init_locked(sc);
+
+ CPSW_GLOBAL_UNLOCK(sc);
+}
+
+static void
+cpsw_init(void *arg)
+{
+ struct cpsw_softc *sc = arg;
+ CPSW_GLOBAL_LOCK(sc);
+ cpsw_init_locked(arg);
+ CPSW_GLOBAL_UNLOCK(sc);
+}
+
+int once = 1;
+
+static void
+cpsw_init_locked(void *arg)
+{
+ struct ifnet *ifp;
+ struct cpsw_softc *sc = arg;
+ uint8_t broadcast_address[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ uint32_t next_bdp;
+ uint32_t i;
+
+ ifp = sc->ifp;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ return;
+
+ printf("%s: start\n",__func__);
+
+ /* Reset writer */
+ cpsw_write_4(CPSW_WR_SOFT_RESET, 1);
+ while(cpsw_read_4(CPSW_WR_SOFT_RESET) & 1);
+
+ /* Reset SS */
+ cpsw_write_4(CPSW_SS_SOFT_RESET, 1);
+ while(cpsw_read_4(CPSW_SS_SOFT_RESET) & 1);
+
+ /* Clear table (30) and enable ALE(31) */
+ if (once)
+ cpsw_write_4(CPSW_ALE_CONTROL, (3 << 30));
+ else
+ cpsw_write_4(CPSW_ALE_CONTROL, (1 << 31));
+ once = 0; // FIXME
+
+ /* Reset and init Sliver port 1 and 2 */
+ for(i=0;i<2;i++) {
+ /* Reset */
+ cpsw_write_4(CPSW_SL_SOFT_RESET(i), 1);
+ while(cpsw_read_4(CPSW_SL_SOFT_RESET(i)) & 1);
+ /* Set Slave Mapping */
+ cpsw_write_4(CPSW_SL_RX_PRI_MAP(i),0x76543210);
+ cpsw_write_4(CPSW_PORT_P_TX_PRI_MAP(i+1),0x33221100);
+ cpsw_write_4(CPSW_SL_RX_MAXLEN(i),0x5f2);
+ /* Set MAC Address */
+ cpsw_write_4(CPSW_PORT_P_SA_HI(i+1), sc->mac_addr[0] |
+ (sc->mac_addr[1] << 8) |
+ (sc->mac_addr[2] << 16) |
+ (sc->mac_addr[3] << 24));
+ cpsw_write_4(CPSW_PORT_P_SA_LO(i+1), sc->mac_addr[4] |
+ (sc->mac_addr[5] << 8));
+
+ /* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5),
+ IFCTL_A(15), IFCTL_B(16) FIXME */
+ cpsw_write_4(CPSW_SL_MACCONTROL(i), 1 | (1<<5) | (1<<15));
+
+ /* Set ALE port to forwarding(3) */
+ cpsw_write_4(CPSW_ALE_PORTCTL(i+1), 3);
+ }
+
+ /* Set Host Port Mapping */
+ cpsw_write_4(CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
+ cpsw_write_4(CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+
+ /* Set ALE port to forwarding(3)*/
+ cpsw_write_4(CPSW_ALE_PORTCTL(0), 3);
+
+ /* Add own MAC address and broadcast to ALE */
+ cpsw_ale_uc_entry_set(sc, 0, sc->mac_addr);
+ cpsw_ale_mc_entry_set(sc, 7, broadcast_address);
+
+ cpsw_write_4(CPSW_SS_PTYPE, 0);
+ /* Enable statistics for ports 0, 1 and 2 */
+ cpsw_write_4(CPSW_SS_STAT_PORT_EN, 7);
+
+ /* Reset CPDMA */
+ cpsw_write_4(CPSW_CPDMA_SOFT_RESET, 1);
+ while(cpsw_read_4(CPSW_CPDMA_SOFT_RESET) & 1);
+
+ for(i = 0; i < 8; i++) {
+ cpsw_write_4(CPSW_CPDMA_TX_HDP(i), 0);
+ cpsw_write_4(CPSW_CPDMA_RX_HDP(i), 0);
+ cpsw_write_4(CPSW_CPDMA_TX_CP(i), 0);
+ cpsw_write_4(CPSW_CPDMA_RX_CP(i), 0);
+ }
+
+ cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 0);
+
+ /* Initialize RX Buffer Descriptors */
+ i = CPSW_MAX_RX_BUFFERS;
+ next_bdp = 0;
+ while (i--) {
+ cpsw_new_rxbuf(sc, i, next_bdp);
+ /* Increment number of free RX buffers */
+ //cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 1);
+ next_bdp = cpsw_cpdma_rxbd_paddr(i);
+ }
+
+ sc->rxbd_head = 0;
+ sc->rxbd_tail = CPSW_MAX_RX_BUFFERS-1;
+ sc->txbd_head = 0;
+ sc->eoq = 1;
+ sc->txbd_queue_size = 0;
+
+ /* Make IP hdr aligned with 4 */
+ cpsw_write_4(CPSW_CPDMA_RX_BUFFER_OFFSET, 2);
+ /* Write channel 0 RX HDP */
+ cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(0));
+
+ /* Clear all interrupt Masks */
+ cpsw_write_4(CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+ cpsw_write_4(CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+
+ /* Enable TX & RX DMA */
+ cpsw_write_4(CPSW_CPDMA_TX_CONTROL, 1);
+ cpsw_write_4(CPSW_CPDMA_RX_CONTROL, 1);
+
+ /* Enable TX and RX interrupt receive for core 0 */
+ cpsw_write_4(CPSW_WR_C_TX_EN(0), 0xFF);
+ cpsw_write_4(CPSW_WR_C_RX_EN(0), 0xFF);
+ //cpsw_write_4(CPSW_WR_C_MISC_EN(0), 0x3F);
+
+ /* Enable host Error Interrupt */
+ cpsw_write_4(CPSW_CPDMA_DMA_INTMASK_SET, 1);
+
+ /* Enable interrupts for TX and RX Channel 0 */
+ cpsw_write_4(CPSW_CPDMA_TX_INTMASK_SET, 1);
+ cpsw_write_4(CPSW_CPDMA_RX_INTMASK_SET, 1);
+
+ /* Ack stalled irqs */
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 0);
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
+ cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
+
+ /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+ cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
+
+ /* Select MII in GMII_SEL, Internal Delay mode */
+ //ti_scm_reg_write_4(0x650, 0);
+
+ /* Activate network interface */
+ sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ sc->wd_timer = 0;
+ callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
+}
+
+static void
+cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+ cpsw_write_4(CPSW_ALE_TBLCTL, idx & 1023);
+ ale_entry[0] = cpsw_read_4(CPSW_ALE_TBLW0);
+ ale_entry[1] = cpsw_read_4(CPSW_ALE_TBLW1);
+ ale_entry[2] = cpsw_read_4(CPSW_ALE_TBLW2);
+}
+
+static void
+cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+ cpsw_write_4(CPSW_ALE_TBLW0, ale_entry[0]);
+ cpsw_write_4(CPSW_ALE_TBLW1, ale_entry[1]);
+ cpsw_write_4(CPSW_ALE_TBLW2, ale_entry[2]);
+ cpsw_write_4(CPSW_ALE_TBLCTL, (idx & 1023) | (1 << 31));
+}
+
+static int
+cpsw_ale_find_entry_by_mac(struct cpsw_softc *sc, uint8_t *mac)
+{
+ int i;
+ uint32_t ale_entry[3];
+ for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+ cpsw_ale_read_entry(sc, i, ale_entry);
+ if ((((ale_entry[1] >> 8) & 0xFF) == mac[0]) &&
+ (((ale_entry[1] >> 0) & 0xFF) == mac[1]) &&
+ (((ale_entry[0] >>24) & 0xFF) == mac[2]) &&
+ (((ale_entry[0] >>16) & 0xFF) == mac[3]) &&
+ (((ale_entry[0] >> 8) & 0xFF) == mac[4]) &&
+ (((ale_entry[0] >> 0) & 0xFF) == mac[5])) {
+ return (i);
+ }
+ }
+ return CPSW_MAX_ALE_ENTRIES;
+}
+
+static int
+cpsw_ale_find_free_entry(struct cpsw_softc *sc)
+{
+ int i;
+ uint32_t ale_entry[3];
+ for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+ cpsw_ale_read_entry(sc, i, ale_entry);
+ /* Entry Type[61:60] is 0 for free entry */
+ if (((ale_entry[1] >> 28) & 3) == 0) {
+ return i;
+ }
+ }
+ return CPSW_MAX_ALE_ENTRIES;
+}
+
+
+static int
+cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac)
+{
+ int i;
+ uint32_t ale_entry[3];
+
+ if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
+ i = cpsw_ale_find_free_entry(sc);
+ }
+
+ if (i == CPSW_MAX_ALE_ENTRIES)
+ return (ENOMEM);
+
+ /* Set MAC address */
+ ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
+ ale_entry[1] = mac[0]<<8 | mac[1];
+
+ /* Entry type[61:60] is addr entry(1) */
+ ale_entry[1] |= 0x10<<24;
+
+ /* Set portmask [67:66] */
+ ale_entry[2] = (port & 3) << 2;
+
+ cpsw_ale_write_entry(sc, i, ale_entry);
+
+ return 0;
+}
+
+static int
+cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac)
+{
+ int i;
+ uint32_t ale_entry[3];
+
+ if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
+ i = cpsw_ale_find_free_entry(sc);
+ }
+
+ if (i == CPSW_MAX_ALE_ENTRIES)
+ return (ENOMEM);
+
+ /* Set MAC address */
+ ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
+ ale_entry[1] = mac[0]<<8 | mac[1];
+
+ /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/
+ ale_entry[1] |= 0xd0<<24;
+
+ /* Set portmask [68:66] */
+ ale_entry[2] = (portmap & 7) << 2;
+
+ cpsw_ale_write_entry(sc, i, ale_entry);
+
+ return 0;
+}
+
+#ifdef CPSW_DEBUG
+static void
+cpsw_ale_dump_table(struct cpsw_softc *sc) {
+ int i;
+ uint32_t ale_entry[3];
+ for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+ cpsw_ale_read_entry(sc, i, ale_entry);
+ if (ale_entry[0] || ale_entry[1] || ale_entry[2]) {
+ printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[0],
+ ale_entry[1],ale_entry[2]);
+ printf("mac: %02x:%02x:%02x:%02x:%02x:%02x ",
+ (ale_entry[1] >> 8) & 0xFF,
+ (ale_entry[1] >> 0) & 0xFF,
+ (ale_entry[0] >>24) & 0xFF,
+ (ale_entry[0] >>16) & 0xFF,
+ (ale_entry[0] >> 8) & 0xFF,
+ (ale_entry[0] >> 0) & 0xFF);
+ printf( ((ale_entry[1]>>8)&1) ? "mcast " : "ucast ");
+ printf("type: %u ", (ale_entry[1]>>28)&3);
+ printf("port: %u ", (ale_entry[2]>>2)&7);
+ printf("\n");
+ }
+ }
+}
+#endif
diff --git a/sys/arm/ti/cpsw/if_cpswreg.h b/sys/arm/ti/cpsw/if_cpswreg.h
new file mode 100644
index 0000000..a4264d4
--- /dev/null
+++ b/sys/arm/ti/cpsw/if_cpswreg.h
@@ -0,0 +1,107 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_CPSWREG_H
+#define _IF_CPSWREG_H
+
+#define CPSW_SS_OFFSET 0x0000
+#define CPSW_SS_IDVER (CPSW_SS_OFFSET + 0x00)
+#define CPSW_SS_SOFT_RESET (CPSW_SS_OFFSET + 0x08)
+#define CPSW_SS_STAT_PORT_EN (CPSW_SS_OFFSET + 0x0C)
+#define CPSW_SS_PTYPE (CPSW_SS_OFFSET + 0x10)
+
+#define CPSW_PORT_OFFSET 0x0100
+#define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
+#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C)
+#define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020)
+#define CPSW_PORT_P_SA_LO(p) (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100))
+#define CPSW_PORT_P_SA_HI(p) (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100))
+
+#define CPSW_CPDMA_OFFSET 0x0800
+#define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04)
+#define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14)
+#define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c)
+#define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20)
+#define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24)
+#define CPSW_CPDMA_RX_BUFFER_OFFSET (CPSW_CPDMA_OFFSET + 0x28)
+#define CPSW_CPDMA_TX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0x80)
+#define CPSW_CPDMA_TX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0x84)
+#define CPSW_CPDMA_TX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0x88)
+#define CPSW_CPDMA_TX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0x8C)
+#define CPSW_CPDMA_CPDMA_EOI_VECTOR (CPSW_CPDMA_OFFSET + 0x94)
+#define CPSW_CPDMA_RX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xA0)
+#define CPSW_CPDMA_RX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xA4)
+#define CPSW_CPDMA_RX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xA8)
+#define CPSW_CPDMA_RX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xAc)
+#define CPSW_CPDMA_DMA_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xB0)
+#define CPSW_CPDMA_DMA_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xB4)
+#define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8)
+#define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC)
+#define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_HDP(p) (CPSW_CPDMA_OFFSET + 0x200 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_HDP(p) (CPSW_CPDMA_OFFSET + 0x220 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_CP(p) (CPSW_CPDMA_OFFSET + 0x240 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_CP(p) (CPSW_CPDMA_OFFSET + 0x260 + ((p) * 0x04))
+
+#define CPSW_CPTS_OFFSET 0x0C00
+
+#define CPSW_ALE_OFFSET 0x0D00
+#define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08)
+#define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20)
+#define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34)
+#define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38)
+#define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C)
+#define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
+
+#define CPSW_SL_OFFSET 0x0D80
+#define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
+#define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
+#define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
+#define CPSW_SL_RX_PRI_MAP(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24)
+
+#define MDIO_OFFSET 0x1000
+#define MDIOCONTROL (MDIO_OFFSET + 0x04)
+#define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80)
+#define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84)
+
+#define CPSW_WR_OFFSET 0x1200
+#define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04)
+#define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08)
+#define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c)
+#define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10)
+#define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14)
+#define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18)
+#define CPSW_WR_C_MISC_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C)
+#define CPSW_WR_C_RX_THRESH_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40)
+#define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
+#define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
+#define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
+
+#define CPSW_CPPI_RAM_OFFSET 0x2000
+
+#endif /*_IF_CPSWREG_H */
diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h
new file mode 100644
index 0000000..836bc2d
--- /dev/null
+++ b/sys/arm/ti/cpsw/if_cpswvar.h
@@ -0,0 +1,124 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_CPSWVAR_H
+#define _IF_CPSWVAR_H
+
+#define CPSW_INTR_COUNT 4
+
+/* MII BUS */
+#define CPSW_MIIBUS_RETRIES 5
+#define CPSW_MIIBUS_DELAY 1000
+
+#define CPSW_MAX_TX_BUFFERS 128
+#define CPSW_MAX_RX_BUFFERS 128
+#define CPSW_MAX_ALE_ENTRIES 1024
+
+struct cpsw_softc {
+ struct ifnet *ifp;
+ phandle_t node;
+ device_t dev;
+ uint8_t mac_addr[ETHER_ADDR_LEN];
+ device_t miibus;
+ struct mii_data *mii;
+ struct mtx tx_lock; /* transmitter lock */
+ struct mtx rx_lock; /* receiver lock */
+ struct resource *res[1 + CPSW_INTR_COUNT]; /* resources */
+ void *ih_cookie[CPSW_INTR_COUNT]; /* interrupt handlers cookies */
+
+ uint32_t cpsw_if_flags;
+ int cpsw_media_status;
+
+ struct callout wd_callout;
+ int wd_timer;
+
+ /* buffers */
+ bus_dma_tag_t mbuf_dtag;
+ bus_dmamap_t tx_dmamap[CPSW_MAX_TX_BUFFERS];
+ bus_dmamap_t rx_dmamap[CPSW_MAX_RX_BUFFERS];
+ struct mbuf *tx_mbuf[CPSW_MAX_TX_BUFFERS];
+ struct mbuf *rx_mbuf[CPSW_MAX_RX_BUFFERS];
+ int txbd_head;
+ int txbd_queue_size;
+ int rxbd_head;
+ int rxbd_tail;
+
+ int tmp;
+ int eoq;
+ int tc[CPSW_MAX_TX_BUFFERS];
+ int tc_unload[CPSW_MAX_TX_BUFFERS];
+
+ struct cpsw_softc *phy_sc;
+};
+
+#define CPDMA_BD_SOP (1<<15)
+#define CPDMA_BD_EOP (1<<14)
+#define CPDMA_BD_OWNER (1<<13)
+#define CPDMA_BD_EOQ (1<<12)
+#define CPDMA_BD_PKT_ERR_MASK (3<< 4)
+
+struct cpsw_cpdma_bd {
+ volatile uint32_t next;
+ volatile uint32_t bufptr;
+ volatile uint16_t buflen;
+ volatile uint16_t bufoff;
+ volatile uint16_t pktlen;
+ volatile uint16_t flags;
+};
+
+/* Read/Write macros */
+#define cpsw_read_4(reg) bus_read_4(sc->res[0], reg)
+#define cpsw_write_4(reg, val) bus_write_4(sc->res[0], reg, val)
+
+#define cpsw_cpdma_txbd_offset(i) \
+ (CPSW_CPPI_RAM_OFFSET + ((i)*16))
+#define cpsw_cpdma_txbd_paddr(i) (cpsw_cpdma_txbd_offset(i) + \
+ vtophys(rman_get_start(sc->res[0])))
+#define cpsw_cpdma_read_txbd(i, val) \
+ bus_read_region_4(sc->res[0], cpsw_cpdma_txbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_txbd(i, val) \
+ bus_write_region_4(sc->res[0], cpsw_cpdma_txbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_txbd_next(i, val) \
+ bus_write_4(sc->res[0], cpsw_cpdma_txbd_offset(i), val)
+#define cpsw_cpdma_read_txbd_flags(i) \
+ bus_read_2(sc->res[0], cpsw_cpdma_txbd_offset(i)+14)
+
+#define cpsw_cpdma_rxbd_offset(i) \
+ (CPSW_CPPI_RAM_OFFSET + ((CPSW_MAX_TX_BUFFERS + (i))*16))
+#define cpsw_cpdma_rxbd_paddr(i) (cpsw_cpdma_rxbd_offset(i) + \
+ vtophys(rman_get_start(sc->res[0])))
+#define cpsw_cpdma_read_rxbd(i, val) \
+ bus_read_region_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_rxbd(i, val) \
+ bus_write_region_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_rxbd_next(i, val) \
+ bus_write_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), val)
+#define cpsw_cpdma_read_rxbd_flags(i) \
+ bus_read_2(sc->res[0], cpsw_cpdma_rxbd_offset(i)+14)
+
+#endif /*_IF_CPSWVAR_H */
diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti
new file mode 100644
index 0000000..baeaa00
--- /dev/null
+++ b/sys/arm/ti/files.ti
@@ -0,0 +1,25 @@
+#$FreeBSD$
+
+kern/kern_clocksource.c standard
+
+arm/arm/bus_space_generic.c standard
+arm/arm/bus_space_asm_generic.S standard
+arm/arm/cpufunc_asm_armv5.S standard
+arm/arm/cpufunc_asm_arm10.S standard
+arm/arm/cpufunc_asm_arm11.S standard
+arm/arm/cpufunc_asm_armv7.S standard
+arm/arm/irq_dispatch.S standard
+
+arm/ti/bus_space.c standard
+arm/ti/common.c standard
+arm/ti/ti_cpuid.c standard
+arm/ti/ti_machdep.c standard
+arm/ti/ti_prcm.c standard
+arm/ti/ti_scm.c standard
+
+arm/ti/ti_gpio.c optional gpio
+arm/ti/ti_i2c.c optional ti_i2c
+dev/ofw/ofw_iicbus.c optional iicbus
+
+dev/uart/uart_dev_ns8250.c optional uart
+
diff --git a/sys/arm/ti/omap3/omap3_reg.h b/sys/arm/ti/omap3/omap3_reg.h
new file mode 100644
index 0000000..3b4e2ea
--- /dev/null
+++ b/sys/arm/ti/omap3/omap3_reg.h
@@ -0,0 +1,780 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Texas Instruments - OMAP3xxx series processors
+ *
+ * Reference:
+ * OMAP35x Applications Processor
+ * Technical Reference Manual
+ * (omap35xx_techref.pdf)
+ *
+ *
+ * Note:
+ * The devices are mapped into address above 0xD000_0000 as the kernel space
+ * memory is at 0xC000_0000 and above. The first 256MB after this is reserved
+ * for the size of the kernel, everything above that is reserved for SoC
+ * devices.
+ *
+ */
+#ifndef _OMAP35XX_REG_H_
+#define _OMAP35XX_REG_H_
+
+#ifndef _LOCORE
+#include <sys/types.h> /* for uint32_t */
+#endif
+
+
+
+
+#define OMAP35XX_SDRAM0_START 0x80000000UL
+#define OMAP35XX_SDRAM1_START 0xA0000000UL
+#define OMAP35XX_SDRAM_BANKS 2
+#define OMAP35XX_SDRAM_BANK_SIZE 0x20000000UL
+
+
+/* Physical/Virtual address for SDRAM controller */
+
+#define OMAP35XX_SMS_VBASE 0x6C000000UL
+#define OMAP35XX_SMS_HWBASE 0x6C000000UL
+#define OMAP35XX_SMS_SIZE 0x01000000UL
+
+#define OMAP35XX_SDRC_VBASE 0x6D000000UL
+#define OMAP35XX_SDRC_HWBASE 0x6D000000UL
+#define OMAP35XX_SDRC_SIZE 0x01000000UL
+
+
+
+/* Physical/Virtual address for I/O space */
+
+#define OMAP35XX_L3_VBASE 0xD0000000UL
+#define OMAP35XX_L3_HWBASE 0x68000000UL
+#define OMAP35XX_L3_SIZE 0x01000000UL
+
+#define OMAP35XX_L4_CORE_VBASE 0xE8000000UL
+#define OMAP35XX_L4_CORE_HWBASE 0x48000000UL
+#define OMAP35XX_L4_CORE_SIZE 0x01000000UL
+
+#define OMAP35XX_L4_WAKEUP_VBASE 0xE8300000UL
+#define OMAP35XX_L4_WAKEUP_HWBASE 0x48300000UL
+#define OMAP35XX_L4_WAKEUP_SIZE 0x00040000UL
+
+#define OMAP35XX_L4_PERIPH_VBASE 0xE9000000UL
+#define OMAP35XX_L4_PERIPH_HWBASE 0x49000000UL
+#define OMAP35XX_L4_PERIPH_SIZE 0x00100000UL
+
+
+/*
+ * L4-CORE Physical/Virtual addresss offsets
+ */
+#define OMAP35XX_SCM_OFFSET 0x00002000UL
+#define OMAP35XX_CM_OFFSET 0x00004000UL
+#define OMAP35XX_SDMA_OFFSET 0x00056000UL
+#define OMAP35XX_I2C3_OFFSET 0x00060000UL
+#define OMAP35XX_USB_TLL_OFFSET 0x00062000UL
+#define OMAP35XX_USB_UHH_OFFSET 0x00064000UL
+#define OMAP35XX_USB_EHCI_OFFSET 0x00064800UL
+
+
+#define OMAP35XX_UART1_OFFSET 0x0006A000UL
+#define OMAP35XX_UART2_OFFSET 0x0006C000UL
+#define OMAP35XX_I2C1_OFFSET 0x00070000UL
+#define OMAP35XX_I2C2_OFFSET 0x00072000UL
+#define OMAP35XX_MCBSP1_OFFSET 0x00074000UL
+#define OMAP35XX_GPTIMER10_OFFSET 0x00086000UL
+#define OMAP35XX_GPTIMER11_OFFSET 0x00088000UL
+#define OMAP35XX_MCBSP5_OFFSET 0x00096000UL
+#define OMAP35XX_MMU1_OFFSET 0x000BD400UL
+#define OMAP35XX_INTCPS_OFFSET 0x00200000UL
+
+
+/*
+ * L4-WAKEUP Physical/Virtual addresss offsets
+ */
+#define OMAP35XX_PRM_OFFSET 0x00006000UL
+#define OMAP35XX_GPIO1_OFFSET 0x00010000UL
+#define OMAP35XX_GPTIMER1_OFFSET 0x00018000UL
+
+
+
+/*
+ * L4-PERIPH Physical/Virtual addresss offsets
+ */
+#define OMAP35XX_UART3_OFFSET 0x00020000UL
+#define OMAP35XX_MCBSP2_OFFSET 0x00022000UL
+#define OMAP35XX_MCBSP3_OFFSET 0x00024000UL
+#define OMAP35XX_MCBSP4_OFFSET 0x00026000UL
+#define OMAP35XX_SIDETONE_MCBSP2_OFFSET 0x00028000UL
+#define OMAP35XX_SIDETONE_MCBSP3_OFFSET 0x0002A000UL
+#define OMAP35XX_GPTIMER2_OFFSET 0x00032000UL
+#define OMAP35XX_GPTIMER3_OFFSET 0x00034000UL
+#define OMAP35XX_GPTIMER4_OFFSET 0x00036000UL
+#define OMAP35XX_GPTIMER5_OFFSET 0x00038000UL
+#define OMAP35XX_GPTIMER6_OFFSET 0x0003A000UL
+#define OMAP35XX_GPTIMER7_OFFSET 0x0003C000UL
+#define OMAP35XX_GPTIMER8_OFFSET 0x0003E000UL
+#define OMAP35XX_GPTIMER9_OFFSET 0x00040000UL
+#define OMAP35XX_GPIO2_OFFSET 0x00050000UL
+#define OMAP35XX_GPIO3_OFFSET 0x00052000UL
+#define OMAP35XX_GPIO4_OFFSET 0x00054000UL
+#define OMAP35XX_GPIO5_OFFSET 0x00056000UL
+#define OMAP35XX_GPIO6_OFFSET 0x00058000UL
+
+
+
+
+
+
+/*
+ * System Control Module
+ */
+#define OMAP35XX_SCM_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SCM_OFFSET)
+#define OMAP35XX_SCM_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_SCM_OFFSET)
+#define OMAP35XX_SCM_SIZE 0x00001000UL
+
+#define OMAP35XX_SCM_REVISION 0x00000000UL
+#define OMAP35XX_SCM_SYSCONFIG 0x00000010UL
+#define OMAP35XX_SCM_PADCONFS_BASE 0x00000030UL
+#define OMAP35XX_SCM_DEVCONF0 0x00000274UL
+#define OMAP35XX_SCM_MEM_DFTRW0 0x00000278UL
+
+
+
+
+/*
+ *
+ */
+#define OMAP35XX_CM_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_CM_OFFSET)
+#define OMAP35XX_CM_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_CM_OFFSET)
+#define OMAP35XX_CM_SIZE 0x00001500UL
+
+#define OMAP35XX_CM_CORE_OFFSET 0x00000A00UL
+#define OMAP35XX_CM_CORE_SIZE 0x00000100UL
+#define OMAP35XX_CM_FCLKEN1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_FCLKEN3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0008UL)
+#define OMAP35XX_CM_ICLKEN1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_ICLKEN2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0014UL)
+#define OMAP35XX_CM_ICLKEN3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0018UL)
+#define OMAP35XX_CM_IDLEST1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_IDLEST2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0024UL)
+#define OMAP35XX_CM_IDLEST3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0028UL)
+#define OMAP35XX_CM_AUTOIDLE1_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_AUTOIDLE2_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0034UL)
+#define OMAP35XX_CM_AUTOIDLE3_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0038UL)
+#define OMAP35XX_CM_CLKSEL_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_CLKSTCTRL_CORE (OMAP35XX_CM_CORE_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_CORE (OMAP35XX_CM_CORE_OFFSET + 0x004CUL)
+
+#define OMAP35XX_CM_WKUP_OFFSET 0x00000C00UL
+#define OMAP35XX_CM_WKUP_SIZE 0x00000100UL
+#define OMAP35XX_CM_FCLKEN_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_CLKSEL_WKUP (OMAP35XX_CM_WKUP_OFFSET + 0x0040UL)
+
+#define OMAP35XX_CM_PLL_OFFSET 0x00000D00UL
+#define OMAP35XX_CM_PLL_SIZE 0x00000100UL
+#define OMAP35XX_CM_CLKEN_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_CLKEN2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0004UL)
+#define OMAP35XX_CM_IDLEST_CKGEN (OMAP35XX_CM_PLL_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_IDLEST2_CKGEN (OMAP35XX_CM_PLL_OFFSET + 0x0024UL)
+#define OMAP35XX_CM_AUTOIDLE_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_AUTOIDLE2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0034UL)
+#define OMAP35XX_CM_CLKSEL1_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_CLKSEL2_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSEL3_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSEL4_PLL (OMAP35XX_CM_PLL_OFFSET + 0x004CUL)
+#define OMAP35XX_CM_CLKSEL5_PLL (OMAP35XX_CM_PLL_OFFSET + 0x0050UL)
+#define OMAP35XX_CM_CLKOUT_CTRL (OMAP35XX_CM_PLL_OFFSET + 0x0070UL)
+
+#define OMAP35XX_CM_PER_OFFSET 0x00001000UL
+#define OMAP35XX_CM_PER_SIZE 0x00000100UL
+#define OMAP35XX_CM_FCLKEN_PER (OMAP35XX_CM_PER_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_PER (OMAP35XX_CM_PER_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_PER (OMAP35XX_CM_PER_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_PER (OMAP35XX_CM_PER_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_CLKSEL_PER (OMAP35XX_CM_PER_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_SLEEPDEP_PER (OMAP35XX_CM_PER_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSTCTRL_PER (OMAP35XX_CM_PER_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_PER (OMAP35XX_CM_PER_OFFSET + 0x004CUL)
+
+#define OMAP35XX_CM_USBHOST_OFFSET 0x00001400UL
+#define OMAP35XX_CM_USBHOST_SIZE 0x00000100UL
+#define OMAP35XX_CM_FCLKEN_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_SLEEPDEP_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSTCTRL_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_USBHOST (OMAP35XX_CM_USBHOST_OFFSET + 0x004CUL)
+
+
+
+
+/*
+ *
+ */
+#define OMAP35XX_PRM_HWBASE (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_PRM_OFFSET)
+#define OMAP35XX_PRM_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_PRM_OFFSET)
+#define OMAP35XX_PRM_SIZE 0x00001600UL
+
+#define OMAP35XX_PRM_CLKCTRL_OFFSET 0x00000D00UL
+#define OMAP35XX_PRM_CLKCTRL_SIZE 0x00000100UL
+#define OMAP35XX_PRM_CLKSEL (OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0040UL)
+#define OMAP35XX_PRM_CLKOUT_CTRL (OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0070UL)
+
+#define OMAP35XX_PRM_GLOBAL_OFFSET 0x00001200UL
+#define OMAP35XX_PRM_GLOBAL_SIZE 0x00000100UL
+#define OMAP35XX_PRM_CLKSRC_CTRL (OMAP35XX_PRM_GLOBAL_OFFSET + 0x0070UL)
+
+
+
+
+
+/*
+ * Uarts
+ */
+#define OMAP35XX_UART1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART1_OFFSET)
+#define OMAP35XX_UART1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_UART1_OFFSET)
+#define OMAP35XX_UART1_SIZE 0x00001000UL
+
+#define OMAP35XX_UART2_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART2_OFFSET)
+#define OMAP35XX_UART2_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_UART2_OFFSET)
+#define OMAP35XX_UART2_SIZE 0x00001000UL
+
+#define OMAP35XX_UART3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_UART3_OFFSET)
+#define OMAP35XX_UART3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_UART3_OFFSET)
+#define OMAP35XX_UART3_SIZE 0x00001000UL
+
+
+
+
+/*
+ * I2C Modules
+ */
+#define OMAP35XX_I2C1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C1_OFFSET)
+#define OMAP35XX_I2C1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C1_OFFSET)
+#define OMAP35XX_I2C1_SIZE 0x00000080UL
+
+#define OMAP35XX_I2C2_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C2_OFFSET)
+#define OMAP35XX_I2C2_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C2_OFFSET)
+#define OMAP35XX_I2C2_SIZE 0x00000080UL
+
+#define OMAP35XX_I2C3_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C3_OFFSET)
+#define OMAP35XX_I2C3_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_I2C3_OFFSET)
+#define OMAP35XX_I2C3_SIZE 0x00000080UL
+
+#define OMAP35XX_I2C_IE 0x04
+#define OMAP35XX_I2C_STAT 0x08
+#define OMAP35XX_I2C_WE 0x0C
+#define OMAP35XX_I2C_SYSS 0x10
+#define OMAP35XX_I2C_BUF 0x14
+#define OMAP35XX_I2C_CNT 0x18
+#define OMAP35XX_I2C_DATA 0x1C
+#define OMAP35XX_I2C_SYSC 0x20
+#define OMAP35XX_I2C_CON 0x24
+#define OMAP35XX_I2C_OA0 0x28
+#define OMAP35XX_I2C_SA 0x2C
+#define OMAP35XX_I2C_PSC 0x30
+#define OMAP35XX_I2C_SCLL 0x34
+#define OMAP35XX_I2C_SCLH 0x38
+#define OMAP35XX_I2C_SYSTEST 0x3C
+#define OMAP35XX_I2C_BUFSTAT 0x40
+#define OMAP35XX_I2C_OA1 0x44
+#define OMAP35XX_I2C_OA2 0x48
+#define OMAP35XX_I2C_OA3 0x4C
+#define OMAP35XX_I2C_ACTOA 0x50
+#define OMAP35XX_I2C_SBLOCK 0x54
+
+
+
+/*
+ * McBSP Modules
+ */
+#define OMAP35XX_MCBSP1_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP1_OFFSET)
+#define OMAP35XX_MCBSP1_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_MCBSP1_OFFSET)
+#define OMAP35XX_MCBSP1_SIZE 0x00001000UL
+
+#define OMAP35XX_MCBSP2_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP2_OFFSET)
+#define OMAP35XX_MCBSP2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP2_OFFSET)
+#define OMAP35XX_MCBSP2_SIZE 0x00001000UL
+
+#define OMAP35XX_MCBSP3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP3_OFFSET)
+#define OMAP35XX_MCBSP3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP3_OFFSET)
+#define OMAP35XX_MCBSP3_SIZE 0x00001000UL
+
+#define OMAP35XX_MCBSP4_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP4_OFFSET)
+#define OMAP35XX_MCBSP4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_MCBSP4_OFFSET)
+#define OMAP35XX_MCBSP4_SIZE 0x00001000UL
+
+#define OMAP35XX_MCBSP5_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP5_OFFSET)
+#define OMAP35XX_MCBSP5_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_MCBSP5_OFFSET)
+#define OMAP35XX_MCBSP5_SIZE 0x00001000UL
+
+#define OMAP35XX_MCBSP_DRR 0x0000
+#define OMAP35XX_MCBSP_DXR 0x0008
+#define OMAP35XX_MCBSP_SPCR2 0x0010
+#define OMAP35XX_MCBSP_SPCR1 0x0014
+#define OMAP35XX_MCBSP_RCR2 0x0018
+#define OMAP35XX_MCBSP_RCR1 0x001C
+#define OMAP35XX_MCBSP_XCR2 0x0020
+#define OMAP35XX_MCBSP_XCR1 0x0024
+#define OMAP35XX_MCBSP_SRGR2 0x0028
+#define OMAP35XX_MCBSP_SRGR1 0x002C
+#define OMAP35XX_MCBSP_MCR2 0x0030
+#define OMAP35XX_MCBSP_MCR1 0x0034
+#define OMAP35XX_MCBSP_RCERA 0x0038
+#define OMAP35XX_MCBSP_RCERB 0x003C
+#define OMAP35XX_MCBSP_XCERA 0x0040
+#define OMAP35XX_MCBSP_XCERB 0x0044
+#define OMAP35XX_MCBSP_PCR 0x0048
+#define OMAP35XX_MCBSP_RCERC 0x004C
+#define OMAP35XX_MCBSP_RCERD 0x0050
+#define OMAP35XX_MCBSP_XCERC 0x0054
+#define OMAP35XX_MCBSP_XCERD 0x0058
+#define OMAP35XX_MCBSP_RCERE 0x005C
+#define OMAP35XX_MCBSP_RCERF 0x0060
+#define OMAP35XX_MCBSP_XCERE 0x0064
+#define OMAP35XX_MCBSP_XCERF 0x0068
+#define OMAP35XX_MCBSP_RCERG 0x006C
+#define OMAP35XX_MCBSP_RCERH 0x0070
+#define OMAP35XX_MCBSP_XCERG 0x0074
+#define OMAP35XX_MCBSP_XCERH 0x0078
+#define OMAP35XX_MCBSP_RINTCLR 0x0080
+#define OMAP35XX_MCBSP_XINTCLR 0x0084
+#define OMAP35XX_MCBSP_ROVFLCLR 0x0088
+#define OMAP35XX_MCBSP_SYSCONFIG 0x008C
+#define OMAP35XX_MCBSP_THRSH2 0x0090
+#define OMAP35XX_MCBSP_THRSH1 0x0094
+#define OMAP35XX_MCBSP_IRQSTATUS 0x00A0
+#define OMAP35XX_MCBSP_IRQENABLE 0x00A4
+#define OMAP35XX_MCBSP_WAKEUPEN 0x00A8
+#define OMAP35XX_MCBSP_XCCR 0x00AC
+#define OMAP35XX_MCBSP_RCCR 0x00B0
+#define OMAP35XX_MCBSP_XBUFFSTAT 0x00B4
+#define OMAP35XX_MCBSP_RBUFFSTAT 0x00B8
+#define OMAP35XX_MCBSP_SSELCR 0x00BC
+#define OMAP35XX_MCBSP_STATUS 0x00C0
+
+
+
+/*
+ * USB TTL Module
+ */
+#define OMAP35XX_USBTLL_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USBTLL_OFFSET)
+#define OMAP35XX_USBTLL_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USBTLL_OFFSET)
+#define OMAP35XX_USBTLL_SIZE 0x00001000UL
+
+#define OMAP35XX_USBTLL_REVISION 0x0000
+#define OMAP35XX_USBTLL_SYSCONFIG 0x0010
+#define OMAP35XX_USBTLL_SYSSTATUS 0x0014
+#define OMAP35XX_USBTLL_IRQSTATUS 0x0018
+#define OMAP35XX_USBTLL_IRQENABLE 0x001C
+#define OMAP35XX_USBTLL_TLL_SHARED_CONF 0x0030
+#define OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i)))
+#define OMAP35XX_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i)))
+
+
+/*
+ * USB Host Module
+ */
+#define OMAP35XX_USB_TLL_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_TLL_OFFSET)
+#define OMAP35XX_USB_TLL_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_TLL_OFFSET)
+#define OMAP35XX_USB_TLL_SIZE 0x00001000UL
+
+#define OMAP35XX_USB_EHCI_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_EHCI_OFFSET)
+#define OMAP35XX_USB_EHCI_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_EHCI_OFFSET)
+#define OMAP35XX_USB_EHCI_SIZE 0x00000400UL
+
+#define OMAP35XX_USB_UHH_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_UHH_OFFSET)
+#define OMAP35XX_USB_UHH_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_UHH_OFFSET)
+#define OMAP35XX_USB_UHH_SIZE 0x00000400UL
+
+
+
+
+
+/*
+ * SDRAM Controler (SDRC)
+ * PA 0x6D00_0000
+ */
+
+#define OMAP35XX_SDRC_SYSCONFIG (OMAP35XX_SDRC_VBASE + 0x10)
+#define OMAP35XX_SDRC_SYSSTATUS (OMAP35XX_SDRC_VBASE + 0x14)
+#define OMAP35XX_SDRC_CS_CFG (OMAP35XX_SDRC_VBASE + 0x40)
+#define OMAP35XX_SDRC_SHARING (OMAP35XX_SDRC_VBASE + 0x44)
+#define OMAP35XX_SDRC_ERR_ADDR (OMAP35XX_SDRC_VBASE + 0x48)
+#define OMAP35XX_SDRC_ERR_TYPE (OMAP35XX_SDRC_VBASE + 0x4C)
+#define OMAP35XX_SDRC_DLLA_CTRL (OMAP35XX_SDRC_VBASE + 0x60)
+#define OMAP35XX_SDRC_DLLA_STATUS (OMAP35XX_SDRC_VBASE + 0x64)
+#define OMAP35XX_SDRC_POWER_REG (OMAP35XX_SDRC_VBASE + 0x70)
+#define OMAP35XX_SDRC_MCFG(p) (OMAP35XX_SDRC_VBASE + 0x80 + (0x30 * (p)))
+#define OMAP35XX_SDRC_MR(p) (OMAP35XX_SDRC_VBASE + 0x84 + (0x30 * (p)))
+#define OMAP35XX_SDRC_EMR2(p) (OMAP35XX_SDRC_VBASE + 0x8C + (0x30 * (p)))
+#define OMAP35XX_SDRC_ACTIM_CTRLA(p) (OMAP35XX_SDRC_VBASE + 0x9C + (0x28 * (p)))
+#define OMAP35XX_SDRC_ACTIM_CTRLB(p) (OMAP35XX_SDRC_VBASE + 0xA0 + (0x28 * (p)))
+#define OMAP35XX_SDRC_RFR_CTRL(p) (OMAP35XX_SDRC_VBASE + 0xA4 + (0x30 * (p)))
+#define OMAP35XX_SDRC_MANUAL(p) (OMAP35XX_SDRC_VBASE + 0xA8 + (0x30 * (p)))
+
+
+/*
+ * SDMA Offset
+ * PA 0x4805 6000
+ */
+
+#define OMAP35XX_SDMA_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SDMA_OFFSET)
+#define OMAP35XX_SDMA_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_SDMA_OFFSET)
+#define OMAP35XX_SDMA_SIZE 0x00001000UL
+
+
+
+/*
+ * Interrupt Controller Unit.
+ * PA 0x4820_0000
+ */
+
+#define OMAP35XX_INTCPS_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_INTCPS_OFFSET)
+#define OMAP35XX_INTCPS_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_INTCPS_OFFSET)
+#define OMAP35XX_INTCPS_SIZE 0x00001000UL
+
+#define OMAP35XX_INTCPS_SYSCONFIG (OMAP35XX_INTCPS_VBASE + 0x10)
+#define OMAP35XX_INTCPS_SYSSTATUS (OMAP35XX_INTCPS_VBASE + 0x14)
+#define OMAP35XX_INTCPS_SIR_IRQ (OMAP35XX_INTCPS_VBASE + 0x40)
+#define OMAP35XX_INTCPS_SIR_FIQ (OMAP35XX_INTCPS_VBASE + 0x44)
+#define OMAP35XX_INTCPS_CONTROL (OMAP35XX_INTCPS_VBASE + 0x48)
+#define OMAP35XX_INTCPS_PROTECTION (OMAP35XX_INTCPS_VBASE + 0x4C)
+#define OMAP35XX_INTCPS_IDLE (OMAP35XX_INTCPS_VBASE + 0x50)
+#define OMAP35XX_INTCPS_IRQ_PRIORITY (OMAP35XX_INTCPS_VBASE + 0x60)
+#define OMAP35XX_INTCPS_FIQ_PRIORITY (OMAP35XX_INTCPS_VBASE + 0x64)
+#define OMAP35XX_INTCPS_THRESHOLD (OMAP35XX_INTCPS_VBASE + 0x68)
+#define OMAP35XX_INTCPS_ITR(n) (OMAP35XX_INTCPS_VBASE + 0x80 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR(n) (OMAP35XX_INTCPS_VBASE + 0x84 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR_CLEAR(n) (OMAP35XX_INTCPS_VBASE + 0x88 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR_SET(n) (OMAP35XX_INTCPS_VBASE + 0x8C + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ISR_SET(n) (OMAP35XX_INTCPS_VBASE + 0x90 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ISR_CLEAR(n) (OMAP35XX_INTCPS_VBASE + 0x94 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_PENDING_IRQ(n) (OMAP35XX_INTCPS_VBASE + 0x98 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_PENDING_FIQ(n) (OMAP35XX_INTCPS_VBASE + 0x9C + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ILR(m) (OMAP35XX_INTCPS_VBASE + 0x100 + (0x4 * (m)))
+
+
+#define OMAP35XX_IRQ_EMUINT 0 /* MPU emulation(2) */
+#define OMAP35XX_IRQ_COMMTX 1 /* MPU emulation(2) */
+#define OMAP35XX_IRQ_COMMRX 2 /* MPU emulation(2) */
+#define OMAP35XX_IRQ_BENCH 3 /* MPU emulation(2) */
+#define OMAP35XX_IRQ_MCBSP2_ST 4 /* Sidetone MCBSP2 overflow */
+#define OMAP35XX_IRQ_MCBSP3_ST 5 /* Sidetone MCBSP3 overflow */
+#define OMAP35XX_IRQ_SSM_ABORT 6 /* MPU subsystem secure state-machine abort (2) */
+#define OMAP35XX_IRQ_SYS_NIRQ 7 /* External source (active low) */
+#define OMAP35XX_IRQ_RESERVED8 8 /* RESERVED */
+#define OMAP35XX_IRQ_SMX_DBG 9 /* SMX error for debug */
+#define OMAP35XX_IRQ_SMX_APP 10 /* SMX error for application */
+#define OMAP35XX_IRQ_PRCM_MPU 11 /* PRCM module IRQ */
+#define OMAP35XX_IRQ_SDMA0 12 /* System DMA request 0(3) */
+#define OMAP35XX_IRQ_SDMA1 13 /* System DMA request 1(3) */
+#define OMAP35XX_IRQ_SDMA2 14 /* System DMA request 2 */
+#define OMAP35XX_IRQ_SDMA3 15 /* System DMA request 3 */
+#define OMAP35XX_IRQ_MCBSP1 16 /* McBSP module 1 IRQ (3) */
+#define OMAP35XX_IRQ_MCBSP2 17 /* McBSP module 2 IRQ (3) */
+#define OMAP35XX_IRQ_SR1 18 /* SmartReflexâ„¢ 1 */
+#define OMAP35XX_IRQ_SR2 19 /* SmartReflexâ„¢ 2 */
+#define OMAP35XX_IRQ_GPMC 20 /* General-purpose memory controller module */
+#define OMAP35XX_IRQ_SGX 21 /* 2D/3D graphics module */
+#define OMAP35XX_IRQ_MCBSP3 22 /* McBSP module 3(3) */
+#define OMAP35XX_IRQ_MCBSP4 23 /* McBSP module 4(3) */
+#define OMAP35XX_IRQ_CAM0 24 /* Camera interface request 0 */
+#define OMAP35XX_IRQ_DSS 25 /* Display subsystem module(3) */
+#define OMAP35XX_IRQ_MAIL_U0 26 /* Mailbox user 0 request */
+#define OMAP35XX_IRQ_MCBSP5_IRQ1 27 /* McBSP module 5 (3) */
+#define OMAP35XX_IRQ_IVA2_MMU 28 /* IVA2 MMU */
+#define OMAP35XX_IRQ_GPIO1_MPU 29 /* GPIO module 1(3) */
+#define OMAP35XX_IRQ_GPIO2_MPU 30 /* GPIO module 2(3) */
+#define OMAP35XX_IRQ_GPIO3_MPU 31 /* GPIO module 3(3) */
+#define OMAP35XX_IRQ_GPIO4_MPU 32 /* GPIO module 4(3) */
+#define OMAP35XX_IRQ_GPIO5_MPU 33 /* GPIO module 5(3) */
+#define OMAP35XX_IRQ_GPIO6_MPU 34 /* GPIO module 6(3) */
+#define OMAP35XX_IRQ_USIM 35 /* USIM interrupt (HS devices only) (4) */
+#define OMAP35XX_IRQ_WDT3 36 /* Watchdog timer module 3 overflow */
+#define OMAP35XX_IRQ_GPT1 37 /* General-purpose timer module 1 */
+#define OMAP35XX_IRQ_GPT2 38 /* General-purpose timer module 2 */
+#define OMAP35XX_IRQ_GPT3 39 /* General-purpose timer module 3 */
+#define OMAP35XX_IRQ_GPT4 40 /* General-purpose timer module 4 */
+#define OMAP35XX_IRQ_GPT5 41 /* General-purpose timer module 5(3) */
+#define OMAP35XX_IRQ_GPT6 42 /* General-purpose timer module 6(3) */
+#define OMAP35XX_IRQ_GPT7 43 /* General-purpose timer module 7(3) */
+#define OMAP35XX_IRQ_GPT8 44 /* General-purpose timer module 8(3) */
+#define OMAP35XX_IRQ_GPT9 45 /* General-purpose timer module 9 */
+#define OMAP35XX_IRQ_GPT10 46 /* General-purpose timer module 10 */
+#define OMAP35XX_IRQ_GPT11 47 /* General-purpose timer module 11 */
+#define OMAP35XX_IRQ_SPI4 48 /* McSPI module 4 */
+#define OMAP35XX_IRQ_SHA1MD5_2 49 /* SHA-1/MD5 crypto-accelerator 2 (HS devices only)(4) */
+#define OMAP35XX_IRQ_FPKA_IRQREADY_N 50 /* PKA crypto-accelerator (HS devices only) (4) */
+#define OMAP35XX_IRQ_SHA2MD5 51 /* SHA-2/MD5 crypto-accelerator 1 (HS devices only) (4) */
+#define OMAP35XX_IRQ_RNG 52 /* RNG module (HS devices only) (4) */
+#define OMAP35XX_IRQ_MG 53 /* MG function (3) */
+#define OMAP35XX_IRQ_MCBSP4_TX 54 /* McBSP module 4 transmit(3) */
+#define OMAP35XX_IRQ_MCBSP4_RX 55 /* McBSP module 4 receive(3) */
+#define OMAP35XX_IRQ_I2C1 56 /* I2C module 1 */
+#define OMAP35XX_IRQ_I2C2 57 /* I2C module 2 */
+#define OMAP35XX_IRQ_HDQ 58 /* HDQ / One-wire */
+#define OMAP35XX_IRQ_MCBSP1_TX 59 /* McBSP module 1 transmit(3) */
+#define OMAP35XX_IRQ_MCBSP1_RX 60 /* McBSP module 1 receive(3) */
+#define OMAP35XX_IRQ_I2C3 61 /* I2C module 3 */
+#define OMAP35XX_IRQ_McBSP2_TX 62 /* McBSP module 2 transmit(3) */
+#define OMAP35XX_IRQ_McBSP2_RX 63 /* McBSP module 2 receive(3) */
+#define OMAP35XX_IRQ_FPKA_IRQRERROR_N 64 /* PKA crypto-accelerator (HS devices only) (4) */
+#define OMAP35XX_IRQ_SPI1 65 /* McSPI module 1 */
+#define OMAP35XX_IRQ_SPI2 66 /* McSPI module 2 */
+#define OMAP35XX_IRQ_RESERVED67 67 /* RESERVED */
+#define OMAP35XX_IRQ_RESERVED68 68 /* RESERVED */
+#define OMAP35XX_IRQ_RESERVED69 69 /* RESERVED */
+#define OMAP35XX_IRQ_RESERVED70 70 /* RESERVED */
+#define OMAP35XX_IRQ_RESERVED71 71 /* RESERVED */
+#define OMAP35XX_IRQ_UART1 72 /* UART module 1 */
+#define OMAP35XX_IRQ_UART2 73 /* UART module 2 */
+#define OMAP35XX_IRQ_UART3 74 /* UART module 3 (also infrared)(3) */
+#define OMAP35XX_IRQ_PBIAS 75 /* Merged interrupt for PBIASlite1 and 2 */
+#define OMAP35XX_IRQ_OHCI 76 /* OHCI controller HSUSB MP Host Interrupt */
+#define OMAP35XX_IRQ_EHCI 77 /* EHCI controller HSUSB MP Host Interrupt */
+#define OMAP35XX_IRQ_TLL 78 /* HSUSB MP TLL Interrupt */
+#define OMAP35XX_IRQ_PARTHASH 79 /* SHA2/MD5 crypto-accelerator 1 (HS devices only) (4) */
+#define OMAP35XX_IRQ_RESERVED80 80 /* Reserved */
+#define OMAP35XX_IRQ_MCBSP5_TX 81 /* McBSP module 5 transmit(3) */
+#define OMAP35XX_IRQ_MCBSP5_RX 82 /* McBSP module 5 receive(3) */
+#define OMAP35XX_IRQ_MMC1 83 /* MMC/SD module 1 */
+#define OMAP35XX_IRQ_MS 84 /* MS-PROâ„¢ module */
+#define OMAP35XX_IRQ_RESERVED85 85 /* Reserved */
+#define OMAP35XX_IRQ_MMC2 86 /* MMC/SD module 2 */
+#define OMAP35XX_IRQ_MPU_ICR 87 /* MPU ICR */
+#define OMAP35XX_IRQ_RESERVED 88 /* RESERVED */
+#define OMAP35XX_IRQ_MCBSP3_TX 89 /* McBSP module 3 transmit(3) */
+#define OMAP35XX_IRQ_MCBSP3_RX 90 /* McBSP module 3 receive(3) */
+#define OMAP35XX_IRQ_SPI3 91 /* McSPI module 3 */
+#define OMAP35XX_IRQ_HSUSB_MC_NINT 92 /* High-Speed USB OTG controller */
+#define OMAP35XX_IRQ_HSUSB_DMA_NINT 93 /* High-Speed USB OTG DMA controller */
+#define OMAP35XX_IRQ_MMC3 94 /* MMC/SD module 3 */
+#define OMAP35XX_IRQ_GPT12 95 /* General-purpose timer module 12 */
+
+
+
+
+/*
+ * General Purpose Timers
+ */
+#define OMAP35XX_GPTIMER1_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_GPTIMER1_OFFSET)
+#define OMAP35XX_GPTIMER1_HWBASE (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_GPTIMER1_OFFSET)
+#define OMAP35XX_GPTIMER2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER2_OFFSET)
+#define OMAP35XX_GPTIMER2_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER2_OFFSET)
+#define OMAP35XX_GPTIMER3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER3_OFFSET)
+#define OMAP35XX_GPTIMER3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER3_OFFSET)
+#define OMAP35XX_GPTIMER4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER4_OFFSET)
+#define OMAP35XX_GPTIMER4_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER4_OFFSET)
+#define OMAP35XX_GPTIMER5_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER5_OFFSET)
+#define OMAP35XX_GPTIMER5_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER5_OFFSET)
+#define OMAP35XX_GPTIMER6_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER6_OFFSET)
+#define OMAP35XX_GPTIMER6_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER6_OFFSET)
+#define OMAP35XX_GPTIMER7_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER7_OFFSET)
+#define OMAP35XX_GPTIMER7_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER7_OFFSET)
+#define OMAP35XX_GPTIMER8_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER8_OFFSET)
+#define OMAP35XX_GPTIMER8_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER8_OFFSET)
+#define OMAP35XX_GPTIMER9_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER9_OFFSET)
+#define OMAP35XX_GPTIMER9_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER9_OFFSET)
+#define OMAP35XX_GPTIMER10_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER10_OFFSET)
+#define OMAP35XX_GPTIMER10_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER10_OFFSET)
+#define OMAP35XX_GPTIMER11_VBASE (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER11_OFFSET)
+#define OMAP35XX_GPTIMER11_HWBASE (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER11_OFFSET)
+#define OMAP35XX_GPTIMER12_VBASE 0x48304000UL /* GPTIMER12 */
+#define OMAP35XX_GPTIMER_SIZE 0x00001000UL
+
+
+
+/* Timer register offsets */
+#define OMAP35XX_GPTIMER_TIOCP_CFG 0x010
+#define OMAP35XX_GPTIMER_TISTAT 0x014
+#define OMAP35XX_GPTIMER_TISR 0x018
+#define OMAP35XX_GPTIMER_TIER 0x01C
+#define OMAP35XX_GPTIMER_TWER 0x020
+#define OMAP35XX_GPTIMER_TCLR 0x024
+#define OMAP35XX_GPTIMER_TCRR 0x028
+#define OMAP35XX_GPTIMER_TLDR 0x02C
+#define OMAP35XX_GPTIMER_TTGR 0x030
+#define OMAP35XX_GPTIMER_TWPS 0x034
+#define OMAP35XX_GPTIMER_TMAR 0x038
+#define OMAP35XX_GPTIMER_TCAR1 0x03C
+#define OMAP35XX_GPTIMER_TSICR 0x040
+#define OMAP35XX_GPTIMER_TCAR2 0x044
+#define OMAP35XX_GPTIMER_TPIR 0x048
+#define OMAP35XX_GPTIMER_TNIR 0x04C
+#define OMAP35XX_GPTIMER_TCVR 0x050
+#define OMAP35XX_GPTIMER_TOCR 0x054
+#define OMAP35XX_GPTIMER_TOWR 0x058
+
+/* Bit values */
+#define MAT_IT_FLAG 0x01
+#define OVF_IT_FLAG 0x02
+#define TCAR_IT_FLAG 0x04
+
+
+
+/*
+ * GPIO - General Purpose IO
+ */
+
+/* Base addresses for the GPIO modules */
+#define OMAP35XX_GPIO1_HWBASE (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_GPIO1_OFFSET)
+#define OMAP35XX_GPIO1_VBASE (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_GPIO1_OFFSET)
+#define OMAP35XX_GPIO1_SIZE 0x00001000UL
+#define OMAP35XX_GPIO2_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO2_OFFSET)
+#define OMAP35XX_GPIO2_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO2_OFFSET)
+#define OMAP35XX_GPIO2_SIZE 0x00001000UL
+#define OMAP35XX_GPIO3_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO3_OFFSET)
+#define OMAP35XX_GPIO3_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO3_OFFSET)
+#define OMAP35XX_GPIO3_SIZE 0x00001000UL
+#define OMAP35XX_GPIO4_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO4_OFFSET)
+#define OMAP35XX_GPIO4_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO4_OFFSET)
+#define OMAP35XX_GPIO4_SIZE 0x00001000UL
+#define OMAP35XX_GPIO5_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO5_OFFSET)
+#define OMAP35XX_GPIO5_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO5_OFFSET)
+#define OMAP35XX_GPIO5_SIZE 0x00001000UL
+#define OMAP35XX_GPIO6_HWBASE (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO6_OFFSET)
+#define OMAP35XX_GPIO6_VBASE (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPIO6_OFFSET)
+#define OMAP35XX_GPIO6_SIZE 0x00001000UL
+
+
+
+/* Register offsets within the banks above */
+#define OMAP35XX_GPIO_SYSCONFIG 0x010
+#define OMAP35XX_GPIO_SYSSTATUS 0x014
+#define OMAP35XX_GPIO_IRQSTATUS1 0x018
+#define OMAP35XX_GPIO_IRQENABLE1 0x01C
+#define OMAP35XX_GPIO_WAKEUPENABLE 0x020
+#define OMAP35XX_GPIO_IRQSTATUS2 0x028
+#define OMAP35XX_GPIO_IRQENABLE2 0x02C
+#define OMAP35XX_GPIO_CTRL 0x030
+#define OMAP35XX_GPIO_OE 0x034
+#define OMAP35XX_GPIO_DATAIN 0x038
+#define OMAP35XX_GPIO_DATAOUT 0x03C
+#define OMAP35XX_GPIO_LEVELDETECT0 0x040
+#define OMAP35XX_GPIO_LEVELDETECT1 0x044
+#define OMAP35XX_GPIO_RISINGDETECT 0x048
+#define OMAP35XX_GPIO_FALLINGDETECT 0x04C
+#define OMAP35XX_GPIO_DEBOUNCENABLE 0x050
+#define OMAP35XX_GPIO_DEBOUNCINGTIME 0x054
+#define OMAP35XX_GPIO_CLEARIRQENABLE1 0x060
+#define OMAP35XX_GPIO_SETIRQENABLE1 0x064
+#define OMAP35XX_GPIO_CLEARIRQENABLE2 0x070
+#define OMAP35XX_GPIO_SETIRQENABLE2 0x074
+#define OMAP35XX_GPIO_CLEARWKUENA 0x080
+#define OMAP35XX_GPIO_SETWKUENA 0x084
+#define OMAP35XX_GPIO_CLEARDATAOUT 0x090
+#define OMAP35XX_GPIO_SETDATAOUT 0x094
+
+
+/*
+ * MMC/SD/SDIO
+ */
+
+/* Base addresses for the MMC/SD/SDIO modules */
+#define OMAP35XX_MMCHS1_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x0009C000)
+#define OMAP35XX_MMCHS1_VBASE (OMAP35XX_L4_CORE_VBASE + 0x0009C000)
+#define OMAP35XX_MMCHS2_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x000B4000)
+#define OMAP35XX_MMCHS2_VBASE (OMAP35XX_L4_CORE_VBASE + 0x000B4000)
+#define OMAP35XX_MMCHS3_HWBASE (OMAP35XX_L4_CORE_HWBASE + 0x000AD000)
+#define OMAP35XX_MMCHS3_VBASE (OMAP35XX_L4_CORE_VBASE + 0x000AD000)
+#define OMAP35XX_MMCHS_SIZE 0x00000200UL
+
+/* Register offsets within each of the MMC/SD/SDIO controllers */
+#define OMAP35XX_MMCHS_SYSCONFIG 0x010
+#define OMAP35XX_MMCHS_SYSSTATUS 0x014
+#define OMAP35XX_MMCHS_CSRE 0x024
+#define OMAP35XX_MMCHS_SYSTEST 0x028
+#define OMAP35XX_MMCHS_CON 0x02C
+#define OMAP35XX_MMCHS_PWCNT 0x030
+#define OMAP35XX_MMCHS_BLK 0x104
+#define OMAP35XX_MMCHS_ARG 0x108
+#define OMAP35XX_MMCHS_CMD 0x10C
+#define OMAP35XX_MMCHS_RSP10 0x110
+#define OMAP35XX_MMCHS_RSP32 0x114
+#define OMAP35XX_MMCHS_RSP54 0x118
+#define OMAP35XX_MMCHS_RSP76 0x11C
+#define OMAP35XX_MMCHS_DATA 0x120
+#define OMAP35XX_MMCHS_PSTATE 0x124
+#define OMAP35XX_MMCHS_HCTL 0x128
+#define OMAP35XX_MMCHS_SYSCTL 0x12C
+#define OMAP35XX_MMCHS_STAT 0x130
+#define OMAP35XX_MMCHS_IE 0x134
+#define OMAP35XX_MMCHS_ISE 0x138
+#define OMAP35XX_MMCHS_AC12 0x13C
+#define OMAP35XX_MMCHS_CAPA 0x140
+#define OMAP35XX_MMCHS_CUR_CAPA 0x148
+#define OMAP35XX_MMCHS_REV 0x1FC
+
+
+
+#endif /* _OMAP35XX_REG_H_ */
diff --git a/sys/arm/ti/omap4/files.omap4 b/sys/arm/ti/omap4/files.omap4
new file mode 100644
index 0000000..d9c043d
--- /dev/null
+++ b/sys/arm/ti/omap4/files.omap4
@@ -0,0 +1,19 @@
+#$FreeBSD$
+
+arm/arm/gic.c standard
+arm/arm/mpcore_timer.c standard
+arm/ti/ti_smc.S standard
+
+arm/ti/usb/omap_ehci.c optional usb ehci
+arm/ti/ti_sdma.c optional ti_sdma
+arm/ti/ti_mmchs.c optional mmc
+
+arm/ti/omap4/omap4_l2cache.c optional pl310
+arm/ti/omap4/omap4_prcm_clks.c standard
+arm/ti/omap4/omap4_scm_padconf.c standard
+arm/ti/omap4/omap4_mp.c optional smp
+
+arm/ti/twl/twl.c optional twl
+arm/ti/twl/twl_vreg.c optional twl twl_vreg
+arm/ti/twl/twl_clks.c optional twl twl_clks
+
diff --git a/sys/arm/ti/omap4/omap4_l2cache.c b/sys/arm/ti/omap4/omap4_l2cache.c
new file mode 100644
index 0000000..b663a1a
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_l2cache.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <arm/ti/ti_smc.h>
+#include <arm/ti/omap4/omap4_smc.h>
+#include <machine/pl310.h>
+
+void
+platform_init_pl310(struct pl310_softc *softc)
+{
+ ti_smc0(1, 0, L2CACHE_ENABLE_L2);
+}
+
diff --git a/sys/arm/ti/omap4/omap4_mp.c b/sys/arm/ti/omap4/omap4_mp.c
new file mode 100644
index 0000000..abb0d88
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_mp.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <machine/smp.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+
+#include <arm/ti/ti_smc.h>
+#include <arm/ti/omap4/omap4_smc.h>
+
+void mpentry(void);
+void mptramp(void);
+
+void
+platform_mp_init_secondary(void)
+{
+ gic_init_secondary();
+}
+
+void
+platform_mp_setmaxid(void)
+{
+
+ mp_maxid = 1;
+}
+
+int
+platform_mp_probe(void)
+{
+
+ mp_ncpus = 2;
+ return (1);
+}
+
+void
+platform_mp_start_ap(void)
+{
+ bus_addr_t scu_addr;
+
+ if (bus_space_map(fdtbus_bs_tag, 0x48240000, 0x1000, 0, &scu_addr) != 0)
+ panic("Couldn't map the SCU\n");
+ /* Enable the SCU */
+ *(volatile unsigned int *)scu_addr |= 1;
+ //*(volatile unsigned int *)(scu_addr + 0x30) |= 1;
+ cpu_idcache_wbinv_all();
+ cpu_l2cache_wbinv_all();
+ ti_smc0(0x200, 0xfffffdff, MODIFY_AUX_CORE_0);
+ ti_smc0(pmap_kextract(mpentry), 0, WRITE_AUX_CORE_1);
+ armv7_sev();
+ bus_space_unmap(fdtbus_bs_tag, scu_addr, 0x1000);
+}
+
+void
+platform_ipi_send(cpuset_t cpus, u_int ipi)
+{
+ pic_ipi_send(cpus, ipi);
+}
diff --git a/sys/arm/ti/omap4/omap4_prcm_clks.c b/sys/arm/ti/omap4/omap4_prcm_clks.c
new file mode 100644
index 0000000..a4cd41c
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_prcm_clks.c
@@ -0,0 +1,1418 @@
+/*-
+ * 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.
+ * 3. 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.
+ */
+
+#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 <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+/*
+ * This file defines the clock configuration for the OMAP4xxx series of
+ * devices.
+ *
+ * How This is Suppose to Work
+ * ===========================
+ * - There is a top level omap_prcm module that defines all OMAP SoC drivers
+ * should use to enable/disable the system clocks regardless of the version
+ * of OMAP device they are running on. This top level PRCM module is just
+ * a thin shim to chip specific functions that perform the donkey work of
+ * configuring the clock - this file is the 'donkey' for OMAP44xx devices.
+ *
+ * - The key bit in this file is the omap_clk_devmap array, it's
+ * used by the omap_prcm driver to determine what clocks are valid and which
+ * functions to call to manipulate them.
+ *
+ * - In essence you just need to define some callbacks for each of the
+ * clocks and then you're done.
+ *
+ * - The other thing that is worth noting is that when the omap_prcm device
+ * is registered you typically pass in some memory ranges which are the
+ * SYS_MEMORY resources. These resources are in turn allocated using
+ * bus_allocate_resources(...) and the resource handles are passed to all
+ * individual clock callback handlers.
+ *
+ *
+ *
+ * OMAP4 devices are different from the previous OMAP3 devices in that there
+ * is no longer a separate functional and interface clock for each module,
+ * instead there is typically an interface clock that spans many modules.
+ *
+ */
+
+#define FREQ_96MHZ 96000000
+#define FREQ_64MHZ 64000000
+#define FREQ_48MHZ 48000000
+#define FREQ_32KHZ 32000
+
+/**
+ * We need three memory regions to cover all the clock configuration registers.
+ *
+ * PRM Instance - 0x4A30 6000 : 0x4A30 8000
+ * CM1 Instance - 0x4A00 4000 : 0x4A00 5000
+ * CM2 Instance - 0x4A00 8000 : 0x4A00 A000
+ *
+ */
+#define PRM_INSTANCE_MEM_REGION 0
+#define CM1_INSTANCE_MEM_REGION 1
+#define CM2_INSTANCE_MEM_REGION 2
+
+/**
+ * Address offsets from the PRM memory region to the top level clock control
+ * registers.
+ */
+#define CKGEN_PRM_OFFSET 0x00000100UL
+#define MPU_PRM_OFFSET 0x00000300UL
+#define DSP_PRM_OFFSET 0x00000400UL
+#define ABE_PRM_OFFSET 0x00000500UL
+#define ALWAYS_ON_PRM_OFFSET 0x00000600UL
+#define CORE_PRM_OFFSET 0x00000700UL
+#define IVAHD_PRM_OFFSET 0x00000F00UL
+#define CAM_PRM_OFFSET 0x00001000UL
+#define DSS_PRM_OFFSET 0x00001100UL
+#define SGX_PRM_OFFSET 0x00001200UL
+#define L3INIT_PRM_OFFSET 0x00001300UL
+#define L4PER_PRM_OFFSET 0x00001400UL
+#define WKUP_PRM_OFFSET 0x00001700UL
+#define WKUP_CM_OFFSET 0x00001800UL
+#define EMU_PRM_OFFSET 0x00001900UL
+#define EMU_CM_OFFSET 0x00001A00UL
+#define DEVICE_PRM_OFFSET 0x00001B00UL
+#define INSTR_PRM_OFFSET 0x00001F00UL
+
+#define CM_ABE_DSS_SYS_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x0000UL)
+#define CM_L4_WKUP_CLKSELL_OFFSET (CKGEN_PRM_OFFSET + 0x0008UL)
+#define CM_ABE_PLL_REF_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x000CUL)
+#define CM_SYS_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x0010UL)
+
+/**
+ * Address offsets from the CM1 memory region to the top level clock control
+ * registers.
+ */
+#define CKGEN_CM1_OFFSET 0x00000100UL
+#define MPU_CM1_OFFSET 0x00000300UL
+#define DSP_CM1_OFFSET 0x00000400UL
+#define ABE_CM1_OFFSET 0x00000500UL
+#define RESTORE_CM1_OFFSET 0x00000E00UL
+#define INSTR_CM1_OFFSET 0x00000F00UL
+
+#define CM_CLKSEL_DPLL_MPU (CKGEN_CM1_OFFSET + 0x006CUL)
+
+/**
+ * Address offsets from the CM2 memory region to the top level clock control
+ * registers.
+ */
+#define INTRCONN_SOCKET_CM2_OFFSET 0x00000000UL
+#define CKGEN_CM2_OFFSET 0x00000100UL
+#define ALWAYS_ON_CM2_OFFSET 0x00000600UL
+#define CORE_CM2_OFFSET 0x00000700UL
+#define IVAHD_CM2_OFFSET 0x00000F00UL
+#define CAM_CM2_OFFSET 0x00001000UL
+#define DSS_CM2_OFFSET 0x00001100UL
+#define SGX_CM2_OFFSET 0x00001200UL
+#define L3INIT_CM2_OFFSET 0x00001300UL
+#define L4PER_CM2_OFFSET 0x00001400UL
+#define RESTORE_CM2_OFFSET 0x00001E00UL
+#define INSTR_CM2_OFFSET 0x00001F00UL
+
+#define CLKCTRL_MODULEMODE_MASK 0x00000003UL
+#define CLKCTRL_MODULEMODE_DISABLE 0x00000000UL
+#define CLKCTRL_MODULEMODE_AUTO 0x00000001UL
+#define CLKCTRL_MODULEMODE_ENABLE 0x00000001UL
+
+#define CLKCTRL_IDLEST_MASK 0x00030000UL
+#define CLKCTRL_IDLEST_ENABLED 0x00000000UL
+#define CLKCTRL_IDLEST_WAKING 0x00010000UL
+#define CLKCTRL_IDLEST_IDLE 0x00020000UL
+#define CLKCTRL_IDLEST_DISABLED 0x00030000UL
+
+static struct resource_spec omap4_scm_res_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */
+ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* Control memory window */
+ { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Control memory window */
+ { -1, 0 }
+};
+
+struct omap4_prcm_softc {
+ struct resource *sc_res[3];
+};
+
+static struct omap4_prcm_softc *omap4_prcm_sc;
+
+static int omap4_clk_generic_activate(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_accessible(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev);
+static int omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev);
+static int omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev);
+
+static int omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+/**
+ * omap_clk_devmap - Array of clock devices available on OMAP4xxx devices
+ *
+ * This map only defines which clocks are valid and the callback functions
+ * for clock activate, deactivate, etc. It is used by the top level omap_prcm
+ * driver.
+ *
+ * The actual details of the clocks (config registers, bit fields, sources,
+ * etc) are in the private g_omap3_clk_details array below.
+ *
+ */
+
+#define OMAP4_GENERIC_CLOCK_DEV(i) \
+ { .id = (i), \
+ .clk_activate = omap4_clk_generic_activate, \
+ .clk_deactivate = omap4_clk_generic_deactivate, \
+ .clk_set_source = omap4_clk_generic_set_source, \
+ .clk_accessible = omap4_clk_generic_accessible, \
+ .clk_get_source_freq = omap4_clk_generic_get_source_freq \
+ }
+
+#define OMAP4_GPTIMER_CLOCK_DEV(i) \
+ { .id = (i), \
+ .clk_activate = omap4_clk_generic_activate, \
+ .clk_deactivate = omap4_clk_generic_deactivate, \
+ .clk_set_source = omap4_clk_gptimer_set_source, \
+ .clk_accessible = omap4_clk_generic_accessible, \
+ .clk_get_source_freq = omap4_clk_gptimer_get_source_freq \
+ }
+
+#define OMAP4_HSMMC_CLOCK_DEV(i) \
+ { .id = (i), \
+ .clk_activate = omap4_clk_generic_activate, \
+ .clk_deactivate = omap4_clk_generic_deactivate, \
+ .clk_set_source = omap4_clk_hsmmc_set_source, \
+ .clk_accessible = omap4_clk_generic_accessible, \
+ .clk_get_source_freq = omap4_clk_hsmmc_get_source_freq \
+ }
+
+#define OMAP4_HSUSBHOST_CLOCK_DEV(i) \
+ { .id = (i), \
+ .clk_activate = omap4_clk_hsusbhost_activate, \
+ .clk_deactivate = omap4_clk_hsusbhost_deactivate, \
+ .clk_set_source = omap4_clk_hsusbhost_set_source, \
+ .clk_accessible = omap4_clk_hsusbhost_accessible, \
+ .clk_get_source_freq = NULL \
+ }
+
+
+struct ti_clock_dev ti_clk_devmap[] = {
+
+ /* System clocks */
+ { .id = SYS_CLK,
+ .clk_activate = NULL,
+ .clk_deactivate = NULL,
+ .clk_set_source = NULL,
+ .clk_accessible = NULL,
+ .clk_get_source_freq = omap4_clk_get_sysclk_freq,
+ },
+ /* MPU (ARM) core clocks */
+ { .id = MPU_CLK,
+ .clk_activate = NULL,
+ .clk_deactivate = NULL,
+ .clk_set_source = NULL,
+ .clk_accessible = NULL,
+ .clk_get_source_freq = omap4_clk_get_arm_fclk_freq,
+ },
+
+
+ /* UART device clocks */
+ OMAP4_GENERIC_CLOCK_DEV(UART1_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(UART2_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(UART3_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(UART4_CLK),
+
+ /* Timer device source clocks */
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER1_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER2_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER3_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER4_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER5_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER6_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER7_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER8_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER9_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER10_CLK),
+ OMAP4_GPTIMER_CLOCK_DEV(GPTIMER11_CLK),
+
+ /* MMC device clocks (MMC1 and MMC2 can have different input clocks) */
+ OMAP4_HSMMC_CLOCK_DEV(MMC1_CLK),
+ OMAP4_HSMMC_CLOCK_DEV(MMC2_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(MMC3_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(MMC4_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(MMC5_CLK),
+
+ /* USB HS (high speed TLL, EHCI and OHCI) */
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBTLL_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBFSHOST_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_PHY_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_PHY_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_UTMI_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_UTMI_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_HSIC_CLK),
+ OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_HSIC_CLK),
+
+ /* GPIO */
+ OMAP4_GENERIC_CLOCK_DEV(GPIO1_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(GPIO2_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(GPIO3_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(GPIO4_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(GPIO5_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(GPIO6_CLK),
+
+ /* sDMA */
+ OMAP4_GENERIC_CLOCK_DEV(SDMA_CLK),
+
+ /* I2C */
+ OMAP4_GENERIC_CLOCK_DEV(I2C1_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(I2C2_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(I2C3_CLK),
+ OMAP4_GENERIC_CLOCK_DEV(I2C4_CLK),
+
+ { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
+};
+
+/**
+ * omap4_clk_details - Stores details for all the different clocks supported
+ *
+ * Whenever an operation on a clock is being performed (activated, deactivated,
+ * etc) this array is looked up to find the correct register and bit(s) we
+ * should be modifying.
+ *
+ */
+struct omap4_clk_details {
+ clk_ident_t id;
+
+ uint32_t mem_region;
+ uint32_t clksel_reg;
+
+ int32_t src_freq;
+
+ uint32_t enable_mode;
+};
+
+#define OMAP4_GENERIC_CLOCK_DETAILS(i, f, m, r, e) \
+ { .id = (i), \
+ .mem_region = (m), \
+ .clksel_reg = (r), \
+ .src_freq = (f), \
+ .enable_mode = (e), \
+ }
+
+static struct omap4_clk_details g_omap4_clk_details[] = {
+
+ /* UART */
+ OMAP4_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(UART4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
+
+ /* General purpose timers */
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK, -1, PRM_INSTANCE_MEM_REGION,
+ (WKUP_CM_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x038), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x048), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK, -1, CM1_INSTANCE_MEM_REGION,
+ (ABE_CM1_OFFSET + 0x068), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK, -1, CM1_INSTANCE_MEM_REGION,
+ (ABE_CM1_OFFSET + 0x070), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK, -1, CM1_INSTANCE_MEM_REGION,
+ (ABE_CM1_OFFSET + 0x078), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK, -1, CM1_INSTANCE_MEM_REGION,
+ (ABE_CM1_OFFSET + 0x080), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x050), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x028), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x030), CLKCTRL_MODULEMODE_ENABLE),
+
+ /* HSMMC (MMC1 and MMC2 can have different input clocks) */
+ OMAP4_GENERIC_CLOCK_DETAILS(MMC1_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L3INIT_CM2_OFFSET + 0x028), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+ OMAP4_GENERIC_CLOCK_DETAILS(MMC2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L3INIT_CM2_OFFSET + 0x030), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+ OMAP4_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x120), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+ OMAP4_GENERIC_CLOCK_DETAILS(MMC4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x128), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+ OMAP4_GENERIC_CLOCK_DETAILS(MMC5_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x160), /*CLKCTRL_MODULEMODE_ENABLE*/1),
+
+ /* GPIO modules */
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, PRM_INSTANCE_MEM_REGION,
+ (WKUP_CM_OFFSET + 0x038), CLKCTRL_MODULEMODE_AUTO),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x060), CLKCTRL_MODULEMODE_AUTO),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x068), CLKCTRL_MODULEMODE_AUTO),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x070), CLKCTRL_MODULEMODE_AUTO),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x078), CLKCTRL_MODULEMODE_AUTO),
+ OMAP4_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x080), CLKCTRL_MODULEMODE_AUTO),
+
+ /* sDMA block */
+ OMAP4_GENERIC_CLOCK_DETAILS(SDMA_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (CORE_CM2_OFFSET + 0x300), CLKCTRL_MODULEMODE_AUTO),
+
+ /* I2C modules */
+ OMAP4_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0A0), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0A8), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0B0), CLKCTRL_MODULEMODE_ENABLE),
+ OMAP4_GENERIC_CLOCK_DETAILS(I2C4_CLK, -1, CM2_INSTANCE_MEM_REGION,
+ (L4PER_CM2_OFFSET + 0x0B8), CLKCTRL_MODULEMODE_ENABLE),
+
+ { INVALID_CLK_IDENT, 0, 0, 0, 0 },
+};
+
+/**
+ * MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come
+ * alive.
+ *
+ */
+#define MAX_MODULE_ENABLE_WAIT 100
+
+/**
+ * ARRAY_SIZE - Macro to return the number of elements in a static const array.
+ *
+ */
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+/**
+ * omap4_clk_details - writes a 32-bit value to one of the timer registers
+ * @timer: Timer device context
+ * @off: The offset of a register from the timer register address range
+ * @val: The value to write into the register
+ *
+ *
+ * RETURNS:
+ * nothing
+ */
+static struct omap4_clk_details*
+omap4_clk_details(clk_ident_t id)
+{
+ struct omap4_clk_details *walker;
+
+ for (walker = g_omap4_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
+ if (id == walker->id)
+ return (walker);
+ }
+
+ return NULL;
+}
+
+/**
+ * omap4_clk_generic_activate - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_activate(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+ unsigned int i;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ /* All the 'generic' clocks have a CLKCTRL register which is more or less
+ * generic - the have at least two fielda called MODULEMODE and IDLEST.
+ */
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= clk_details->enable_mode;
+ bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+
+ /* Now poll on the IDLEST register to tell us if the module has come up.
+ * TODO: We need to take into account the parent clocks.
+ */
+
+ /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+ for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+ if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
+ break;
+ DELAY(10);
+ }
+
+ /* Check the enabled state */
+ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
+ printf("Error: failed to enable module with clock %d\n", clkdev->id);
+ printf("Error: 0x%08x => 0x%08x\n", clk_details->clksel_reg, clksel);
+ return (ETIMEDOUT);
+ }
+
+ return (0);
+}
+
+/**
+ * omap4_clk_generic_deactivate - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ /* All the 'generic' clocks have a CLKCTRL register which is more or less
+ * generic - the have at least two fielda called MODULEMODE and IDLEST.
+ */
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= CLKCTRL_MODULEMODE_DISABLE;
+ bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+
+ return (0);
+}
+
+/**
+ * omap4_clk_generic_set_source - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_set_source(struct ti_clock_dev *clkdev,
+ clk_src_t clksrc)
+{
+
+ return (0);
+}
+
+/**
+ * omap4_clk_generic_accessible - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_generic_accessible(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+
+ /* Check the enabled state */
+ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
+ return (0);
+
+ return (1);
+}
+
+/**
+ * omap4_clk_generic_get_source_freq - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev,
+ unsigned int *freq
+ )
+{
+ struct omap4_clk_details* clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ /* Simply return the stored frequency */
+ if (freq)
+ *freq = (unsigned int)clk_details->src_freq;
+
+ return (0);
+}
+
+
+/**
+ * omap4_clk_gptimer_set_source - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev,
+ clk_src_t clksrc)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ /* TODO: Implement */
+
+ return (0);
+}
+
+/**
+ * omap4_clk_gptimer_get_source_freq - checks if a module is accessible
+ * @module: identifier for the module to check, see omap3_prcm.h for a list
+ * of possible modules.
+ * Example: OMAP3_MODULE_MMC1
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev,
+ unsigned int *freq
+ )
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+ unsigned int src_freq;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ /* Need to read the CLKSEL field to determine the clock source */
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+ if (clksel & (0x1UL << 24))
+ src_freq = FREQ_32KHZ;
+ else
+ omap4_clk_get_sysclk_freq(NULL, &src_freq);
+
+ /* Return the frequency */
+ if (freq)
+ *freq = src_freq;
+
+ return (0);
+}
+
+/**
+ * omap4_clk_hsmmc_set_source - sets the source clock (freq)
+ * @clkdev: pointer to the clockdev structure (id field will contain clock id)
+ *
+ * The MMC 1 and 2 clocks can be source from either a 64MHz or 96MHz clock.
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev,
+ clk_src_t clksrc)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ /* For MMC modules 3, 4 & 5 you can't change the freq, it's always 48MHz */
+ if ((clkdev->id == MMC3_CLK) || (clkdev->id == MMC4_CLK) ||
+ (clkdev->id == MMC5_CLK)) {
+ if (clksrc != F48MHZ_CLK)
+ return (EINVAL);
+ return 0;
+ }
+
+
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+
+ /* Bit 24 is set if 96MHz clock or cleared for 64MHz clock */
+ if (clksrc == F64MHZ_CLK)
+ clksel &= ~(0x1UL << 24);
+ else if (clksrc == F96MHZ_CLK)
+ clksel |= (0x1UL << 24);
+ else
+ return (EINVAL);
+
+ bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+
+ return (0);
+}
+
+/**
+ * omap4_clk_hsmmc_get_source_freq - checks if a module is accessible
+ * @clkdev: pointer to the clockdev structure (id field will contain clock id)
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,
+ unsigned int *freq
+ )
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct omap4_clk_details* clk_details;
+ struct resource* clk_mem_res;
+ uint32_t clksel;
+ unsigned int src_freq;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ clk_details = omap4_clk_details(clkdev->id);
+
+ if (clk_details == NULL)
+ return (ENXIO);
+
+ clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+ if (clk_mem_res == NULL)
+ return (EINVAL);
+
+ switch (clkdev->id) {
+ case MMC1_CLK:
+ case MMC2_CLK:
+ /* Need to read the CLKSEL field to determine the clock source */
+ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+ if (clksel & (0x1UL << 24))
+ src_freq = FREQ_96MHZ;
+ else
+ src_freq = FREQ_64MHZ;
+ break;
+ case MMC3_CLK:
+ case MMC4_CLK:
+ case MMC5_CLK:
+ src_freq = FREQ_48MHZ;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /* Return the frequency */
+ if (freq)
+ *freq = src_freq;
+
+ return (0);
+}
+
+/**
+ * omap4_clk_get_sysclk_freq - gets the sysclk frequency
+ * @sc: pointer to the clk module/device context
+ *
+ * Read the clocking information from the power-control/boot-strap registers,
+ * and stored in two global variables.
+ *
+ * RETURNS:
+ * nothing, values are saved in global variables
+ */
+static int
+omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev,
+ unsigned int *freq)
+{
+ uint32_t clksel;
+ uint32_t sysclk;
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ /* Read the input clock freq from the configuration register (CM_SYS_CLKSEL) */
+ clksel = bus_read_4(sc->sc_res[PRM_INSTANCE_MEM_REGION], CM_SYS_CLKSEL_OFFSET);
+ switch (clksel & 0x7) {
+ case 0x1:
+ /* 12Mhz */
+ sysclk = 12000000;
+ break;
+ case 0x3:
+ /* 16.8Mhz */
+ sysclk = 16800000;
+ break;
+ case 0x4:
+ /* 19.2Mhz */
+ sysclk = 19200000;
+ break;
+ case 0x5:
+ /* 26Mhz */
+ sysclk = 26000000;
+ break;
+ case 0x7:
+ /* 38.4Mhz */
+ sysclk = 38400000;
+ break;
+ default:
+ panic("%s: Invalid clock freq", __func__);
+ }
+
+ /* Return the value */
+ if (freq)
+ *freq = sysclk;
+
+ return (0);
+}
+
+/**
+ * omap4_clk_get_arm_fclk_freq - gets the MPU clock frequency
+ * @clkdev: ignored
+ * @freq: pointer which upon return will contain the freq in hz
+ * @mem_res: array of allocated memory resources
+ *
+ * Reads the frequency setting information registers and returns the value
+ * in the freq variable.
+ *
+ * RETURNS:
+ * returns 0 on success, a positive error code on failure.
+ */
+static int
+omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev,
+ unsigned int *freq)
+{
+ uint32_t clksel;
+ uint32_t pll_mult, pll_div;
+ uint32_t mpuclk, sysclk;
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ /* Read the clksel register which contains the DPLL multiple and divide
+ * values. These are applied to the sysclk.
+ */
+ clksel = bus_read_4(sc->sc_res[CM1_INSTANCE_MEM_REGION], CM_CLKSEL_DPLL_MPU);
+
+ pll_mult = ((clksel >> 8) & 0x7ff);
+ pll_div = (clksel & 0x7f) + 1;
+
+
+ /* Get the system clock freq */
+ omap4_clk_get_sysclk_freq(NULL, &sysclk);
+
+
+ /* Calculate the MPU freq */
+ mpuclk = (sysclk * pll_mult) / pll_div;
+
+ /* Return the value */
+ if (freq)
+ *freq = mpuclk;
+
+ return (0);
+}
+
+/**
+ * omap4_clk_hsusbhost_activate - activates the USB clocks for the given module
+ * @clkdev: pointer to the clock device structure.
+ * @mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *
+ * The USB clocking setup seems to be a bit more tricky than the other modules,
+ * to start with the clocking diagram for the HS host module shows 13 different
+ * clocks. So to try and make it easier to follow the clocking activation
+ * and deactivation is handled in it's own set of callbacks.
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a positive error code on failure.
+ */
+
+struct dpll_param {
+ unsigned int m;
+ unsigned int n;
+ unsigned int m2;
+ unsigned int m3;
+ unsigned int m4;
+ unsigned int m5;
+ unsigned int m6;
+ unsigned int m7;
+};
+/* USB parameters */
+struct dpll_param usb_dpll_param[7] = {
+ /* 12M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 13M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 16.8M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 19.2M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 26M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 27M values */
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ /* 38.4M values */
+#ifdef CONFIG_OMAP4_SDC
+ {0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
+#else
+ {0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
+#endif
+};
+static int
+omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct resource* clk_mem_res;
+ uint32_t clksel_reg_off;
+ uint32_t clksel;
+ unsigned int i;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ switch (clkdev->id) {
+ case USBTLL_CLK:
+ /* For the USBTLL module we need to enable the following clocks:
+ * - INIT_L4_ICLK (will be enabled by bootloader)
+ * - TLL_CH0_FCLK
+ * - TLL_CH1_FCLK
+ */
+
+ /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+
+ /* Enable the module and also enable the optional func clocks for
+ * channels 0 & 1 (is this needed ?)
+ */
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= CLKCTRL_MODULEMODE_ENABLE;
+
+ clksel |= (0x1 << 8); /* USB-HOST optional clock: USB_CH0_CLK */
+ clksel |= (0x1 << 9); /* USB-HOST optional clock: USB_CH1_CLK */
+ break;
+
+ case USBHSHOST_CLK:
+ case USBP1_PHY_CLK:
+ case USBP2_PHY_CLK:
+ case USBP1_UTMI_CLK:
+ case USBP2_UTMI_CLK:
+ case USBP1_HSIC_CLK:
+ case USBP2_HSIC_CLK:
+ /* For the USB HS HOST module we need to enable the following clocks:
+ * - INIT_L4_ICLK (will be enabled by bootloader)
+ * - INIT_L3_ICLK (will be enabled by bootloader)
+ * - INIT_48MC_FCLK
+ * - UTMI_ROOT_GFCLK (UTMI only, create a new clock for that ?)
+ * - UTMI_P1_FCLK (UTMI only, create a new clock for that ?)
+ * - UTMI_P2_FCLK (UTMI only, create a new clock for that ?)
+ * - HSIC_P1_60 (HSIC only, create a new clock for that ?)
+ * - HSIC_P1_480 (HSIC only, create a new clock for that ?)
+ * - HSIC_P2_60 (HSIC only, create a new clock for that ?)
+ * - HSIC_P2_480 (HSIC only, create a new clock for that ?)
+ */
+
+ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+ /* Enable the module and also enable the optional func clocks */
+ if (clkdev->id == USBHSHOST_CLK) {
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= /*CLKCTRL_MODULEMODE_ENABLE*/2;
+
+ clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
+ }
+
+ else if (clkdev->id == USBP1_UTMI_CLK)
+ clksel |= (0x1 << 8); /* UTMI_P1_CLK */
+ else if (clkdev->id == USBP2_UTMI_CLK)
+ clksel |= (0x1 << 9); /* UTMI_P2_CLK */
+
+ else if (clkdev->id == USBP1_HSIC_CLK)
+ clksel |= (0x5 << 11); /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
+ else if (clkdev->id == USBP2_HSIC_CLK)
+ clksel |= (0x5 << 12); /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
+
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+
+ /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+ for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+ if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
+ break;
+ }
+
+ /* Check the enabled state */
+ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
+ printf("Error: HERE failed to enable module with clock %d\n", clkdev->id);
+ printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
+ return (ETIMEDOUT);
+ }
+
+ return (0);
+}
+
+/**
+ * omap4_clk_generic_deactivate - checks if a module is accessible
+ * @clkdev: pointer to the clock device structure.
+ * @mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct resource* clk_mem_res;
+ uint32_t clksel_reg_off;
+ uint32_t clksel;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ switch (clkdev->id) {
+ case USBTLL_CLK:
+ /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= CLKCTRL_MODULEMODE_DISABLE;
+ break;
+
+ case USBHSHOST_CLK:
+ case USBP1_PHY_CLK:
+ case USBP2_PHY_CLK:
+ case USBP1_UTMI_CLK:
+ case USBP2_UTMI_CLK:
+ case USBP1_HSIC_CLK:
+ case USBP2_HSIC_CLK:
+ /* For the USB HS HOST module we need to enable the following clocks:
+ * - INIT_L4_ICLK (will be enabled by bootloader)
+ * - INIT_L3_ICLK (will be enabled by bootloader)
+ * - INIT_48MC_FCLK
+ * - UTMI_ROOT_GFCLK (UTMI only, create a new clock for that ?)
+ * - UTMI_P1_FCLK (UTMI only, create a new clock for that ?)
+ * - UTMI_P2_FCLK (UTMI only, create a new clock for that ?)
+ * - HSIC_P1_60 (HSIC only, create a new clock for that ?)
+ * - HSIC_P1_480 (HSIC only, create a new clock for that ?)
+ * - HSIC_P2_60 (HSIC only, create a new clock for that ?)
+ * - HSIC_P2_480 (HSIC only, create a new clock for that ?)
+ */
+
+ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+
+ /* Enable the module and also enable the optional func clocks */
+ if (clkdev->id == USBHSHOST_CLK) {
+ clksel &= ~CLKCTRL_MODULEMODE_MASK;
+ clksel |= CLKCTRL_MODULEMODE_DISABLE;
+
+ clksel &= ~(0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
+ }
+
+ else if (clkdev->id == USBP1_UTMI_CLK)
+ clksel &= ~(0x1 << 8); /* UTMI_P1_CLK */
+ else if (clkdev->id == USBP2_UTMI_CLK)
+ clksel &= ~(0x1 << 9); /* UTMI_P2_CLK */
+
+ else if (clkdev->id == USBP1_HSIC_CLK)
+ clksel &= ~(0x5 << 11); /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
+ else if (clkdev->id == USBP2_HSIC_CLK)
+ clksel &= ~(0x5 << 12); /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
+
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+
+ return (0);
+}
+
+/**
+ * omap4_clk_hsusbhost_accessible - checks if a module is accessible
+ * @clkdev: pointer to the clock device structure.
+ * @mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 if module is not enable, 1 if module is enabled or a negative
+ * error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct resource* clk_mem_res;
+ uint32_t clksel_reg_off;
+ uint32_t clksel;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ if (clkdev->id == USBTLL_CLK) {
+ /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+ }
+ else if (clkdev->id == USBHSHOST_CLK) {
+ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+ }
+ else {
+ return (EINVAL);
+ }
+
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+
+ /* Check the enabled state */
+ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
+ return (0);
+
+ return (1);
+}
+
+/**
+ * omap4_clk_hsusbhost_set_source - sets the source clocks
+ * @clkdev: pointer to the clock device structure.
+ * @clksrc: the clock source ID for the given clock.
+ * @mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *
+ *
+ *
+ * LOCKING:
+ * Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ * RETURNS:
+ * Returns 0 if sucessful otherwise a negative error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev,
+ clk_src_t clksrc)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ struct resource* clk_mem_res;
+ uint32_t clksel_reg_off;
+ uint32_t clksel;
+ unsigned int bit;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ if (clkdev->id == USBP1_PHY_CLK)
+ bit = 24;
+ else if (clkdev->id != USBP2_PHY_CLK)
+ bit = 25;
+ else
+ return (EINVAL);
+
+ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+ clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+ clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+ clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+
+ /* Set the clock source to either external or internal */
+ if (clksrc == EXT_CLK)
+ clksel |= (0x1 << bit);
+ else
+ clksel &= ~(0x1 << bit);
+
+ bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+
+ return (0);
+}
+
+#define PRM_RSTCTRL 0x1b00
+#define PRM_RSTCTRL_RESET 0x2
+
+static void
+omap4_prcm_reset(void)
+{
+ struct omap4_prcm_softc *sc = omap4_prcm_sc;
+ bus_write_4(sc->sc_res[0], PRM_RSTCTRL,
+ bus_read_4(sc->sc_res[0], PRM_RSTCTRL) | PRM_RSTCTRL_RESET);
+ bus_read_4(sc->sc_res[0], PRM_RSTCTRL);
+}
+
+/**
+ * omap4_prcm_probe - probe function for the driver
+ * @dev: prcm device handle
+ *
+ * Simply sets the name of the driver module.
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+omap4_prcm_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,omap4_prcm"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI OMAP Power, Reset and Clock Management");
+ return (0);
+}
+
+/**
+ * omap_prcm_attach - attach function for the driver
+ * @dev: prcm device handle
+ *
+ * Allocates and sets up the driver context, this simply entails creating a
+ * bus mappings for the PRCM register set.
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+omap4_prcm_attach(device_t dev)
+{
+ struct omap4_prcm_softc *sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, omap4_scm_res_spec, sc->sc_res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ omap4_prcm_sc = sc;
+ ti_cpu_reset = omap4_prcm_reset;
+
+ return (0);
+}
+
+static device_method_t omap4_prcm_methods[] = {
+ DEVMETHOD(device_probe, omap4_prcm_probe),
+ DEVMETHOD(device_attach, omap4_prcm_attach),
+ {0, 0},
+};
+
+static driver_t omap4_prcm_driver = {
+ "omap4_prcm",
+ omap4_prcm_methods,
+ sizeof(struct omap4_prcm_softc),
+};
+
+static devclass_t omap4_prcm_devclass;
+
+DRIVER_MODULE(omap4_prcm, simplebus, omap4_prcm_driver, omap4_prcm_devclass, 0, 0);
+MODULE_VERSION(omap4_prcm, 1);
diff --git a/sys/arm/ti/omap4/omap4_reg.h b/sys/arm/ti/omap4/omap4_reg.h
new file mode 100644
index 0000000..5a071c2
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_reg.h
@@ -0,0 +1,586 @@
+/*-
+ * 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$
+ */
+
+/*
+ * Texas Instruments - OMAP44xx series processors
+ *
+ * Reference:
+ * OMAP44xx Applications Processor
+ * Technical Reference Manual
+ * (omap44xx_techref.pdf)
+ *
+ *
+ * Note:
+ * The devices are mapped into address above 0xD000_0000 as the kernel space
+ * memory is at 0xC000_0000 and above. The first 256MB after this is reserved
+ * for the size of the kernel, everything above that is reserved for SoC
+ * devices.
+ *
+ */
+#ifndef _OMAP44XX_REG_H_
+#define _OMAP44XX_REG_H_
+
+#ifndef _LOCORE
+#include <sys/types.h> /* for uint32_t */
+#endif
+
+
+
+
+
+/* Physical/Virtual address for SDRAM controller */
+
+#define OMAP44XX_SMS_VBASE 0x6C000000UL
+#define OMAP44XX_SMS_HWBASE 0x6C000000UL
+#define OMAP44XX_SMS_SIZE 0x01000000UL
+
+#define OMAP44XX_SDRC_VBASE 0x6D000000UL
+#define OMAP44XX_SDRC_HWBASE 0x6D000000UL
+#define OMAP44XX_SDRC_SIZE 0x01000000UL
+
+
+
+/* Physical/Virtual address for I/O space */
+
+#define OMAP44XX_L3_EMU_VBASE 0xD4000000UL
+#define OMAP44XX_L3_EMU_HWBASE 0x54000000UL
+#define OMAP44XX_L3_EMU_SIZE 0x00200000UL
+
+#define OMAP44XX_L3_EMIF1_VBASE 0xEC000000UL
+#define OMAP44XX_L3_EMIF1_HWBASE 0x4C000000UL
+#define OMAP44XX_L3_EMIF1_SIZE 0x01000000UL
+
+#define OMAP44XX_L3_EMIF2_VBASE 0xED000000UL
+#define OMAP44XX_L3_EMIF2_HWBASE 0x4D000000UL
+#define OMAP44XX_L3_EMIF2_SIZE 0x01000000UL
+
+
+#define OMAP44XX_L4_CORE_VBASE 0xEA000000UL
+#define OMAP44XX_L4_CORE_HWBASE 0x4A000000UL
+#define OMAP44XX_L4_CORE_SIZE 0x01000000UL
+
+#define OMAP44XX_L4_WAKEUP_VBASE 0xEA300000UL
+#define OMAP44XX_L4_WAKEUP_HWBASE 0x4A300000UL
+#define OMAP44XX_L4_WAKEUP_SIZE 0x00040000UL
+
+#define OMAP44XX_L4_PERIPH_VBASE 0xE8000000UL
+#define OMAP44XX_L4_PERIPH_HWBASE 0x48000000UL
+#define OMAP44XX_L4_PERIPH_SIZE 0x01000000UL
+
+#define OMAP44XX_L4_ABE_VBASE 0xE9000000UL
+#define OMAP44XX_L4_ABE_HWBASE 0x49000000UL
+#define OMAP44XX_L4_ABE_SIZE 0x00100000UL
+
+
+/* Physical/Virtual address for MPU Subsystem space */
+
+#define OMAP44XX_MPU_SUBSYS_VBASE (OMAP44XX_L4_PERIPH_VBASE + 0x00240000UL)
+#define OMAP44XX_MPU_SUBSYS_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + 0x00240000UL)
+#define OMAP44XX_MPU_SUBSYS_SIZE 0x00004000UL
+
+/*
+ * MPU Subsystem addresss offsets
+ */
+#define OMAP44XX_SCU_OFFSET 0x00000000UL
+#define OMAP44XX_GIC_CPU_OFFSET 0x00000100UL
+#define OMAP44XX_GBL_TIMER_OFFSET 0x00000200UL
+#define OMAP44XX_PRV_TIMER_OFFSET 0x00000600UL
+#define OMAP44XX_GIC_DIST_OFFSET 0x00001000UL
+#define OMAP44XX_PL310_OFFSET 0x00002000UL
+#define OMAP44XX_CORTEXA9_SOCKET_PRCM_OFFSET 0x00003000UL
+#define OMAP44XX_CORTEXA9_PRM_OFFSET 0x00003200UL
+#define OMAP44XX_CORTEXA9_CPU0_OFFSET 0x00003400UL
+#define OMAP44XX_CORTEXA9_CPU1_OFFSET 0x00003800UL
+
+#define OMAP44XX_SCU_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_SCU_OFFSET)
+#define OMAP44XX_SCU_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_SCU_OFFSET)
+#define OMAP44XX_SCU_SIZE 0x00000080UL
+#define OMAP44XX_GIC_CPU_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GIC_CPU_OFFSET)
+#define OMAP44XX_GIC_CPU_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_GIC_CPU_OFFSET)
+#define OMAP44XX_GIC_CPU_SIZE 0x00000100UL
+#define OMAP44XX_GBL_TIMER_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GBL_TIMER_OFFSET)
+#define OMAP44XX_GBL_TIMER_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_GBL_TIMER_OFFSET)
+#define OMAP44XX_GBL_TIMER_SIZE 0x00000100UL
+#define OMAP44XX_PRV_TIMER_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_PRV_TIMER_OFFSET)
+#define OMAP44XX_PRV_TIMER_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_PRV_TIMER_OFFSET)
+#define OMAP44XX_PRV_TIMER_SIZE 0x00000100UL
+#define OMAP44XX_GIC_DIST_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GIC_DIST_OFFSET)
+#define OMAP44XX_GIC_DIST_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_GIC_DIST_OFFSET)
+#define OMAP44XX_GIC_DIST_SIZE 0x00000100UL
+#define OMAP44XX_PL310_HWBASE (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_PL310_OFFSET)
+#define OMAP44XX_PL310_VBASE (OMAP44XX_MPU_SUBSYS_VBASE + OMAP44XX_PL310_OFFSET)
+#define OMAP44XX_PL310_SIZE 0x00001000UL
+
+
+
+
+/*
+ * L4-CORE Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_SCM_OFFSET 0x00002000UL
+#define OMAP44XX_CM_OFFSET 0x00004000UL
+#define OMAP44XX_SDMA_OFFSET 0x00056000UL
+#define OMAP44XX_USB_TLL_OFFSET 0x00062000UL
+#define OMAP44XX_USB_UHH_OFFSET 0x00064000UL
+#define OMAP44XX_USB_OHCI_OFFSET 0x00064800UL
+#define OMAP44XX_USB_EHCI_OFFSET 0x00064C00UL
+#define OMAP44XX_MCBSP1_OFFSET 0x00074000UL
+#define OMAP44XX_MCBSP5_OFFSET 0x00096000UL
+#define OMAP44XX_SCM_PADCONF_OFFSET 0x00100000UL
+
+/*
+ * L4-WAKEUP Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_PRM_OFFSET 0x00006000UL
+#define OMAP44XX_SCRM_OFFSET 0x0000A000UL
+#define OMAP44XX_GPIO1_OFFSET 0x00010000UL
+#define OMAP44XX_GPTIMER1_OFFSET 0x00018000UL
+
+
+
+/*
+ * L4-PERIPH Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_UART3_OFFSET 0x00020000UL
+#define OMAP44XX_GPTIMER2_OFFSET 0x00032000UL
+#define OMAP44XX_GPTIMER3_OFFSET 0x00034000UL
+#define OMAP44XX_GPTIMER4_OFFSET 0x00036000UL
+#define OMAP44XX_GPTIMER9_OFFSET 0x0003E000UL
+#define OMAP44XX_GPIO2_OFFSET 0x00055000UL
+#define OMAP44XX_GPIO3_OFFSET 0x00057000UL
+#define OMAP44XX_GPIO4_OFFSET 0x00059000UL
+#define OMAP44XX_GPIO5_OFFSET 0x0005B000UL
+#define OMAP44XX_GPIO6_OFFSET 0x0005D000UL
+#define OMAP44XX_I2C3_OFFSET 0x00060000UL
+#define OMAP44XX_UART1_OFFSET 0x0006A000UL
+#define OMAP44XX_UART2_OFFSET 0x0006C000UL
+#define OMAP44XX_UART4_OFFSET 0x0006E000UL
+#define OMAP44XX_I2C1_OFFSET 0x00070000UL
+#define OMAP44XX_I2C2_OFFSET 0x00072000UL
+#define OMAP44XX_SLIMBUS2_OFFSET 0x00076000UL
+#define OMAP44XX_ELM_OFFSET 0x00078000UL
+#define OMAP44XX_GPTIMER10_OFFSET 0x00086000UL
+#define OMAP44XX_GPTIMER11_OFFSET 0x00088000UL
+#define OMAP44XX_MCBSP4_OFFSET 0x00096000UL
+#define OMAP44XX_MCSPI1_OFFSET 0x00098000UL
+#define OMAP44XX_MCSPI2_OFFSET 0x0009A000UL
+#define OMAP44XX_MMCHS1_OFFSET 0x0009C000UL
+#define OMAP44XX_MMCSD3_OFFSET 0x000AD000UL
+#define OMAP44XX_MMCHS2_OFFSET 0x000B4000UL
+#define OMAP44XX_MMCSD4_OFFSET 0x000D1000UL
+#define OMAP44XX_MMCSD5_OFFSET 0x000D5000UL
+#define OMAP44XX_I2C4_OFFSET 0x00350000UL
+
+/* The following are registers defined as part of the ARM MPCORE system,
+ * they are not SoC components rather registers that control the MPCORE core.
+ */
+// #define OMAP44XX_SCU_OFFSET 0x48240000 /* Snoop control unit */
+// #define OMAP44XX_GIC_PROC_OFFSET 0x48240100 /* Interrupt controller unit */
+// #define OMAP44XX_MPU_TIMER_OFFSET 0x48240600
+// #define OMAP44XX_GIC_INTR_OFFSET 0x48241000
+// #define OMAP44XX_PL310_OFFSET 0x48242000 /* L2 Cache controller */
+
+
+/*
+ * L4-ABE Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_GPTIMER5_OFFSET 0x00038000UL
+#define OMAP44XX_GPTIMER6_OFFSET 0x0003A000UL
+#define OMAP44XX_GPTIMER7_OFFSET 0x0003C000UL
+#define OMAP44XX_GPTIMER8_OFFSET 0x0003E000UL
+
+
+
+
+
+/*
+ * System Control Module
+ */
+#define OMAP44XX_SCM_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SCM_OFFSET)
+#define OMAP44XX_SCM_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_SCM_OFFSET)
+#define OMAP44XX_SCM_SIZE 0x00001000UL
+
+
+
+/*
+ *
+ */
+#define OMAP44XX_CM_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_CM_OFFSET)
+#define OMAP44XX_CM_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_CM_OFFSET)
+#define OMAP44XX_CM_SIZE 0x00001500UL
+
+
+/*
+ *
+ */
+#define OMAP44XX_PRM_HWBASE (OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_PRM_OFFSET)
+#define OMAP44XX_PRM_VBASE (OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_PRM_OFFSET)
+#define OMAP44XX_PRM_SIZE 0x00001600UL
+
+/*
+ *
+ */
+#define OMAP44XX_SCRM_HWBASE (OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_SCRM_OFFSET)
+#define OMAP44XX_SCRM_VBASE (OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_SCRM_OFFSET)
+#define OMAP44XX_SCRM_SIZE 0x00000800UL
+
+
+
+/*
+ * Uarts
+ */
+#define OMAP44XX_UART1_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_UART1_OFFSET)
+#define OMAP44XX_UART1_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_UART1_OFFSET)
+#define OMAP44XX_UART1_SIZE 0x00001000UL
+#define OMAP44XX_UART2_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_UART2_OFFSET)
+#define OMAP44XX_UART2_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_UART2_OFFSET)
+#define OMAP44XX_UART2_SIZE 0x00001000UL
+#define OMAP44XX_UART3_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_UART3_OFFSET)
+#define OMAP44XX_UART3_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_UART3_OFFSET)
+#define OMAP44XX_UART3_SIZE 0x00001000UL
+#define OMAP44XX_UART4_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_UART4_OFFSET)
+#define OMAP44XX_UART4_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_UART4_OFFSET)
+#define OMAP44XX_UART4_SIZE 0x00001000UL
+
+
+
+
+/*
+ * I2C Modules
+ */
+#define OMAP44XX_I2C1_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C1_OFFSET)
+#define OMAP44XX_I2C1_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_I2C1_OFFSET)
+#define OMAP44XX_I2C1_SIZE 0x00000080UL
+#define OMAP44XX_I2C2_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C2_OFFSET)
+#define OMAP44XX_I2C2_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_I2C2_OFFSET)
+#define OMAP44XX_I2C2_SIZE 0x00000080UL
+#define OMAP44XX_I2C3_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C3_OFFSET)
+#define OMAP44XX_I2C3_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_I2C3_OFFSET)
+#define OMAP44XX_I2C3_SIZE 0x00000080UL
+
+
+
+/*
+ * McBSP Modules
+ */
+#define OMAP44XX_MCBSP1_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_MCBSP1_OFFSET)
+#define OMAP44XX_MCBSP1_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_MCBSP1_OFFSET)
+#define OMAP44XX_MCBSP1_SIZE 0x00001000UL
+#define OMAP44XX_MCBSP2_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP2_OFFSET)
+#define OMAP44XX_MCBSP2_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MCBSP2_OFFSET)
+#define OMAP44XX_MCBSP2_SIZE 0x00001000UL
+#define OMAP44XX_MCBSP3_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP3_OFFSET)
+#define OMAP44XX_MCBSP3_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MCBSP3_OFFSET)
+#define OMAP44XX_MCBSP3_SIZE 0x00001000UL
+#define OMAP44XX_MCBSP4_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP4_OFFSET)
+#define OMAP44XX_MCBSP4_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MCBSP4_OFFSET)
+#define OMAP44XX_MCBSP4_SIZE 0x00001000UL
+#define OMAP44XX_MCBSP5_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_MCBSP5_OFFSET)
+#define OMAP44XX_MCBSP5_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_MCBSP5_OFFSET)
+#define OMAP44XX_MCBSP5_SIZE 0x00001000UL
+
+
+
+/*
+ * USB TTL Module
+ */
+#define OMAP44XX_USB_TLL_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_TLL_OFFSET)
+#define OMAP44XX_USB_TLL_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_USB_TLL_OFFSET)
+#define OMAP44XX_USB_TLL_SIZE 0x00001000UL
+
+/*
+ * USB Host Module
+ */
+#define OMAP44XX_USB_UHH_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_UHH_OFFSET)
+#define OMAP44XX_USB_UHH_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_USB_UHH_OFFSET)
+#define OMAP44XX_USB_UHH_SIZE 0x00000700UL
+
+/*
+ * USB OHCI Module
+ */
+#define OMAP44XX_USB_OHCI_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_OHCI_OFFSET)
+#define OMAP44XX_USB_OHCI_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_USB_OHCI_OFFSET)
+#define OMAP44XX_USB_OHCI_SIZE 0x00000400UL
+
+/*
+ * USB EHCI Module
+ */
+#define OMAP44XX_USB_EHCI_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_EHCI_OFFSET)
+#define OMAP44XX_USB_EHCI_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_USB_EHCI_OFFSET)
+#define OMAP44XX_USB_EHCI_SIZE 0x0000400UL
+
+
+
+
+
+/*
+ * SDMA Offset
+ * PA 0x4805 6000
+ */
+
+#define OMAP44XX_SDMA_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SDMA_OFFSET)
+#define OMAP44XX_SDMA_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_SDMA_OFFSET)
+#define OMAP44XX_SDMA_SIZE 0x00001000UL
+
+
+
+/*
+ * Interrupt Controller Unit.
+ *
+ * Refer to the omap4_intr.c file for interrupt controller (GIC)
+ * implementation.
+ *
+ * Note:
+ * - 16 Interprocessor interrupts (IPI): ID[15:0]
+ * - 2 private Timer/Watchdog interrupts: ID[30:29]
+ * - 2 legacy nFIQ & nIRQ: one per CPU, bypasses the interrupt distributor
+ * logic and directly drives interrupt requests into CPU if used in
+ * legacy mode (else treated like other interrupts lines with ID28
+ * and ID31 respectively)
+ * - 128 hardware interrupts: ID[159:32] (rising-edge or high-level sensitive).
+ */
+#define OMAP44XX_HARDIRQ(x) (32 + (x))
+
+#define OMAP44XX_IRQ_L2CACHE OMAP44XX_HARDIRQ(0) /* L2 cache controller interrupt */
+#define OMAP44XX_IRQ_CTI_0 OMAP44XX_HARDIRQ(1) /* Cross-trigger module 0 (CTI0) interrupt */
+#define OMAP44XX_IRQ_CTI_1 OMAP44XX_HARDIRQ(2) /* Cross-trigger module 1 (CTI1) interrupt */
+#define OMAP44XX_IRQ_RESERVED3 OMAP44XX_HARDIRQ(3) /* RESERVED */
+#define OMAP44XX_IRQ_ELM OMAP44XX_HARDIRQ(4) /* Error location process completion */
+#define OMAP44XX_IRQ_RESERVED5 OMAP44XX_HARDIRQ(5) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED6 OMAP44XX_HARDIRQ(6) /* RESERVED */
+#define OMAP44XX_IRQ_SYS_NIRQ OMAP44XX_HARDIRQ(7) /* External source (active low) */
+#define OMAP44XX_IRQ_RESERVED8 OMAP44XX_HARDIRQ(8) /* RESERVED */
+#define OMAP44XX_IRQ_L3_DBG OMAP44XX_HARDIRQ(9) /* L3 interconnect debug error */
+#define OMAP44XX_IRQ_L3_APP OMAP44XX_HARDIRQ(10) /* L3 interconnect application error */
+#define OMAP44XX_IRQ_PRCM_MPU OMAP44XX_HARDIRQ(11) /* PRCM module IRQ */
+#define OMAP44XX_IRQ_SDMA0 OMAP44XX_HARDIRQ(12) /* System DMA request 0(3) */
+#define OMAP44XX_IRQ_SDMA1 OMAP44XX_HARDIRQ(13) /* System DMA request 1(3) */
+#define OMAP44XX_IRQ_SDMA2 OMAP44XX_HARDIRQ(14) /* System DMA request 2 */
+#define OMAP44XX_IRQ_SDMA3 OMAP44XX_HARDIRQ(15) /* System DMA request 3 */
+#define OMAP44XX_IRQ_MCBSP4 OMAP44XX_HARDIRQ(16) /* McBSP module 4 IRQ */
+#define OMAP44XX_IRQ_MCBSP1 OMAP44XX_HARDIRQ(17) /* McBSP module 1 IRQ */
+#define OMAP44XX_IRQ_SR1 OMAP44XX_HARDIRQ(18) /* SmartReflexâ„¢ 1 */
+#define OMAP44XX_IRQ_SR2 OMAP44XX_HARDIRQ(19) /* SmartReflexâ„¢ 2 */
+#define OMAP44XX_IRQ_GPMC OMAP44XX_HARDIRQ(20) /* General-purpose memory controller module */
+#define OMAP44XX_IRQ_SGX OMAP44XX_HARDIRQ(21) /* 2D/3D graphics module */
+#define OMAP44XX_IRQ_MCBSP2 OMAP44XX_HARDIRQ(22) /* McBSP module 2 */
+#define OMAP44XX_IRQ_MCBSP3 OMAP44XX_HARDIRQ(23) /* McBSP module 3 */
+#define OMAP44XX_IRQ_ISS5 OMAP44XX_HARDIRQ(24) /* Imaging subsystem interrupt 5 */
+#define OMAP44XX_IRQ_DSS OMAP44XX_HARDIRQ(25) /* Display subsystem module(3) */
+#define OMAP44XX_IRQ_MAIL_U0 OMAP44XX_HARDIRQ(26) /* Mailbox user 0 request */
+#define OMAP44XX_IRQ_C2C_SSCM OMAP44XX_HARDIRQ(27) /* C2C status interrupt */
+#define OMAP44XX_IRQ_DSP_MMU OMAP44XX_HARDIRQ(28) /* DSP MMU */
+#define OMAP44XX_IRQ_GPIO1_MPU OMAP44XX_HARDIRQ(29) /* GPIO module 1(3) */
+#define OMAP44XX_IRQ_GPIO2_MPU OMAP44XX_HARDIRQ(30) /* GPIO module 2(3) */
+#define OMAP44XX_IRQ_GPIO3_MPU OMAP44XX_HARDIRQ(31) /* GPIO module 3(3) */
+#define OMAP44XX_IRQ_GPIO4_MPU OMAP44XX_HARDIRQ(32) /* GPIO module 4(3) */
+#define OMAP44XX_IRQ_GPIO5_MPU OMAP44XX_HARDIRQ(33) /* GPIO module 5(3) */
+#define OMAP44XX_IRQ_GPIO6_MPU OMAP44XX_HARDIRQ(34) /* GPIO module 6(3) */
+#define OMAP44XX_IRQ_RESERVED35 OMAP44XX_HARDIRQ(35) /* RESERVED */
+#define OMAP44XX_IRQ_WDT3 OMAP44XX_HARDIRQ(36) /* Watchdog timer module 3 overflow */
+#define OMAP44XX_IRQ_GPT1 OMAP44XX_HARDIRQ(37) /* General-purpose timer module 1 */
+#define OMAP44XX_IRQ_GPT2 OMAP44XX_HARDIRQ(38) /* General-purpose timer module 2 */
+#define OMAP44XX_IRQ_GPT3 OMAP44XX_HARDIRQ(39) /* General-purpose timer module 3 */
+#define OMAP44XX_IRQ_GPT4 OMAP44XX_HARDIRQ(40) /* General-purpose timer module 4 */
+#define OMAP44XX_IRQ_GPT5 OMAP44XX_HARDIRQ(41) /* General-purpose timer module 5 */
+#define OMAP44XX_IRQ_GPT6 OMAP44XX_HARDIRQ(42) /* General-purpose timer module 6 */
+#define OMAP44XX_IRQ_GPT7 OMAP44XX_HARDIRQ(43) /* General-purpose timer module 7 */
+#define OMAP44XX_IRQ_GPT8 OMAP44XX_HARDIRQ(44) /* General-purpose timer module 8 */
+#define OMAP44XX_IRQ_GPT9 OMAP44XX_HARDIRQ(45) /* General-purpose timer module 9 */
+#define OMAP44XX_IRQ_GPT10 OMAP44XX_HARDIRQ(46) /* General-purpose timer module 10 */
+#define OMAP44XX_IRQ_GPT11 OMAP44XX_HARDIRQ(47) /* General-purpose timer module 11 */
+#define OMAP44XX_IRQ_MCSPI4 OMAP44XX_HARDIRQ(48) /* McSPI module 4 */
+#define OMAP44XX_IRQ_RESERVED49 OMAP44XX_HARDIRQ(49) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED50 OMAP44XX_HARDIRQ(50) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED51 OMAP44XX_HARDIRQ(51) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED52 OMAP44XX_HARDIRQ(52) /* RESERVED */
+#define OMAP44XX_IRQ_DSS_DSI1 OMAP44XX_HARDIRQ(53) /* Display Subsystem DSI1 interrupt */
+#define OMAP44XX_IRQ_RESERVED54 OMAP44XX_HARDIRQ(54) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED55 OMAP44XX_HARDIRQ(55) /* RESERVED */
+#define OMAP44XX_IRQ_I2C1 OMAP44XX_HARDIRQ(56) /* I2C module 1 */
+#define OMAP44XX_IRQ_I2C2 OMAP44XX_HARDIRQ(57) /* I2C module 2 */
+#define OMAP44XX_IRQ_HDQ OMAP44XX_HARDIRQ(58) /* HDQ / One-wire */
+#define OMAP44XX_IRQ_MMC5 OMAP44XX_HARDIRQ(59) /* MMC5 interrupt */
+#define OMAP44XX_IRQ_RESERVED60 OMAP44XX_HARDIRQ(60) /* RESERVED */
+#define OMAP44XX_IRQ_I2C3 OMAP44XX_HARDIRQ(61) /* I2C module 3 */
+#define OMAP44XX_IRQ_I2C4 OMAP44XX_HARDIRQ(62) /* I2C module 4 */
+#define OMAP44XX_IRQ_RESERVED63 OMAP44XX_HARDIRQ(63) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED64 OMAP44XX_HARDIRQ(64) /* RESERVED */
+#define OMAP44XX_IRQ_MCSPI1 OMAP44XX_HARDIRQ(65) /* McSPI module 1 */
+#define OMAP44XX_IRQ_MCSPI2 OMAP44XX_HARDIRQ(66) /* McSPI module 2 */
+#define OMAP44XX_IRQ_HSI_P1 OMAP44XX_HARDIRQ(67) /* HSI Port 1 interrupt */
+#define OMAP44XX_IRQ_HSI_P2 OMAP44XX_HARDIRQ(68) /* HSI Port 2 interrupt */
+#define OMAP44XX_IRQ_FDIF_3 OMAP44XX_HARDIRQ(69) /* Face detect interrupt 3 */
+#define OMAP44XX_IRQ_UART4 OMAP44XX_HARDIRQ(70) /* UART module 4 interrupt */
+#define OMAP44XX_IRQ_HSI_DMA OMAP44XX_HARDIRQ(71) /* HSI DMA engine MPU request */
+#define OMAP44XX_IRQ_UART1 OMAP44XX_HARDIRQ(72) /* UART module 1 */
+#define OMAP44XX_IRQ_UART2 OMAP44XX_HARDIRQ(73) /* UART module 2 */
+#define OMAP44XX_IRQ_UART3 OMAP44XX_HARDIRQ(74) /* UART module 3 (also infrared)(3) */
+#define OMAP44XX_IRQ_PBIAS OMAP44XX_HARDIRQ(75) /* Merged interrupt for PBIASlite1 and 2 */
+#define OMAP44XX_IRQ_OHCI OMAP44XX_HARDIRQ(76) /* OHCI controller HSUSB MP Host Interrupt */
+#define OMAP44XX_IRQ_EHCI OMAP44XX_HARDIRQ(77) /* EHCI controller HSUSB MP Host Interrupt */
+#define OMAP44XX_IRQ_TLL OMAP44XX_HARDIRQ(78) /* HSUSB MP TLL Interrupt */
+#define OMAP44XX_IRQ_RESERVED79 OMAP44XX_HARDIRQ(79) /* RESERVED */
+#define OMAP44XX_IRQ_WDT2 OMAP44XX_HARDIRQ(80) /* WDTIMER2 interrupt */
+#define OMAP44XX_IRQ_RESERVED81 OMAP44XX_HARDIRQ(81) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED82 OMAP44XX_HARDIRQ(82) /* RESERVED */
+#define OMAP44XX_IRQ_MMC1 OMAP44XX_HARDIRQ(83) /* MMC/SD module 1 */
+#define OMAP44XX_IRQ_DSS_DSI2 OMAP44XX_HARDIRQ(84) /* Display subsystem DSI2 interrupt */
+#define OMAP44XX_IRQ_RESERVED85 OMAP44XX_HARDIRQ(85) /* Reserved */
+#define OMAP44XX_IRQ_MMC2 OMAP44XX_HARDIRQ(86) /* MMC/SD module 2 */
+#define OMAP44XX_IRQ_MPU_ICR OMAP44XX_HARDIRQ(87) /* MPU ICR */
+#define OMAP44XX_IRQ_C2C_GPI OMAP44XX_HARDIRQ(88) /* C2C GPI interrupt */
+#define OMAP44XX_IRQ_FSUSB OMAP44XX_HARDIRQ(89) /* FS-USB - host controller Interrupt */
+#define OMAP44XX_IRQ_FSUSB_SMI OMAP44XX_HARDIRQ(90) /* FS-USB - host controller SMI Interrupt */
+#define OMAP44XX_IRQ_MCSPI3 OMAP44XX_HARDIRQ(91) /* McSPI module 3 */
+#define OMAP44XX_IRQ_HSUSB_OTG OMAP44XX_HARDIRQ(92) /* High-Speed USB OTG controller */
+#define OMAP44XX_IRQ_HSUSB_OTG_DMA OMAP44XX_HARDIRQ(93) /* High-Speed USB OTG DMA controller */
+#define OMAP44XX_IRQ_MMC3 OMAP44XX_HARDIRQ(94) /* MMC/SD module 3 */
+#define OMAP44XX_IRQ_RESERVED95 OMAP44XX_HARDIRQ(95) /* RESERVED */
+#define OMAP44XX_IRQ_MMC4 OMAP44XX_HARDIRQ(96) /* MMC4 interrupt */
+#define OMAP44XX_IRQ_SLIMBUS1 OMAP44XX_HARDIRQ(97) /* SLIMBUS1 interrupt */
+#define OMAP44XX_IRQ_SLIMBUS2 OMAP44XX_HARDIRQ(98) /* SLIMBUS2 interrupt */
+#define OMAP44XX_IRQ_ABE OMAP44XX_HARDIRQ(99) /* Audio back-end interrupt */
+#define OMAP44XX_IRQ_CORTEXM3_MMU OMAP44XX_HARDIRQ(100) /* Cortex-M3 MMU interrupt */
+#define OMAP44XX_IRQ_DSS_HDMI OMAP44XX_HARDIRQ(101) /* Display subsystem HDMI interrupt */
+#define OMAP44XX_IRQ_SR_IVA OMAP44XX_HARDIRQ(102) /* SmartReflex IVA interrupt */
+#define OMAP44XX_IRQ_IVAHD1 OMAP44XX_HARDIRQ(103) /* Sync interrupt from iCONT2 (vDMA) */
+#define OMAP44XX_IRQ_IVAHD2 OMAP44XX_HARDIRQ(104) /* Sync interrupt from iCONT1 */
+#define OMAP44XX_IRQ_RESERVED105 OMAP44XX_HARDIRQ(105) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED106 OMAP44XX_HARDIRQ(106) /* RESERVED */
+#define OMAP44XX_IRQ_IVAHD_MAILBOX0 OMAP44XX_HARDIRQ(107) /* IVAHD mailbox interrupt */
+#define OMAP44XX_IRQ_RESERVED108 OMAP44XX_HARDIRQ(108) /* RESERVED */
+#define OMAP44XX_IRQ_MCASP1 OMAP44XX_HARDIRQ(109) /* McASP1 transmit interrupt */
+#define OMAP44XX_IRQ_EMIF1 OMAP44XX_HARDIRQ(110) /* EMIF1 interrupt */
+#define OMAP44XX_IRQ_EMIF2 OMAP44XX_HARDIRQ(111) /* EMIF2 interrupt */
+#define OMAP44XX_IRQ_MCPDM OMAP44XX_HARDIRQ(112) /* MCPDM interrupt */
+#define OMAP44XX_IRQ_DMM OMAP44XX_HARDIRQ(113) /* DMM interrupt */
+#define OMAP44XX_IRQ_DMIC OMAP44XX_HARDIRQ(114) /* DMIC interrupt */
+#define OMAP44XX_IRQ_RESERVED115 OMAP44XX_HARDIRQ(115) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED116 OMAP44XX_HARDIRQ(116) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED117 OMAP44XX_HARDIRQ(117) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED118 OMAP44XX_HARDIRQ(118) /* RESERVED */
+#define OMAP44XX_IRQ_SYS_NIRQ2 OMAP44XX_HARDIRQ(119) /* External source 2 (active low) */
+#define OMAP44XX_IRQ_KBD OMAP44XX_HARDIRQ(120) /* Keyboard controller interrupt */
+#define OMAP44XX_IRQ_RESERVED121 OMAP44XX_HARDIRQ(121) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED122 OMAP44XX_HARDIRQ(122) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED123 OMAP44XX_HARDIRQ(123) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED124 OMAP44XX_HARDIRQ(124) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED125 OMAP44XX_HARDIRQ(125) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED126 OMAP44XX_HARDIRQ(126) /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED127 OMAP44XX_HARDIRQ(127) /* RESERVED */
+
+
+
+/*
+ * General Purpose Timers
+ */
+#define OMAP44XX_GPTIMER1_VBASE (OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_GPTIMER1_OFFSET)
+#define OMAP44XX_GPTIMER1_HWBASE (OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_GPTIMER1_OFFSET)
+#define OMAP44XX_GPTIMER2_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER2_OFFSET)
+#define OMAP44XX_GPTIMER2_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER2_OFFSET)
+#define OMAP44XX_GPTIMER3_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER3_OFFSET)
+#define OMAP44XX_GPTIMER3_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER3_OFFSET)
+#define OMAP44XX_GPTIMER4_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER4_OFFSET)
+#define OMAP44XX_GPTIMER4_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER4_OFFSET)
+#define OMAP44XX_GPTIMER5_VBASE (OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER5_OFFSET)
+#define OMAP44XX_GPTIMER5_HWBASE (OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER5_OFFSET)
+#define OMAP44XX_GPTIMER6_VBASE (OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER6_OFFSET)
+#define OMAP44XX_GPTIMER6_HWBASE (OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER6_OFFSET)
+#define OMAP44XX_GPTIMER7_VBASE (OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER7_OFFSET)
+#define OMAP44XX_GPTIMER7_HWBASE (OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER7_OFFSET)
+#define OMAP44XX_GPTIMER8_VBASE (OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER8_OFFSET)
+#define OMAP44XX_GPTIMER8_HWBASE (OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER8_OFFSET)
+#define OMAP44XX_GPTIMER9_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER9_OFFSET)
+#define OMAP44XX_GPTIMER9_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER9_OFFSET)
+#define OMAP44XX_GPTIMER10_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER10_OFFSET)
+#define OMAP44XX_GPTIMER10_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER10_OFFSET)
+#define OMAP44XX_GPTIMER11_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER11_OFFSET)
+#define OMAP44XX_GPTIMER11_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER11_OFFSET)
+#define OMAP44XX_GPTIMER_SIZE 0x00001000UL
+
+
+
+/*
+ * GPIO - General Purpose IO
+ */
+
+/* Base addresses for the GPIO modules */
+#define OMAP44XX_GPIO1_HWBASE (OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_GPIO1_OFFSET)
+#define OMAP44XX_GPIO1_VBASE (OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_GPIO1_OFFSET)
+#define OMAP44XX_GPIO1_SIZE 0x00001000UL
+#define OMAP44XX_GPIO2_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO2_OFFSET)
+#define OMAP44XX_GPIO2_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPIO2_OFFSET)
+#define OMAP44XX_GPIO2_SIZE 0x00001000UL
+#define OMAP44XX_GPIO3_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO3_OFFSET)
+#define OMAP44XX_GPIO3_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPIO3_OFFSET)
+#define OMAP44XX_GPIO3_SIZE 0x00001000UL
+#define OMAP44XX_GPIO4_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO4_OFFSET)
+#define OMAP44XX_GPIO4_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPIO4_OFFSET)
+#define OMAP44XX_GPIO4_SIZE 0x00001000UL
+#define OMAP44XX_GPIO5_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO5_OFFSET)
+#define OMAP44XX_GPIO5_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPIO5_OFFSET)
+#define OMAP44XX_GPIO5_SIZE 0x00001000UL
+#define OMAP44XX_GPIO6_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO6_OFFSET)
+#define OMAP44XX_GPIO6_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPIO6_OFFSET)
+#define OMAP44XX_GPIO6_SIZE 0x00001000UL
+
+
+/*
+ * MMC/SD/SDIO
+ */
+
+/* Base addresses for the MMC/SD/SDIO modules */
+#define OMAP44XX_MMCHS1_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCHS1_OFFSET)
+#define OMAP44XX_MMCHS1_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCHS1_OFFSET)
+#define OMAP44XX_MMCHS2_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCHS2_OFFSET)
+#define OMAP44XX_MMCHS2_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCHS2_OFFSET)
+#define OMAP44XX_MMCHS3_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD3_OFFSET)
+#define OMAP44XX_MMCHS3_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD3_OFFSET)
+#define OMAP44XX_MMCHS4_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD4_OFFSET)
+#define OMAP44XX_MMCHS4_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD4_OFFSET)
+#define OMAP44XX_MMCHS5_HWBASE (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD5_OFFSET)
+#define OMAP44XX_MMCHS5_VBASE (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD5_OFFSET)
+#define OMAP44XX_MMCHS_SIZE 0x00001000UL
+
+
+
+/*
+ * SCM - System Control Module
+ */
+
+/* Base addresses for the SC modules */
+#define OMAP44XX_SCM_PADCONF_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SCM_PADCONF_OFFSET)
+#define OMAP44XX_SCM_PADCONF_VBASE (OMAP44XX_L4_CORE_VBASE + OMAP44XX_SCM_PADCONF_OFFSET)
+#define OMAP44XX_SCM_PADCONF_SIZE 0x00001000UL
+
+
+
+
+#endif /* _OMAP44XX_REG_H_ */
diff --git a/sys/arm/ti/omap4/omap4_scm_padconf.c b/sys/arm/ti/omap4/omap4_scm_padconf.c
new file mode 100644
index 0000000..4cd3a56
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_scm_padconf.c
@@ -0,0 +1,405 @@
+/*-
+ * 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.
+ * 3. 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.
+ */
+#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 <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <sys/gpio.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/omap4/omap4var.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+
+/*
+ * This file defines the pin mux configuration for the OMAP4xxx series of
+ * devices.
+ *
+ * How This is Suppose to Work
+ * ===========================
+ * - There is a top level ti_scm module (System Control Module) that is
+ * the interface for all omap drivers, which can use it to change the mux
+ * settings for individual pins. (That said, typically the pin mux settings
+ * are set to defaults by the 'hints' and then not altered by the driver).
+ *
+ * - For this to work the top level driver needs all the pin info, and hence
+ * this is where this file comes in. Here we define all the pin information
+ * that is supplied to the top level driver.
+ *
+ */
+
+#define CONTROL_PADCONF_WAKEUP_EVENT (1UL << 15)
+#define CONTROL_PADCONF_WAKEUP_ENABLE (1UL << 14)
+#define CONTROL_PADCONF_OFF_PULL_UP (1UL << 13)
+#define CONTROL_PADCONF_OFF_PULL_ENABLE (1UL << 12)
+#define CONTROL_PADCONF_OFF_OUT_HIGH (1UL << 11)
+#define CONTROL_PADCONF_OFF_OUT_ENABLE (1UL << 10)
+#define CONTROL_PADCONF_OFF_ENABLE (1UL << 9)
+#define CONTROL_PADCONF_INPUT_ENABLE (1UL << 8)
+#define CONTROL_PADCONF_PULL_UP (1UL << 4)
+#define CONTROL_PADCONF_PULL_ENABLE (1UL << 3)
+#define CONTROL_PADCONF_MUXMODE_MASK (0x7)
+
+#define CONTROL_PADCONF_SATE_MASK ( CONTROL_PADCONF_WAKEUP_EVENT \
+ | CONTROL_PADCONF_WAKEUP_ENABLE \
+ | CONTROL_PADCONF_OFF_PULL_UP \
+ | CONTROL_PADCONF_OFF_PULL_ENABLE \
+ | CONTROL_PADCONF_OFF_OUT_HIGH \
+ | CONTROL_PADCONF_OFF_OUT_ENABLE \
+ | CONTROL_PADCONF_OFF_ENABLE \
+ | CONTROL_PADCONF_INPUT_ENABLE \
+ | CONTROL_PADCONF_PULL_UP \
+ | CONTROL_PADCONF_PULL_ENABLE )
+
+/* Active pin states */
+#define PADCONF_PIN_OUTPUT 0
+#define PADCONF_PIN_INPUT CONTROL_PADCONF_INPUT_ENABLE
+#define PADCONF_PIN_INPUT_PULLUP ( CONTROL_PADCONF_INPUT_ENABLE \
+ | CONTROL_PADCONF_PULL_ENABLE \
+ | CONTROL_PADCONF_PULL_UP)
+#define PADCONF_PIN_INPUT_PULLDOWN ( CONTROL_PADCONF_INPUT_ENABLE \
+ | CONTROL_PADCONF_PULL_ENABLE )
+
+/* Off mode states */
+#define PADCONF_PIN_OFF_NONE 0
+#define PADCONF_PIN_OFF_OUTPUT_HIGH ( CONTROL_PADCONF_OFF_ENABLE \
+ | CONTROL_PADCONF_OFF_OUT_ENABLE \
+ | CONTROL_PADCONF_OFF_OUT_HIGH)
+#define PADCONF_PIN_OFF_OUTPUT_LOW ( CONTROL_PADCONF_OFF_ENABLE \
+ | CONTROL_PADCONF_OFF_OUT_ENABLE)
+#define PADCONF_PIN_OFF_INPUT_PULLUP ( CONTROL_PADCONF_OFF_ENABLE \
+ | CONTROL_PADCONF_OFF_PULL_ENABLE \
+ | CONTROL_PADCONF_OFF_PULL_UP)
+#define PADCONF_PIN_OFF_INPUT_PULLDOWN ( CONTROL_PADCONF_OFF_ENABLE \
+ | CONTROL_PADCONF_OFF_PULL_ENABLE)
+#define PADCONF_PIN_OFF_WAKEUPENABLE CONTROL_PADCONF_WAKEUP_ENABLE
+
+
+#define _PINDEF(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \
+ { .reg_off = r, \
+ .gpio_pin = gp, \
+ .gpio_mode = gm, \
+ .ballname = b, \
+ .muxmodes[0] = m0, \
+ .muxmodes[1] = m1, \
+ .muxmodes[2] = m2, \
+ .muxmodes[3] = m3, \
+ .muxmodes[4] = m4, \
+ .muxmodes[5] = m5, \
+ .muxmodes[6] = m6, \
+ .muxmodes[7] = m7, \
+ }
+
+const struct ti_scm_padstate ti_padstate_devmap[] = {
+ {"output", PADCONF_PIN_OUTPUT},
+ {"input", PADCONF_PIN_INPUT},
+ {"input_pullup", PADCONF_PIN_INPUT_PULLUP},
+ {"input_pulldown", PADCONF_PIN_INPUT_PULLDOWN},
+ { .state = NULL }
+};
+
+/*
+ * Table 18-10, p. 3470
+ */
+const struct ti_scm_padconf ti_padconf_devmap[] = {
+ _PINDEF(0x0040, "c12", 0, 0, "gpmc_ad0", "sdmmc2_dat0", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0042, "d12", 0, 0, "gpmc_ad1", "sdmmc2_dat1", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0044, "c13", 0, 0, "gpmc_ad2", "sdmmc2_dat2", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0046, "d13", 0, 0, "gpmc_ad3", "sdmmc2_dat3", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0048, "c15", 0, 0, "gpmc_ad4", "sdmmc2_dat4", "sdmmc2_dir_dat0", NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x004a, "d15", 0, 0, "gpmc_ad5", "sdmmc2_dat5", "sdmmc2_dir_dat1", NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x004c, "a16", 0, 0, "gpmc_ad6", "sdmmc2_dat6", "sdmmc2_dir_cmd", NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x004e, "b16", 0, 0, "gpmc_ad7", "sdmmc2_dat7", "sdmmc2_clk_fdbk", NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0050, "c16", 32, 3, "gpmc_ad8", "kpd_row0", "c2c_data15", "gpio_32", NULL, "sdmmc1_dat0", NULL, NULL),
+ _PINDEF(0x0052, "d16", 33, 3, "gpmc_ad9", "kpd_row1", "c2c_data14", "gpio_33", NULL, "sdmmc1_dat1", NULL, NULL),
+ _PINDEF(0x0054, "c17", 34, 3, "gpmc_ad10", "kpd_row2", "c2c_data13", "gpio_34", NULL, "sdmmc1_dat2", NULL, NULL),
+ _PINDEF(0x0056, "d17", 35, 3, "gpmc_ad11", "kpd_row3", "c2c_data12", "gpio_35", NULL, "sdmmc1_dat3", NULL, NULL),
+ _PINDEF(0x0058, "c18", 36, 3, "gpmc_ad12", "kpd_col0", "c2c_data11", "gpio_36", NULL, "sdmmc1_dat4", NULL, NULL),
+ _PINDEF(0x005a, "d18", 37, 3, "gpmc_ad13", "kpd_col1", "c2c_data10", "gpio_37", NULL, "sdmmc1_dat5", NULL, NULL),
+ _PINDEF(0x005c, "c19", 38, 3, "gpmc_ad14", "kpd_col2", "c2c_data9", "gpio_38", NULL, "sdmmc1_dat6", NULL, NULL),
+ _PINDEF(0x005e, "d19", 39, 3, "gpmc_ad15", "kpd_col3", "c2c_data8", "gpio_39", NULL, "sdmmc1_dat7", NULL, NULL),
+ _PINDEF(0x0060, "b17", 40, 3, "gpmc_a16", "kpd_row4", "c2c_datain0", "gpio_40", "venc_656_data0", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0062, "a18", 41, 3, "gpmc_a17", "kpd_row5", "c2c_datain1", "gpio_41", "venc_656_data1", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0064, "b18", 42, 3, "gpmc_a18", "kpd_row6", "c2c_datain2", "gpio_42", "venc_656_data2", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0066, "a19", 43, 3, "gpmc_a19", "kpd_row7", "c2c_datain3", "gpio_43", "venc_656_data3", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0068, "b19", 44, 3, "gpmc_a20", "kpd_col4", "c2c_datain4", "gpio_44", "venc_656_data4", NULL, NULL, "safe_mode"),
+ _PINDEF(0x006a, "b20", 45, 3, "gpmc_a21", "kpd_col5", "c2c_datain5", "gpio_45", "venc_656_data5", NULL, NULL, "safe_mode"),
+ _PINDEF(0x006c, "a21", 46, 3, "gpmc_a22", "kpd_col6", "c2c_datain6", "gpio_46", "venc_656_data6", NULL, NULL, "safe_mode"),
+ _PINDEF(0x006e, "b21", 47, 3, "gpmc_a23", "kpd_col7", "c2c_datain7", "gpio_47", "venc_656_data7", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0070, "c20", 48, 3, "gpmc_a24", "kpd_col8", "c2c_clkout0", "gpio_48", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0072, "d20", 49, 3, "gpmc_a25", NULL, "c2c_clkout1", "gpio_49", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0074, "b25", 50, 3, "gpmc_ncs0", NULL, NULL, "gpio_50", "sys_ndmareq0", NULL, NULL, NULL),
+ _PINDEF(0x0076, "c21", 51, 3, "gpmc_ncs1", NULL, "c2c_dataout6", "gpio_51", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0078, "d21", 52, 3, "gpmc_ncs2", "kpd_row8", "c2c_dataout7", "gpio_52", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x007a, "c22", 53, 3, "gpmc_ncs3", "gpmc_dir", "c2c_dataout4", "gpio_53", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x007c, "c25", 54, 3, "gpmc_nwp", "dsi1_te0", NULL, "gpio_54", "sys_ndmareq1", NULL, NULL, NULL),
+ _PINDEF(0x007e, "b22", 55, 3, "gpmc_clk", NULL, NULL, "gpio_55", "sys_ndmareq2", "sdmmc1_cmd", NULL, NULL),
+ _PINDEF(0x0080, "d25", 56, 3, "gpmc_nadv_ale", "dsi1_te1", NULL, "gpio_56", "sys_ndmareq3", "sdmmc1_clk", NULL, NULL),
+ _PINDEF(0x0082, "b11", 0, 0, "gpmc_noe", "sdmmc2_clk", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0084, "b12", 0, 0, "gpmc_nwe", "sdmmc2_cmd", NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0086, "c23", 59, 3, "gpmc_nbe0_cle", "dsi2_te0", NULL, "gpio_59", NULL, NULL, NULL, NULL),
+ _PINDEF(0x0088, "d22", 60, 3, "gpmc_nbe1", NULL, "c2c_dataout5", "gpio_60", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x008a, "b26", 61, 3, "gpmc_wait0", "dsi2_te1", NULL, "gpio_61", NULL, NULL, NULL, NULL),
+ _PINDEF(0x008c, "b23", 62, 3, "gpmc_wait1", NULL, "c2c_dataout2", "gpio_62", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x008e, "d23", 100, 3, "gpmc_wait2", "usbc1_icusb_txen", "c2c_dataout3", "gpio_100", "sys_ndmareq0", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0090, "a24", 101, 3, "gpmc_ncs4", "dsi1_te0", "c2c_clkin0", "gpio_101", "sys_ndmareq1", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0092, "b24", 102, 3, "gpmc_ncs5", "dsi1_te1", "c2c_clkin1", "gpio_102", "sys_ndmareq2", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0094, "c24", 103, 3, "gpmc_ncs6", "dsi2_te0", "c2c_dataout0", "gpio_103", "sys_ndmareq3", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0096, "d24", 104, 3, "gpmc_ncs7", "dsi2_te1", "c2c_dataout1", "gpio_104", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0098, "b9", 63, 3, "hdmi_hpd", NULL, NULL, "gpio_63", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x009a, "b10", 64, 3, "hdmi_cec", NULL, NULL, "gpio_64", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x009c, "a8", 65, 3, "hdmi_ddc_scl", NULL, NULL, "gpio_65", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x009e, "b8", 66, 3, "hdmi_ddc_sda", NULL, NULL, "gpio_66", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00a0, "r26", 0, 0, "csi21_dx0", NULL, NULL, "gpi_67", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00a2, "r25", 0, 0, "csi21_dy0", NULL, NULL, "gpi_68", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00a4, "t26", 0, 0, "csi21_dx1", NULL, NULL, "gpi_69", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00a6, "t25", 0, 0, "csi21_dy1", NULL, NULL, "gpi_70", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00a8, "u26", 0, 0, "csi21_dx2", NULL, NULL, "gpi_71", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00aa, "u25", 0, 0, "csi21_dy2", NULL, NULL, "gpi_72", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ac, "v26", 0, 0, "csi21_dx3", NULL, NULL, "gpi_73", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ae, "v25", 0, 0, "csi21_dy3", NULL, NULL, "gpi_74", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00b0, "w26", 0, 0, "csi21_dx4", NULL, NULL, "gpi_75", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00b2, "w25", 0, 0, "csi21_dy4", NULL, NULL, "gpi_76", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00b4, "m26", 0, 0, "csi22_dx0", NULL, NULL, "gpi_77", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00b6, "m25", 0, 0, "csi22_dy0", NULL, NULL, "gpi_78", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00b8, "n26", 0, 0, "csi22_dx1", NULL, NULL, "gpi_79", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ba, "n25", 0, 0, "csi22_dy1", NULL, NULL, "gpi_80", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00bc, "t27", 81, 3, "cam_shutter", NULL, NULL, "gpio_81", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00be, "u27", 82, 3, "cam_strobe", NULL, NULL, "gpio_82", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00c0, "v27", 83, 3, "cam_globalreset", NULL, NULL, "gpio_83", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00c2, "ae18", 84, 3, "usbb1_ulpitll_clk", "hsi1_cawake", NULL, "gpio_84", "usbb1_ulpiphy_clk", NULL, "hw_dbg20", "safe_mode"),
+ _PINDEF(0x00c4, "ag19", 85, 3, "usbb1_ulpitll_stp", "hsi1_cadata", "mcbsp4_clkr", "gpio_85", "usbb1_ulpiphy_stp", "usbb1_mm_rxdp", "hw_dbg21", "safe_mode"),
+ _PINDEF(0x00c6, "af19", 86, 3, "usbb1_ulpitll_dir", "hsi1_caflag", "mcbsp4_fsr", "gpio_86", "usbb1_ulpiphy_dir", NULL, "hw_dbg22", "safe_mode"),
+ _PINDEF(0x00c8, "ae19", 87, 3, "usbb1_ulpitll_nxt", "hsi1_acready", "mcbsp4_fsx", "gpio_87", "usbb1_ulpiphy_nxt", "usbb1_mm_rxdm", "hw_dbg23", "safe_mode"),
+ _PINDEF(0x00ca, "af18", 88, 3, "usbb1_ulpitll_dat0", "hsi1_acwake", "mcbsp4_clkx", "gpio_88", "usbb1_ulpiphy_dat0", "usbb1_mm_txen", "hw_dbg24", "safe_mode"),
+ _PINDEF(0x00cc, "ag18", 89, 3, "usbb1_ulpitll_dat1", "hsi1_acdata", "mcbsp4_dx", "gpio_89", "usbb1_ulpiphy_dat1", "usbb1_mm_txdat", "hw_dbg25", "safe_mode"),
+ _PINDEF(0x00ce, "ae17", 90, 3, "usbb1_ulpitll_dat2", "hsi1_acflag", "mcbsp4_dr", "gpio_90", "usbb1_ulpiphy_dat2", "usbb1_mm_txse0", "hw_dbg26", "safe_mode"),
+ _PINDEF(0x00d0, "af17", 91, 3, "usbb1_ulpitll_dat3", "hsi1_caready", NULL, "gpio_91", "usbb1_ulpiphy_dat3", "usbb1_mm_rxrcv", "hw_dbg27", "safe_mode"),
+ _PINDEF(0x00d2, "ah17", 92, 3, "usbb1_ulpitll_dat4", "dmtimer8_pwm_evt", "abe_mcbsp3_dr", "gpio_92", "usbb1_ulpiphy_dat4", NULL, "hw_dbg28", "safe_mode"),
+ _PINDEF(0x00d4, "ae16", 93, 3, "usbb1_ulpitll_dat5", "dmtimer9_pwm_evt", "abe_mcbsp3_dx", "gpio_93", "usbb1_ulpiphy_dat5", NULL, "hw_dbg29", "safe_mode"),
+ _PINDEF(0x00d6, "af16", 94, 3, "usbb1_ulpitll_dat6", "dmtimer10_pwm_evt", "abe_mcbsp3_clkx", "gpio_94", "usbb1_ulpiphy_dat6", "abe_dmic_din3", "hw_dbg30", "safe_mode"),
+ _PINDEF(0x00d8, "ag16", 95, 3, "usbb1_ulpitll_dat7", "dmtimer11_pwm_evt", "abe_mcbsp3_fsx", "gpio_95", "usbb1_ulpiphy_dat7", "abe_dmic_clk3", "hw_dbg31", "safe_mode"),
+ _PINDEF(0x00da, "af14", 96, 3, "usbb1_hsic_data", NULL, NULL, "gpio_96", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00dc, "ae14", 97, 3, "usbb1_hsic_strobe", NULL, NULL, "gpio_97", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00de, "h2", 98, 3, "usbc1_icusb_dp", NULL, NULL, "gpio_98", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00e0, "h3", 99, 3, "usbc1_icusb_dm", NULL, NULL, "gpio_99", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00e2, "d2", 100, 3, "sdmmc1_clk", NULL, "dpm_emu19", "gpio_100", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00e4, "e3", 101, 3, "sdmmc1_cmd", NULL, "uart1_rx", "gpio_101", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00e6, "e4", 102, 3, "sdmmc1_dat0", NULL, "dpm_emu18", "gpio_102", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00e8, "e2", 103, 3, "sdmmc1_dat1", NULL, "dpm_emu17", "gpio_103", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ea, "e1", 104, 3, "sdmmc1_dat2", NULL, "dpm_emu16", "gpio_104", "jtag_tms_tmsc", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ec, "f4", 105, 3, "sdmmc1_dat3", NULL, "dpm_emu15", "gpio_105", "jtag_tck", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00ee, "f3", 106, 3, "sdmmc1_dat4", NULL, NULL, "gpio_106", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00f0, "f1", 107, 3, "sdmmc1_dat5", NULL, NULL, "gpio_107", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00f2, "g4", 108, 3, "sdmmc1_dat6", NULL, NULL, "gpio_108", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00f4, "g3", 109, 3, "sdmmc1_dat7", NULL, NULL, "gpio_109", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x00f6, "ad27", 110, 3, "abe_mcbsp2_clkx", "mcspi2_clk", "abe_mcasp_ahclkx", "gpio_110", "usbb2_mm_rxdm", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00f8, "ad26", 111, 3, "abe_mcbsp2_dr", "mcspi2_somi", "abe_mcasp_axr", "gpio_111", "usbb2_mm_rxdp", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00fa, "ad25", 112, 3, "abe_mcbsp2_dx", "mcspi2_simo", "abe_mcasp_amute", "gpio_112", "usbb2_mm_rxrcv", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00fc, "ac28", 113, 3, "abe_mcbsp2_fsx", "mcspi2_cs0", "abe_mcasp_afsx", "gpio_113", "usbb2_mm_txen", NULL, NULL, "safe_mode"),
+ _PINDEF(0x00fe, "ac26", 114, 3, "abe_mcbsp1_clkx", "abe_slimbus1_clock", NULL, "gpio_114", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0100, "ac25", 115, 3, "abe_mcbsp1_dr", "abe_slimbus1_data", NULL, "gpio_115", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0102, "ab25", 116, 3, "abe_mcbsp1_dx", "sdmmc3_dat2", "abe_mcasp_aclkx", "gpio_116", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0104, "ac27", 117, 3, "abe_mcbsp1_fsx", "sdmmc3_dat3", "abe_mcasp_amutein", "gpio_117", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0106, "ag25", 0, 0, "abe_pdm_ul_data", "abe_mcbsp3_dr", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0108, "af25", 0, 0, "abe_pdm_dl_data", "abe_mcbsp3_dx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x010a, "ae25", 0, 0, "abe_pdm_frame", "abe_mcbsp3_clkx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x010c, "af26", 0, 0, "abe_pdm_lb_clk", "abe_mcbsp3_fsx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x010e, "ah26", 118, 3, "abe_clks", NULL, NULL, "gpio_118", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0110, "ae24", 119, 3, "abe_dmic_clk1", NULL, NULL, "gpio_119", "usbb2_mm_txse0", "uart4_cts", NULL, "safe_mode"),
+ _PINDEF(0x0112, "af24", 120, 3, "abe_dmic_din1", NULL, NULL, "gpio_120", "usbb2_mm_txdat", "uart4_rts", NULL, "safe_mode"),
+ _PINDEF(0x0114, "ag24", 121, 3, "abe_dmic_din2", "slimbus2_clock", "abe_mcasp_axr", "gpio_121", NULL, "dmtimer11_pwm_evt", NULL, "safe_mode"),
+ _PINDEF(0x0116, "ah24", 122, 3, "abe_dmic_din3", "slimbus2_data", "abe_dmic_clk2", "gpio_122", NULL, "dmtimer9_pwm_evt", NULL, "safe_mode"),
+ _PINDEF(0x0118, "ab26", 123, 3, "uart2_cts", "sdmmc3_clk", NULL, "gpio_123", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x011a, "ab27", 124, 3, "uart2_rts", "sdmmc3_cmd", NULL, "gpio_124", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x011c, "aa25", 125, 3, "uart2_rx", "sdmmc3_dat0", NULL, "gpio_125", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x011e, "aa26", 126, 3, "uart2_tx", "sdmmc3_dat1", NULL, "gpio_126", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0120, "aa27", 127, 3, "hdq_sio", "i2c3_sccb", "i2c2_sccb", "gpio_127", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0122, "ae28", 0, 0, "i2c1_scl", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0124, "ae26", 0, 0, "i2c1_sda", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0126, "c26", 128, 3, "i2c2_scl", "uart1_rx", NULL, "gpio_128", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0128, "d26", 129, 3, "i2c2_sda", "uart1_tx", NULL, "gpio_129", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x012a, "w27", 130, 3, "i2c3_scl", NULL, NULL, "gpio_130", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x012c, "y27", 131, 3, "i2c3_sda", NULL, NULL, "gpio_131", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x012e, "ag21", 132, 3, "i2c4_scl", NULL, NULL, "gpio_132", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0130, "ah22", 133, 3, "i2c4_sda", NULL, NULL, "gpio_133", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0132, "af22", 134, 3, "mcspi1_clk", NULL, NULL, "gpio_134", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0134, "ae22", 135, 3, "mcspi1_somi", NULL, NULL, "gpio_135", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0136, "ag22", 136, 3, "mcspi1_simo", NULL, NULL, "gpio_136", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0138, "ae23", 137, 3, "mcspi1_cs0", NULL, NULL, "gpio_137", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x013a, "af23", 138, 3, "mcspi1_cs1", "uart1_rx", NULL, "gpio_138", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x013c, "ag23", 139, 3, "mcspi1_cs2", "uart1_cts", "slimbus2_clock", "gpio_139", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x013e, "ah23", 140, 3, "mcspi1_cs3", "uart1_rts", "slimbus2_data", "gpio_140", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0140, "f27", 141, 3, "uart3_cts_rctx", "uart1_tx", NULL, "gpio_141", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0142, "f28", 142, 3, "uart3_rts_sd", NULL, NULL, "gpio_142", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0144, "g27", 143, 3, "uart3_rx_irrx", "dmtimer8_pwm_evt", NULL, "gpio_143", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0146, "g28", 144, 3, "uart3_tx_irtx", "dmtimer9_pwm_evt", NULL, "gpio_144", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0148, "ae5", 145, 3, "sdmmc5_clk", "mcspi2_clk", "usbc1_icusb_dp", "gpio_145", NULL, "sdmmc2_clk", NULL, "safe_mode"),
+ _PINDEF(0x014a, "af5", 146, 3, "sdmmc5_cmd", "mcspi2_simo", "usbc1_icusb_dm", "gpio_146", NULL, "sdmmc2_cmd", NULL, "safe_mode"),
+ _PINDEF(0x014c, "ae4", 147, 3, "sdmmc5_dat0", "mcspi2_somi", "usbc1_icusb_rcv", "gpio_147", NULL, "sdmmc2_dat0", NULL, "safe_mode"),
+ _PINDEF(0x014e, "af4", 148, 3, "sdmmc5_dat1", NULL, "usbc1_icusb_txen", "gpio_148", NULL, "sdmmc2_dat1", NULL, "safe_mode"),
+ _PINDEF(0x0150, "ag3", 149, 3, "sdmmc5_dat2", "mcspi2_cs1", NULL, "gpio_149", NULL, "sdmmc2_dat2", NULL, "safe_mode"),
+ _PINDEF(0x0152, "af3", 150, 3, "sdmmc5_dat3", "mcspi2_cs0", NULL, "gpio_150", NULL, "sdmmc2_dat3", NULL, "safe_mode"),
+ _PINDEF(0x0154, "ae21", 151, 3, "mcspi4_clk", "sdmmc4_clk", "kpd_col6", "gpio_151", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0156, "af20", 152, 3, "mcspi4_simo", "sdmmc4_cmd", "kpd_col7", "gpio_152", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0158, "af21", 153, 3, "mcspi4_somi", "sdmmc4_dat0", "kpd_row6", "gpio_153", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x015a, "ae20", 154, 3, "mcspi4_cs0", "sdmmc4_dat3", "kpd_row7", "gpio_154", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x015c, "ag20", 155, 3, "uart4_rx", "sdmmc4_dat2", "kpd_row8", "gpio_155", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x015e, "ah19", 156, 3, "uart4_tx", "sdmmc4_dat1", "kpd_col8", "gpio_156", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0160, "ag12", 157, 3, "usbb2_ulpitll_clk", "usbb2_ulpiphy_clk", "sdmmc4_cmd", "gpio_157", "hsi2_cawake", NULL, NULL, "safe_mode"),
+ _PINDEF(0x0162, "af12", 158, 3, "usbb2_ulpitll_stp", "usbb2_ulpiphy_stp", "sdmmc4_clk", "gpio_158", "hsi2_cadata", "dispc2_data23", NULL, "safe_mode"),
+ _PINDEF(0x0164, "ae12", 159, 3, "usbb2_ulpitll_dir", "usbb2_ulpiphy_dir", "sdmmc4_dat0", "gpio_159", "hsi2_caflag", "dispc2_data22", NULL, "safe_mode"),
+ _PINDEF(0x0166, "ag13", 160, 3, "usbb2_ulpitll_nxt", "usbb2_ulpiphy_nxt", "sdmmc4_dat1", "gpio_160", "hsi2_acready", "dispc2_data21", NULL, "safe_mode"),
+ _PINDEF(0x0168, "ae11", 161, 3, "usbb2_ulpitll_dat0", "usbb2_ulpiphy_dat0", "sdmmc4_dat2", "gpio_161", "hsi2_acwake", "dispc2_data20", "usbb2_mm_txen", "safe_mode"),
+ _PINDEF(0x016a, "af11", 162, 3, "usbb2_ulpitll_dat1", "usbb2_ulpiphy_dat1", "sdmmc4_dat3", "gpio_162", "hsi2_acdata", "dispc2_data19", "usbb2_mm_txdat", "safe_mode"),
+ _PINDEF(0x016c, "ag11", 163, 3, "usbb2_ulpitll_dat2", "usbb2_ulpiphy_dat2", "sdmmc3_dat2", "gpio_163", "hsi2_acflag", "dispc2_data18", "usbb2_mm_txse0", "safe_mode"),
+ _PINDEF(0x016e, "ah11", 164, 3, "usbb2_ulpitll_dat3", "usbb2_ulpiphy_dat3", "sdmmc3_dat1", "gpio_164", "hsi2_caready", "dispc2_data15", "rfbi_data15", "safe_mode"),
+ _PINDEF(0x0170, "ae10", 165, 3, "usbb2_ulpitll_dat4", "usbb2_ulpiphy_dat4", "sdmmc3_dat0", "gpio_165", "mcspi3_somi", "dispc2_data14", "rfbi_data14", "safe_mode"),
+ _PINDEF(0x0172, "af10", 166, 3, "usbb2_ulpitll_dat5", "usbb2_ulpiphy_dat5", "sdmmc3_dat3", "gpio_166", "mcspi3_cs0", "dispc2_data13", "rfbi_data13", "safe_mode"),
+ _PINDEF(0x0174, "ag10", 167, 3, "usbb2_ulpitll_dat6", "usbb2_ulpiphy_dat6", "sdmmc3_cmd", "gpio_167", "mcspi3_simo", "dispc2_data12", "rfbi_data12", "safe_mode"),
+ _PINDEF(0x0176, "ae9", 168, 3, "usbb2_ulpitll_dat7", "usbb2_ulpiphy_dat7", "sdmmc3_clk", "gpio_168", "mcspi3_clk", "dispc2_data11", "rfbi_data11", "safe_mode"),
+ _PINDEF(0x0178, "af13", 169, 3, "usbb2_hsic_data", NULL, NULL, "gpio_169", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x017a, "ae13", 170, 3, "usbb2_hsic_strobe", NULL, NULL, "gpio_170", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x017c, "g26", 171, 3, "kpd_col3", "kpd_col0", NULL, "gpio_171", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x017e, "g25", 172, 3, "kpd_col4", "kpd_col1", NULL, "gpio_172", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0180, "h26", 173, 3, "kpd_col5", "kpd_col2", NULL, "gpio_173", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0182, "h25", 174, 3, "kpd_col0", "kpd_col3", NULL, "gpio_174", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0184, "j27", 0, 0, "kpd_col1", "kpd_col4", NULL, "gpio_0", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0186, "h27", 1, 3, "kpd_col2", "kpd_col5", NULL, "gpio_1", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0188, "j26", 175, 3, "kpd_row3", "kpd_row0", NULL, "gpio_175", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x018a, "j25", 176, 3, "kpd_row4", "kpd_row1", NULL, "gpio_176", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x018c, "k26", 177, 3, "kpd_row5", "kpd_row2", NULL, "gpio_177", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x018e, "k25", 178, 3, "kpd_row0", "kpd_row3", NULL, "gpio_178", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0190, "l27", 2, 3, "kpd_row1", "kpd_row4", NULL, "gpio_2", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0192, "k27", 3, 3, "kpd_row2", "kpd_row5", NULL, "gpio_3", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0194, "c3", 0, 0, "usba0_otg_ce", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+ _PINDEF(0x0196, "b5", 0, 0, "usba0_otg_dp", "uart3_rx_irrx", "uart2_rx", NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x0198, "b4", 0, 0, "usba0_otg_dm", "uart3_tx_irtx", "uart2_tx", NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x019a, "aa28", 181, 3, "fref_clk1_out", NULL, NULL, "gpio_181", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x019c, "y28", 182, 3, "fref_clk2_out", NULL, NULL, "gpio_182", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x019e, "ae6", 0, 0, "sys_nirq1", NULL, NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01a0, "af6", 183, 3, "sys_nirq2", NULL, NULL, "gpio_183", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01a2, "f26", 184, 3, "sys_boot0", NULL, NULL, "gpio_184", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01a4, "e27", 185, 3, "sys_boot1", NULL, NULL, "gpio_185", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01a6, "e26", 186, 3, "sys_boot2", NULL, NULL, "gpio_186", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01a8, "e25", 187, 3, "sys_boot3", NULL, NULL, "gpio_187", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01aa, "d28", 188, 3, "sys_boot4", NULL, NULL, "gpio_188", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01ac, "d27", 189, 3, "sys_boot5", NULL, NULL, "gpio_189", NULL, NULL, NULL, "safe_mode"),
+ _PINDEF(0x01ae, "m2", 11, 3, "dpm_emu0", NULL, NULL, "gpio_11", NULL, NULL, "hw_dbg0", "safe_mode"),
+ _PINDEF(0x01b0, "n2", 12, 3, "dpm_emu1", NULL, NULL, "gpio_12", NULL, NULL, "hw_dbg1", "safe_mode"),
+ _PINDEF(0x01b2, "p2", 13, 3, "dpm_emu2", "usba0_ulpiphy_clk", NULL, "gpio_13", NULL, "dispc2_fid", "hw_dbg2", "safe_mode"),
+ _PINDEF(0x01b4, "v1", 14, 3, "dpm_emu3", "usba0_ulpiphy_stp", NULL, "gpio_14", "rfbi_data10", "dispc2_data10", "hw_dbg3", "safe_mode"),
+ _PINDEF(0x01b6, "v2", 15, 3, "dpm_emu4", "usba0_ulpiphy_dir", NULL, "gpio_15", "rfbi_data9", "dispc2_data9", "hw_dbg4", "safe_mode"),
+ _PINDEF(0x01b8, "w1", 16, 3, "dpm_emu5", "usba0_ulpiphy_nxt", NULL, "gpio_16", "rfbi_te_vsync0", "dispc2_data16", "hw_dbg5", "safe_mode"),
+ _PINDEF(0x01ba, "w2", 17, 3, "dpm_emu6", "usba0_ulpiphy_dat0", "uart3_tx_irtx", "gpio_17", "rfbi_hsync0", "dispc2_data17", "hw_dbg6", "safe_mode"),
+ _PINDEF(0x01bc, "w3", 18, 3, "dpm_emu7", "usba0_ulpiphy_dat1", "uart3_rx_irrx", "gpio_18", "rfbi_cs0", "dispc2_hsync", "hw_dbg7", "safe_mode"),
+ _PINDEF(0x01be, "w4", 19, 3, "dpm_emu8", "usba0_ulpiphy_dat2", "uart3_rts_sd", "gpio_19", "rfbi_re", "dispc2_pclk", "hw_dbg8", "safe_mode"),
+ _PINDEF(0x01c0, "y2", 20, 3, "dpm_emu9", "usba0_ulpiphy_dat3", "uart3_cts_rctx", "gpio_20", "rfbi_we", "dispc2_vsync", "hw_dbg9", "safe_mode"),
+ _PINDEF(0x01c2, "y3", 21, 3, "dpm_emu10", "usba0_ulpiphy_dat4", NULL, "gpio_21", "rfbi_a0", "dispc2_de", "hw_dbg10", "safe_mode"),
+ _PINDEF(0x01c4, "y4", 22, 3, "dpm_emu11", "usba0_ulpiphy_dat5", NULL, "gpio_22", "rfbi_data8", "dispc2_data8", "hw_dbg11", "safe_mode"),
+ _PINDEF(0x01c6, "aa1", 23, 3, "dpm_emu12", "usba0_ulpiphy_dat6", NULL, "gpio_23", "rfbi_data7", "dispc2_data7", "hw_dbg12", "safe_mode"),
+ _PINDEF(0x01c8, "aa2", 24, 3, "dpm_emu13", "usba0_ulpiphy_dat7", NULL, "gpio_24", "rfbi_data6", "dispc2_data6", "hw_dbg13", "safe_mode"),
+ _PINDEF(0x01ca, "aa3", 25, 3, "dpm_emu14", "sys_drm_msecure", "uart1_rx", "gpio_25", "rfbi_data5", "dispc2_data5", "hw_dbg14", "safe_mode"),
+ _PINDEF(0x01cc, "aa4", 26, 3, "dpm_emu15", "sys_secure_indicator", NULL, "gpio_26", "rfbi_data4", "dispc2_data4", "hw_dbg15", "safe_mode"),
+ _PINDEF(0x01ce, "ab2", 27, 3, "dpm_emu16", "dmtimer8_pwm_evt", "dsi1_te0", "gpio_27", "rfbi_data3", "dispc2_data3", "hw_dbg16", "safe_mode"),
+ _PINDEF(0x01d0, "ab3", 28, 3, "dpm_emu17", "dmtimer9_pwm_evt", "dsi1_te1", "gpio_28", "rfbi_data2", "dispc2_data2", "hw_dbg17", "safe_mode"),
+ _PINDEF(0x01d2, "ab4", 190, 3, "dpm_emu18", "dmtimer10_pwm_evt", "dsi2_te0", "gpio_190", "rfbi_data1", "dispc2_data1", "hw_dbg18", "safe_mode"),
+ _PINDEF(0x01d4, "ac4", 191, 3, "dpm_emu19", "dmtimer11_pwm_evt", "dsi2_te1", "gpio_191", "rfbi_data0", "dispc2_data0", "hw_dbg19", "safe_mode"),
+ { .ballname = NULL },
+};
+
+const struct ti_scm_device ti_scm_dev = {
+ .padconf_muxmode_mask = CONTROL_PADCONF_MUXMODE_MASK,
+ .padconf_sate_mask = CONTROL_PADCONF_SATE_MASK,
+ .padstate = (struct ti_scm_padstate *) &ti_padstate_devmap,
+ .padconf = (struct ti_scm_padconf *) &ti_padconf_devmap,
+};
+
+int
+ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags)
+{
+ unsigned int state = 0;
+ /* First the SCM driver needs to be told to put the pad into GPIO mode */
+ if (flags & GPIO_PIN_OUTPUT)
+ state = PADCONF_PIN_OUTPUT;
+ else if (flags & GPIO_PIN_INPUT) {
+ if (flags & GPIO_PIN_PULLUP)
+ state = PADCONF_PIN_INPUT_PULLUP;
+ else if (flags & GPIO_PIN_PULLDOWN)
+ state = PADCONF_PIN_INPUT_PULLDOWN;
+ else
+ state = PADCONF_PIN_INPUT;
+ }
+ return ti_scm_padconf_set_gpiomode(gpio, state);
+}
+
+void
+ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags)
+{
+ unsigned int state;
+ /* Get the current pin state */
+ if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0)
+ *flags = 0;
+ else {
+ switch (state) {
+ case PADCONF_PIN_OUTPUT:
+ *flags = GPIO_PIN_OUTPUT;
+ break;
+ case PADCONF_PIN_INPUT:
+ *flags = GPIO_PIN_INPUT;
+ break;
+ case PADCONF_PIN_INPUT_PULLUP:
+ *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+ break;
+ case PADCONF_PIN_INPUT_PULLDOWN:
+ *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN;
+ break;
+ default:
+ *flags = 0;
+ break;
+ }
+ }
+}
+
diff --git a/sys/arm/ti/omap4/omap4_smc.h b/sys/arm/ti/omap4/omap4_smc.h
new file mode 100644
index 0000000..11ff853
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4_smc.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard. 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 OMAP4_SMC_H_
+#define OMAP4_SMC_H_
+/* Define the various function IDs used by the OMAP4 */
+#define L2CACHE_WRITE_DEBUG_REG 0x100
+#define L2CACHE_CLEAN_INV_RANG 0x101
+#define L2CACHE_ENABLE_L2 0x102
+#define READ_AUX_CORE_REGS 0x103
+#define MODIFY_AUX_CORE_0 0x104
+#define WRITE_AUX_CORE_1 0x105
+#define READ_WKG_CTRL_REG 0x106
+#define CLEAR_WKG_CTRL_REG 0x107
+#define SET_POWER_STATUS_REG 0x108
+#define WRITE_AUXCTRL_REG 0x109
+#define LOCKDOWN_TLB 0x10a
+#define SELECT_TLB_ENTRY_FOR_WRITE 0x10b
+#define READ_TLB_VA_ENTRY 0x10c
+#define WRITE_TLB_VA_ENTRY 0x10d
+#define READ_TLB_PA_ENTRY 0x10e
+#define WRITE_TLB_PA_ENTRY 0x10f
+#define READ_TLB_ATTR_ENTRY 0x110
+#define WRITE_TLB_ATTR_ENTRY 0x111
+#define WRITE_LATENCY_CTRL_REG 0x112
+#define WRITE_PREFETCH_CTRL_REG 0x113
+#endif /* OMAP4_SMC_H_ */
diff --git a/sys/arm/ti/omap4/omap4var.h b/sys/arm/ti/omap4/omap4var.h
new file mode 100644
index 0000000..8246e76
--- /dev/null
+++ b/sys/arm/ti/omap4/omap4var.h
@@ -0,0 +1,91 @@
+/*-
+ * 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. 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 _OMAP4VAR_H_
+#define _OMAP4VAR_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+
+void omap4_mask_all_intr(void);
+void omap4_post_filter_intr(void *arg);
+
+struct omap4_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iotag;
+
+ /* Handles for the two generic interrupt controller (GIC) register mappings */
+ bus_space_handle_t sc_gic_cpu_ioh;
+ bus_space_handle_t sc_gic_dist_ioh;
+
+ /* Handle for the PL310 L2 cache controller */
+ bus_space_handle_t sc_pl310_ioh;
+
+ /* Handle for the global and provate timer register set in the Cortex core */
+ bus_space_handle_t sc_prv_timer_ioh;
+ bus_space_handle_t sc_gbl_timer_ioh;
+
+ /* SCM access */
+ struct resource *sc_scm_mem;
+ int sc_scm_rid;
+};
+
+struct omap4_intr_conf {
+ int num;
+ unsigned int priority;
+ unsigned int target_cpu;
+};
+
+int omap4_setup_intr_controller(device_t dev,
+ const struct omap4_intr_conf *irqs);
+int omap4_setup_gic_cpu(unsigned int prio_mask);
+
+void omap4_init_timer(device_t dev);
+
+int omap4_setup_l2cache_controller(struct omap4_softc *sc);
+void omap4_smc_call(uint32_t fn, uint32_t arg);
+
+#endif /* _OMAP4VAR_H_ */
diff --git a/sys/arm/ti/omap4/pandaboard/files.pandaboard b/sys/arm/ti/omap4/pandaboard/files.pandaboard
new file mode 100644
index 0000000..f658ffb
--- /dev/null
+++ b/sys/arm/ti/omap4/pandaboard/files.pandaboard
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+arm/ti/omap4/pandaboard/pandaboard.c standard
diff --git a/sys/arm/ti/omap4/pandaboard/pandaboard.c b/sys/arm/ti/omap4/pandaboard/pandaboard.c
new file mode 100644
index 0000000..043f2a0
--- /dev/null
+++ b/sys/arm/ti/omap4/pandaboard/pandaboard.c
@@ -0,0 +1,210 @@
+/*-
+ * 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.
+ * 3. 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.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/fdt.h>
+
+#include <arm/ti/omap4/omap4var.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+/* Registers in the SCRM that control the AUX clocks */
+#define SCRM_ALTCLKSRC (0x110)
+#define SCRM_AUXCLK0 (0x0310)
+#define SCRM_AUXCLK1 (0x0314)
+#define SCRM_AUXCLK2 (0x0318)
+#define SCRM_AUXCLK3 (0x031C)
+
+/* Some of the GPIO register set */
+#define GPIO1_OE (0x0134)
+#define GPIO1_CLEARDATAOUT (0x0190)
+#define GPIO1_SETDATAOUT (0x0194)
+#define GPIO2_OE (0x0134)
+#define GPIO2_CLEARDATAOUT (0x0190)
+#define GPIO2_SETDATAOUT (0x0194)
+
+/* Some of the PADCONF register set */
+#define CONTROL_WKUP_PAD0_FREF_CLK3_OUT (0x058)
+#define CONTROL_CORE_PAD1_KPD_COL2 (0x186)
+#define CONTROL_CORE_PAD0_GPMC_WAIT1 (0x08C)
+
+#define REG_WRITE32(r, x) *((volatile uint32_t*)(r)) = (uint32_t)(x)
+#define REG_READ32(r) *((volatile uint32_t*)(r))
+
+#define REG_WRITE16(r, x) *((volatile uint16_t*)(r)) = (uint16_t)(x)
+#define REG_READ16(r) *((volatile uint16_t*)(r))
+
+/**
+ * usb_hub_init - initialises and resets the external USB hub
+ *
+ * The USB hub needs to be held in reset while the power is being applied
+ * and the reference clock is enabled at 19.2MHz. The following is the
+ * layout of the USB hub taken from the Pandaboard reference manual.
+ *
+ *
+ * .-------------. .--------------. .----------------.
+ * | OMAP4430 | | USB3320C | | LAN9514 |
+ * | | | | | USB Hub / Eth |
+ * | CLK | <------ | CLKOUT | | |
+ * | STP | ------> | STP | | |
+ * | DIR | <------ | DIR | | |
+ * | NXT | <------ | NXT | | |
+ * | DAT0 | <-----> | DAT0 | | |
+ * | DAT1 | <-----> | DAT1 DP | <-----> | DP |
+ * | DAT2 | <-----> | DAT2 DM | <-----> | DM |
+ * | DAT3 | <-----> | DAT3 | | |
+ * | DAT4 | <-----> | DAT4 | | |
+ * | DAT5 | <-----> | DAT5 | +----> | N_RESET |
+ * | DAT6 | <-----> | DAT6 | | | |
+ * | DAT7 | <-----> | DAT7 | | | |
+ * | | | | | +-> | VDD33IO |
+ * | AUX_CLK3 | ------> | REFCLK | | +-> | VDD33A |
+ * | | | | | | | |
+ * | GPIO_62 | --+---> | RESET | | | | |
+ * | | | | | | | | |
+ * | | | '--------------' | | '----------------'
+ * | | | .--------------. | |
+ * | | '---->| VOLT CONVERT |--' |
+ * | | '--------------' |
+ * | | |
+ * | | .--------------. |
+ * | GPIO_1 | ------> | TPS73633 |-----'
+ * | | '--------------'
+ * '-------------'
+ *
+ *
+ * RETURNS:
+ * nothing.
+ */
+static void
+usb_hub_init(void)
+{
+ bus_space_handle_t scrm_addr, gpio1_addr, gpio2_addr, scm_addr;
+
+ if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCRM_HWBASE,
+ OMAP44XX_SCRM_SIZE, 0, &scrm_addr) != 0)
+ panic("Couldn't map SCRM registers");
+ if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO1_HWBASE,
+ OMAP44XX_GPIO1_SIZE, 0, &gpio1_addr) != 0)
+ panic("Couldn't map GPIO1 registers");
+ if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO2_HWBASE,
+ OMAP44XX_GPIO2_SIZE, 0, &gpio2_addr) != 0)
+ panic("Couldn't map GPIO2 registers");
+ if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCM_PADCONF_HWBASE,
+ OMAP44XX_SCM_PADCONF_SIZE, 0, &scm_addr) != 0)
+ panic("Couldn't map SCM Padconf registers");
+
+
+
+ /* Need to set FREF_CLK3_OUT to 19.2 MHz and pump it out on pin GPIO_WK31.
+ * We know the SYS_CLK is 38.4Mhz and therefore to get the needed 19.2Mhz,
+ * just use a 2x divider and ensure the SYS_CLK is used as the source.
+ */
+ REG_WRITE32(scrm_addr + SCRM_AUXCLK3, (1 << 16) | /* Divider of 2 */
+ (0 << 1) | /* Use the SYS_CLK as the source */
+ (1 << 8)); /* Enable the clock */
+
+ /* Enable the clock out to the pin (GPIO_WK31).
+ * muxmode=fref_clk3_out, pullup/down=disabled, input buffer=disabled,
+ * wakeup=disabled.
+ */
+ REG_WRITE16(scm_addr + CONTROL_WKUP_PAD0_FREF_CLK3_OUT, 0x0000);
+
+
+ /* Disable the power to the USB hub, drive GPIO1 low */
+ REG_WRITE32(gpio1_addr + GPIO1_OE, REG_READ32(gpio1_addr +
+ GPIO1_OE) & ~(1UL << 1));
+ REG_WRITE32(gpio1_addr + GPIO1_CLEARDATAOUT, (1UL << 1));
+ REG_WRITE16(scm_addr + CONTROL_CORE_PAD1_KPD_COL2, 0x0003);
+
+
+ /* Reset the USB PHY and Hub using GPIO_62 */
+ REG_WRITE32(gpio2_addr + GPIO2_OE,
+ REG_READ32(gpio2_addr + GPIO2_OE) & ~(1UL << 30));
+ REG_WRITE32(gpio2_addr + GPIO2_CLEARDATAOUT, (1UL << 30));
+ REG_WRITE16(scm_addr + CONTROL_CORE_PAD0_GPMC_WAIT1, 0x0003);
+ DELAY(10);
+ REG_WRITE32(gpio2_addr + GPIO2_SETDATAOUT, (1UL << 30));
+
+
+ /* Enable power to the hub (GPIO_1) */
+ REG_WRITE32(gpio1_addr + GPIO1_SETDATAOUT, (1UL << 1));
+ bus_space_unmap(fdtbus_bs_tag, scrm_addr, OMAP44XX_SCRM_SIZE);
+ bus_space_unmap(fdtbus_bs_tag, gpio1_addr, OMAP44XX_GPIO1_SIZE);
+ bus_space_unmap(fdtbus_bs_tag, gpio2_addr, OMAP44XX_GPIO2_SIZE);
+ bus_space_unmap(fdtbus_bs_tag, scm_addr, OMAP44XX_SCM_PADCONF_SIZE);
+}
+
+/**
+ * board_init - initialises the pandaboard
+ * @dummy: ignored
+ *
+ * This function is called before any of the driver are initialised, which is
+ * annoying because it means we can't use the SCM, PRCM and GPIO modules which
+ * would really be useful.
+ *
+ * So we don't have:
+ * - any drivers
+ * - no interrupts
+ *
+ * What we do have:
+ * - virt/phys mappings from the devmap (see omap4.c)
+ * -
+ *
+ *
+ * So we are hamstrung without the useful drivers and we have to go back to
+ * direct register manupulation. Luckly we don't have to do to much, basically
+ * just setup the usb hub/ethernet.
+ *
+ */
+static void
+board_init(void *dummy)
+{
+ /* Initialise the USB phy and hub */
+ usb_hub_init();
+
+ /*
+ * XXX Board identification e.g. read out from FPGA or similar should
+ * go here
+ */
+}
+
+SYSINIT(board_init, SI_SUB_CPU, SI_ORDER_THIRD, board_init, NULL);
diff --git a/sys/arm/ti/omap4/pandaboard/std.pandaboard b/sys/arm/ti/omap4/pandaboard/std.pandaboard
new file mode 100644
index 0000000..6a65f66
--- /dev/null
+++ b/sys/arm/ti/omap4/pandaboard/std.pandaboard
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+include "../ti/omap4/std.omap4"
+files "../ti/omap4/pandaboard/files.pandaboard"
diff --git a/sys/arm/ti/omap4/std.omap4 b/sys/arm/ti/omap4/std.omap4
new file mode 100644
index 0000000..056a823
--- /dev/null
+++ b/sys/arm/ti/omap4/std.omap4
@@ -0,0 +1,21 @@
+# Omap4430 generic configuration
+#$FreeBSD$
+files "../ti/omap4/files.omap4"
+include "../ti/std.ti"
+makeoption ARM_LITTLE_ENDIAN
+
+# Physical memory starts at 0x80000000. We assume images are loaded at
+# 0x80200000, e.g. from u-boot with 'fatload mmc 0 0x80200000 kernel.bin'
+#
+#
+options PHYSADDR=0x80000000
+options KERNPHYSADDR=0x80200000
+makeoptions KERNPHYSADDR=0x80200000
+options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
+makeoptions KERNVIRTADDR=0xc0200000
+
+options STARTUP_PAGETABLE_ADDR=0x80000000
+
+options SOC_OMAP4
+
+options ARM_L2_PIPT
diff --git a/sys/arm/ti/std.ti b/sys/arm/ti/std.ti
new file mode 100644
index 0000000..f3bc4fb
--- /dev/null
+++ b/sys/arm/ti/std.ti
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+cpu CPU_CORTEXA
+
+files "../ti/files.ti"
diff --git a/sys/arm/ti/ti_cpuid.c b/sys/arm/ti/ti_cpuid.c
new file mode 100644
index 0000000..16de8aa
--- /dev/null
+++ b/sys/arm/ti/ti_cpuid.c
@@ -0,0 +1,285 @@
+/*-
+ * 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.
+ */
+
+#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 <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_cpuid.h>
+
+#include <arm/ti/omap4/omap4_reg.h>
+#include <arm/ti/omap3/omap3_reg.h>
+#include <arm/ti/am335x/am335x_reg.h>
+
+#define OMAP4_STD_FUSE_DIE_ID_0 0x2200
+#define OMAP4_ID_CODE 0x2204
+#define OMAP4_STD_FUSE_DIE_ID_1 0x2208
+#define OMAP4_STD_FUSE_DIE_ID_2 0x220C
+#define OMAP4_STD_FUSE_DIE_ID_3 0x2210
+#define OMAP4_STD_FUSE_PROD_ID_0 0x2214
+#define OMAP4_STD_FUSE_PROD_ID_1 0x2218
+
+#define OMAP3_ID_CODE 0xA204
+
+static uint32_t chip_revision = 0xffffffff;
+
+/**
+ * ti_revision - Returns the revision number of the device
+ *
+ * Simply returns an identifier for the revision of the chip we are running
+ * on.
+ *
+ * RETURNS
+ * A 32-bit identifier for the current chip
+ */
+uint32_t
+ti_revision(void)
+{
+ return chip_revision;
+}
+
+/**
+ * omap4_get_revision - determines omap4 revision
+ *
+ * Reads the registers to determine the revision of the chip we are currently
+ * running on. Stores the information in global variables.
+ *
+ *
+ */
+static void
+omap4_get_revision(void)
+{
+ uint32_t id_code;
+ uint32_t revision;
+ uint32_t hawkeye;
+ bus_space_handle_t bsh;
+
+ /* The chip revsion is read from the device identification registers and
+ * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
+ * 0x4A00_2218. This is part of the L4_CORE memory range and should have
+ * been mapped in by the machdep.c code.
+ *
+ * STD_FUSE_DIE_ID_0 0x4A00 2200
+ * ID_CODE 0x4A00 2204 (this is the only one we need)
+ * STD_FUSE_DIE_ID_1 0x4A00 2208
+ * STD_FUSE_DIE_ID_2 0x4A00 220C
+ * STD_FUSE_DIE_ID_3 0x4A00 2210
+ * STD_FUSE_PROD_ID_0 0x4A00 2214
+ * STD_FUSE_PROD_ID_1 0x4A00 2218
+ */
+ // id_code = REG_READ32(OMAP44XX_L4_CORE_VBASE + OMAP4_ID_CODE);
+ //FIXME Should we map somewhere else?
+ bus_space_map(fdtbus_bs_tag,OMAP44XX_L4_CORE_HWBASE, 0x4000, 0, &bsh);
+ id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP4_ID_CODE);
+ bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000);
+
+ hawkeye = ((id_code >> 12) & 0xffff);
+ revision = ((id_code >> 28) & 0xf);
+
+ /* Apparently according to the linux code there were some ES2.0 samples that
+ * have the wrong id code and report themselves as ES1.0 silicon. So used
+ * the ARM cpuid to get the correct revision.
+ */
+ if (revision == 0) {
+ id_code = cpufunc_id();
+ revision = (id_code & 0xf) - 1;
+ }
+
+ switch (hawkeye) {
+ case 0xB852:
+ if (revision == 0)
+ chip_revision = OMAP4430_REV_ES1_0;
+ else
+ chip_revision = OMAP4430_REV_ES2_0;
+ break;
+ case 0xB95C:
+ if (revision == 3)
+ chip_revision = OMAP4430_REV_ES2_1;
+ else if (revision == 4)
+ chip_revision = OMAP4430_REV_ES2_2;
+ else
+ chip_revision = OMAP4430_REV_ES2_3;
+ break;
+ default:
+ /* Default to the latest revision if we can't determine type */
+ chip_revision = OMAP4430_REV_ES2_3;
+ break;
+ }
+ printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
+ OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision),
+ OMAP_REV_MINOR(chip_revision));
+}
+
+/**
+ * omap3_get_revision - determines omap3 revision
+ *
+ * Reads the registers to determine the revision of the chip we are currently
+ * running on. Stores the information in global variables.
+ *
+ * WARNING: This function currently only really works for OMAP3530 devices.
+ *
+ *
+ *
+ */
+static void
+omap3_get_revision(void)
+{
+ uint32_t id_code;
+ uint32_t revision;
+ uint32_t hawkeye;
+ bus_space_handle_t bsh;
+
+ /* The chip revsion is read from the device identification registers and
+ * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
+ * 0x4A00_2218. This is part of the L4_CORE memory range and should have
+ * been mapped in by the machdep.c code.
+ *
+ * CONTROL_IDCODE 0x4830 A204 (this is the only one we need)
+ *
+ *
+ */
+ //id_code = REG_READ32(OMAP35XX_L4_WAKEUP_VBASE + OMAP3_ID_CODE);
+ bus_space_map(fdtbus_bs_tag,OMAP35XX_L4_WAKEUP_HWBASE, 0x10000, 0, &bsh);
+ id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP3_ID_CODE);
+ bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000);
+
+ hawkeye = ((id_code >> 12) & 0xffff);
+ revision = ((id_code >> 28) & 0xf);
+
+ switch (hawkeye) {
+ case 0xB6D6:
+ chip_revision = OMAP3350_REV_ES1_0;
+ break;
+ case 0xB7AE:
+ if (revision == 1)
+ chip_revision = OMAP3530_REV_ES2_0;
+ else if (revision == 2)
+ chip_revision = OMAP3530_REV_ES2_1;
+ else if (revision == 3)
+ chip_revision = OMAP3530_REV_ES3_0;
+ else if (revision == 4)
+ chip_revision = OMAP3530_REV_ES3_1;
+ else if (revision == 7)
+ chip_revision = OMAP3530_REV_ES3_1_2;
+ break;
+ default:
+ /* Default to the latest revision if we can't determine type */
+ chip_revision = OMAP3530_REV_ES3_1_2;
+ break;
+ }
+ printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
+ OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision),
+ OMAP_REV_MINOR(chip_revision));
+}
+
+static void
+am335x_get_revision(void)
+{
+ uint32_t dev_feature;
+ uint8_t cpu_last_char;
+ bus_space_handle_t bsh;
+
+ bus_space_map(fdtbus_bs_tag, AM335X_CONTROL_BASE, AM335X_CONTROL_SIZE, 0, &bsh);
+ chip_revision = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEVICE_ID);
+ dev_feature = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEV_FEATURE);
+ bus_space_unmap(fdtbus_bs_tag, bsh, AM335X_CONTROL_SIZE);
+
+ switch (dev_feature) {
+ case 0x00FF0382:
+ cpu_last_char='2';
+ break;
+ case 0x20FF0382:
+ cpu_last_char='4';
+ break;
+ case 0x00FF0383:
+ cpu_last_char='6';
+ break;
+ case 0x00FE0383:
+ cpu_last_char='7';
+ break;
+ case 0x20FF0383:
+ cpu_last_char='8';
+ break;
+ case 0x20FE0383:
+ cpu_last_char='9';
+ break;
+ default:
+ cpu_last_char='x';
+ }
+
+ printf("Texas Instruments AM335%c Processor, Revision ES1.%u\n",
+ cpu_last_char, AM335X_DEVREV(chip_revision));
+}
+
+/**
+ * ti_cpu_ident - attempts to identify the chip we are running on
+ * @dummy: ignored
+ *
+ * This function is called before any of the driver are initialised, however
+ * the basic virt to phys maps have been setup in machdep.c so we can still
+ * access the required registers, we just have to use direct register reads
+ * and writes rather than going through the bus stuff.
+ *
+ *
+ */
+static void
+ti_cpu_ident(void *dummy)
+{
+ switch(ti_chip()) {
+ case CHIP_OMAP_3:
+ omap3_get_revision();
+ break;
+ case CHIP_OMAP_4:
+ omap4_get_revision();
+ break;
+ case CHIP_AM335X:
+ am335x_get_revision();
+ break;
+ default:
+ panic("Unknown chip type, fixme!\n");
+ }
+}
+
+SYSINIT(ti_cpu_ident, SI_SUB_CPU, SI_ORDER_SECOND, ti_cpu_ident, NULL);
diff --git a/sys/arm/ti/ti_cpuid.h b/sys/arm/ti/ti_cpuid.h
new file mode 100644
index 0000000..f68f54c
--- /dev/null
+++ b/sys/arm/ti/ti_cpuid.h
@@ -0,0 +1,77 @@
+/*-
+ * 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 AM335X_DEVREV(x) ((x) >> 28)
+
+#define CHIP_OMAP_3 0
+#define CHIP_OMAP_4 1
+#define CHIP_AM335X 2
+
+static __inline int ti_chip(void)
+{
+#if defined(SOC_OMAP4)
+ return CHIP_OMAP_4;
+#elif defined(SOC_OMAP3)
+ return CHIP_OMAP_3;
+#elif defined(SOC_TI_AM335X)
+ return CHIP_AM335X;
+#else
+# error Chip type not defined, ensure SOC_xxxx is defined
+#endif
+}
+
+uint32_t ti_revision(void);
+
+#endif /* _TI_CPUID_H_ */
diff --git a/sys/arm/ti/ti_edma3.c b/sys/arm/ti/ti_edma3.c
new file mode 100644
index 0000000..b757010
--- /dev/null
+++ b/sys/arm/ti/ti_edma3.c
@@ -0,0 +1,424 @@
+/*-
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * 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.
+ * 3. Neither the name of authors nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * 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/endian.h>
+#include <sys/mbuf.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <sys/sockio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <arm/ti/ti_edma3.h>
+
+#define TI_EDMA3_NUM_TCS 3
+#define TI_EDMA3_NUM_IRQS 3
+#define TI_EDMA3_NUM_DMA_CHS 64
+#define TI_EDMA3_NUM_QDMA_CHS 8
+
+#define TI_EDMA3CC_PID 0x000
+#define TI_EDMA3CC_DCHMAP(p) (0x100 + ((p)*4))
+#define TI_EDMA3CC_DMAQNUM(n) (0x240 + ((n)*4))
+#define TI_EDMA3CC_QDMAQNUM 0x260
+#define TI_EDMA3CC_EMCR 0x308
+#define TI_EDMA3CC_EMCRH 0x30C
+#define TI_EDMA3CC_QEMCR 0x314
+#define TI_EDMA3CC_CCERR 0x318
+#define TI_EDMA3CC_CCERRCLR 0x31C
+#define TI_EDMA3CC_DRAE(p) (0x340 + ((p)*8))
+#define TI_EDMA3CC_DRAEH(p) (0x344 + ((p)*8))
+#define TI_EDMA3CC_QRAE(p) (0x380 + ((p)*4))
+#define TI_EDMA3CC_S_ESR(p) (0x2010 + ((p)*0x200))
+#define TI_EDMA3CC_S_ESRH(p) (0x2014 + ((p)*0x200))
+#define TI_EDMA3CC_S_SECR(p) (0x2040 + ((p)*0x200))
+#define TI_EDMA3CC_S_SECRH(p) (0x2044 + ((p)*0x200))
+#define TI_EDMA3CC_S_EESR(p) (0x2030 + ((p)*0x200))
+#define TI_EDMA3CC_S_EESRH(p) (0x2034 + ((p)*0x200))
+#define TI_EDMA3CC_S_IESR(p) (0x2060 + ((p)*0x200))
+#define TI_EDMA3CC_S_IESRH(p) (0x2064 + ((p)*0x200))
+#define TI_EDMA3CC_S_IPR(p) (0x2068 + ((p)*0x200))
+#define TI_EDMA3CC_S_IPRH(p) (0x206C + ((p)*0x200))
+#define TI_EDMA3CC_S_QEESR(p) (0x208C + ((p)*0x200))
+
+#define TI_EDMA3CC_PARAM_OFFSET 0x4000
+#define TI_EDMA3CC_OPT(p) (TI_EDMA3CC_PARAM_OFFSET + 0x0 + ((p)*0x20))
+
+#define TI_EDMA3CC_DMAQNUM_SET(c,q) ((0x7 & (q)) << (((c) % 8) * 4))
+#define TI_EDMA3CC_DMAQNUM_CLR(c) (~(0x7 << (((c) % 8) * 4)))
+#define TI_EDMA3CC_QDMAQNUM_SET(c,q) ((0x7 & (q)) << ((c) * 4))
+#define TI_EDMA3CC_QDMAQNUM_CLR(c) (~(0x7 << ((c) * 4)))
+
+#define TI_EDMA3CC_OPT_TCC_CLR (~(0x3F000))
+#define TI_EDMA3CC_OPT_TCC_SET(p) (((0x3F000 >> 12) & (p)) << 12)
+
+struct ti_edma3_softc {
+ device_t sc_dev;
+ struct resource * mem_res[TI_EDMA3_NUM_TCS+1];
+ struct resource * irq_res[TI_EDMA3_NUM_IRQS];
+ void *ih_cookie[TI_EDMA3_NUM_IRQS];
+};
+
+static struct ti_edma3_softc *ti_edma3_sc = NULL;
+
+static struct resource_spec ti_edma3_mem_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+static struct resource_spec ti_edma3_irq_spec[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+/* Read/Write macros */
+#define ti_edma3_cc_rd_4(reg) bus_read_4(ti_edma3_sc->mem_res[0], reg)
+#define ti_edma3_cc_wr_4(reg, val) bus_write_4(ti_edma3_sc->mem_res[0], reg, val)
+#define ti_edma3_tc_rd_4(c, reg) bus_read_4(ti_edma3_sc->mem_res[c+1], reg)
+#define ti_edma3_tc_wr_4(c, reg, val) bus_write_4(ti_edma3_sc->mem_res[c+1], reg, val)
+
+static void ti_edma3_intr_comp(void *arg);
+static void ti_edma3_intr_mperr(void *arg);
+static void ti_edma3_intr_err(void *arg);
+
+static struct {
+ driver_intr_t *handler;
+ char * description;
+} ti_edma3_intrs[TI_EDMA3_NUM_IRQS] = {
+ { ti_edma3_intr_comp, "EDMA Completion Interrupt" },
+ { ti_edma3_intr_mperr, "EDMA Memory Protection Error Interrupt" },
+ { ti_edma3_intr_err, "EDMA Error Interrupt" },
+};
+
+static int
+ti_edma3_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,edma"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI EDMA Controller");
+ return (0);
+}
+
+static int
+ti_edma3_attach(device_t dev)
+{
+ struct ti_edma3_softc *sc = device_get_softc(dev);
+ uint32_t reg;
+ int err;
+ int i;
+
+ if (ti_edma3_sc)
+ return (ENXIO);
+
+ ti_edma3_sc = sc;
+ sc->sc_dev = dev;
+
+ /* Request the memory resources */
+ err = bus_alloc_resources(dev, ti_edma3_mem_spec, sc->mem_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate mem resources\n");
+ return (ENXIO);
+ }
+
+ /* Request the IRQ resources */
+ err = bus_alloc_resources(dev, ti_edma3_irq_spec, sc->irq_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate irq resources\n");
+ return (ENXIO);
+ }
+
+ /* Enable Channel Controller */
+ ti_prcm_clk_enable(EDMA_TPCC_CLK);
+
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_PID);
+
+ device_printf(dev, "EDMA revision %08x\n", reg);
+
+
+ /* Attach interrupt handlers */
+ for (i = 0; i < TI_EDMA3_NUM_IRQS; ++i) {
+ err = bus_setup_intr(dev, sc->irq_res[i], INTR_TYPE_MISC |
+ INTR_MPSAFE, NULL, *ti_edma3_intrs[i].handler,
+ sc, &sc->ih_cookie[i]);
+ if (err) {
+ device_printf(dev, "could not setup %s\n",
+ ti_edma3_intrs[i].description);
+ return (err);
+ }
+ }
+
+ return (0);
+}
+
+static device_method_t ti_edma3_methods[] = {
+ DEVMETHOD(device_probe, ti_edma3_probe),
+ DEVMETHOD(device_attach, ti_edma3_attach),
+ {0, 0},
+};
+
+static driver_t ti_edma3_driver = {
+ "ti_edma3",
+ ti_edma3_methods,
+ sizeof(struct ti_edma3_softc),
+};
+static devclass_t ti_edma3_devclass;
+
+DRIVER_MODULE(ti_edma3, simplebus, ti_edma3_driver, ti_edma3_devclass, 0, 0);
+MODULE_DEPEND(ti_edma3, ti_prcm, 1, 1, 1);
+
+static void
+ti_edma3_intr_comp(void *arg)
+{
+ printf("%s: unimplemented\n", __func__);
+}
+
+static void
+ti_edma3_intr_mperr(void *arg)
+{
+ printf("%s: unimplemented\n", __func__);
+}
+
+static void
+ti_edma3_intr_err(void *arg)
+{
+ printf("%s: unimplemented\n", __func__);
+}
+
+void
+ti_edma3_init(unsigned int eqn)
+{
+ uint32_t reg;
+ int i;
+
+ /* on AM335x Event queue 0 is always mapped to Transfer Controller 0,
+ * event queue 1 to TC2, etc. So we are asking PRCM to power on specific
+ * TC based on what event queue we need to initialize */
+ ti_prcm_clk_enable(EDMA_TPTC0_CLK + eqn);
+
+ /* Clear Event Missed Regs */
+ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, 0xFFFFFFFF);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 0xFFFFFFFF);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_QEMCR, 0xFFFFFFFF);
+
+ /* Clear Error Reg */
+ ti_edma3_cc_wr_4(TI_EDMA3CC_CCERRCLR, 0xFFFFFFFF);
+
+ /* Enable DMA channels 0-63 */
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), 0xFFFFFFFF);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), 0xFFFFFFFF);
+
+ for (i = 0; i < 64; i++) {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DCHMAP(i), i<<5);
+ }
+
+ /* Initialize the DMA Queue Number Registers */
+ for (i = 0; i < TI_EDMA3_NUM_DMA_CHS; i++) {
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(i>>3));
+ reg &= TI_EDMA3CC_DMAQNUM_CLR(i);
+ reg |= TI_EDMA3CC_DMAQNUM_SET(i, eqn);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(i>>3), reg);
+ }
+
+ /* Enable the QDMA Region access for all channels */
+ ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), (1 << TI_EDMA3_NUM_QDMA_CHS) - 1);
+
+ /*Initialize QDMA Queue Number Registers */
+ for (i = 0; i < TI_EDMA3_NUM_QDMA_CHS; i++) {
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM);
+ reg &= TI_EDMA3CC_QDMAQNUM_CLR(i);
+ reg |= TI_EDMA3CC_QDMAQNUM_SET(i, eqn);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg);
+ }
+}
+
+#ifdef notyet
+int
+ti_edma3_enable_event_intr(unsigned int ch)
+{
+ uint32_t reg;
+
+ if (ch >= TI_EDMA3_NUM_DMA_CHS)
+ return (EINVAL);
+
+ if (ch < 32) {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESR(0), 1 << ch);
+ } else {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESRH(0), 1 << (ch - 32));
+ }
+ return 0;
+}
+#endif
+
+int
+ti_edma3_request_dma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn)
+{
+ uint32_t reg;
+
+ if (ch >= TI_EDMA3_NUM_DMA_CHS)
+ return (EINVAL);
+
+ /* Enable the DMA channel in the DRAE/DRAEH registers */
+ if (ch < 32) {
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAE(0));
+ reg |= (0x01 << ch);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), reg);
+ } else {
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAEH(0));
+ reg |= (0x01 << (ch - 32));
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), reg);
+ }
+
+ /* Associate DMA Channel to Event Queue */
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(ch >> 3));
+ reg &= TI_EDMA3CC_DMAQNUM_CLR(ch);
+ reg |= TI_EDMA3CC_DMAQNUM_SET((ch), eqn);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(ch >> 3), reg);
+
+ /* Set TCC in corresponding PaRAM Entry */
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch));
+ reg &= TI_EDMA3CC_OPT_TCC_CLR;
+ reg |= TI_EDMA3CC_OPT_TCC_SET(ch);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg);
+
+ return 0;
+}
+
+int
+ti_edma3_request_qdma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn)
+{
+ uint32_t reg;
+
+ if (ch >= TI_EDMA3_NUM_DMA_CHS)
+ return (EINVAL);
+
+ /* Enable the QDMA channel in the QRAE registers */
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QRAE(0));
+ reg |= (0x01 << ch);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), reg);
+
+ /* Associate QDMA Channel to Event Queue */
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM);
+ reg |= TI_EDMA3CC_QDMAQNUM_SET(ch, eqn);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg);
+
+ /* Set TCC in corresponding PaRAM Entry */
+ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch));
+ reg &= TI_EDMA3CC_OPT_TCC_CLR;
+ reg |= TI_EDMA3CC_OPT_TCC_SET(ch);
+ ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg);
+
+ return 0;
+}
+
+int
+ti_edma3_enable_transfer_manual(unsigned int ch)
+{
+ if (ch >= TI_EDMA3_NUM_DMA_CHS)
+ return (EINVAL);
+
+ /* set corresponding bit in ESR/ESRH to set a event */
+ if (ch < 32) {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESR(0), 1 << ch);
+ } else {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESRH(0), 1 << (ch - 32));
+ }
+
+ return 0;
+}
+
+int
+ti_edma3_enable_transfer_qdma(unsigned int ch)
+{
+ if (ch >= TI_EDMA3_NUM_QDMA_CHS)
+ return (EINVAL);
+
+ /* set corresponding bit in QEESR to enable QDMA event */
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_QEESR(0), (1 << ch));
+
+ return 0;
+}
+
+int
+ti_edma3_enable_transfer_event(unsigned int ch)
+{
+ if (ch >= TI_EDMA3_NUM_DMA_CHS)
+ return (EINVAL);
+
+ /* Clear SECR(H) & EMCR(H) to clean any previous NULL request
+ * and set corresponding bit in EESR to enable DMA event */
+ if(ch < 32) {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECR(0), (1 << ch));
+ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, (1 << ch));
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESR(0), (1 << ch));
+ } else {
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECRH(0), 1 << (ch - 32));
+ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 1 << (ch - 32));
+ ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESRH(0), 1 << (ch - 32));
+ }
+
+ return 0;
+}
+
+void
+ti_edma3_param_write(unsigned int ch, struct ti_edma3cc_param_set *prs)
+{
+ bus_write_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch),
+ (uint32_t *) prs, 8);
+}
+
+void
+ti_edma3_param_read(unsigned int ch, struct ti_edma3cc_param_set *prs)
+{
+ bus_read_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch),
+ (uint32_t *) prs, 8);
+}
diff --git a/sys/arm/ti/ti_edma3.h b/sys/arm/ti/ti_edma3.h
new file mode 100644
index 0000000..f149c9c
--- /dev/null
+++ b/sys/arm/ti/ti_edma3.h
@@ -0,0 +1,81 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TI_EDMA3_H_
+#define _TI_EDMA3_H_
+
+/* Direct Mapped EDMA3 Events */
+#define TI_EDMA3_EVENT_SDTXEVT1 2
+#define TI_EDMA3_EVENT_SDRXEVT1 3
+#define TI_EDMA3_EVENT_SDTXEVT0 24
+#define TI_EDMA3_EVENT_SDRXEVT0 25
+
+struct ti_edma3cc_param_set {
+ struct {
+ uint32_t sam:1; /* Source address mode */
+ uint32_t dam:1; /* Destination address mode */
+ uint32_t syncdim:1; /* Transfer synchronization dimension */
+ uint32_t static_set:1; /* Static Set */
+ uint32_t :4;
+ uint32_t fwid:3; /* FIFO Width */
+ uint32_t tccmode:1; /* Transfer complete code mode */
+ uint32_t tcc:6; /* Transfer complete code */
+ uint32_t :2;
+ uint32_t tcinten:1; /* Transfer complete interrupt enable */
+ uint32_t itcinten:1; /* Intermediate xfer completion intr. ena */
+ uint32_t tcchen:1; /* Transfer complete chaining enable */
+ uint32_t itcchen:1; /* Intermediate xfer completion chaining ena */
+ uint32_t privid:4; /* Privilege identification */
+ uint32_t :3;
+ uint32_t priv:1; /* Privilege level */
+ } opt;
+ uint32_t src; /* Channel Source Address */
+ uint16_t acnt; /* Count for 1st Dimension */
+ uint16_t bcnt; /* Count for 2nd Dimension */
+ uint32_t dst; /* Channel Destination Address */
+ int16_t srcbidx; /* Source B Index */
+ int16_t dstbidx; /* Destination B Index */
+ uint16_t link; /* Link Address */
+ uint16_t bcntrld; /* BCNT Reload */
+ int16_t srccidx; /* Source C Index */
+ int16_t dstcidx; /* Destination C Index */
+ uint16_t ccnt; /* Count for 3rd Dimension */
+ uint16_t reserved; /* Reserved */
+};
+
+void ti_edma3_init(unsigned int eqn);
+int ti_edma3_request_dma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn);
+int ti_edma3_request_qdma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn);
+int ti_edma3_enable_transfer_manual(unsigned int ch);
+int ti_edma3_enable_transfer_qdma(unsigned int ch);
+int ti_edma3_enable_transfer_event(unsigned int ch);
+
+void ti_edma3_param_write(unsigned int ch, struct ti_edma3cc_param_set *prs);
+void ti_edma3_param_read(unsigned int ch, struct ti_edma3cc_param_set *prs);
+
+#endif /* _TI_EDMA3_H_ */
diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c
new file mode 100644
index 0000000..979326fa
--- /dev/null
+++ b/sys/arm/ti/ti_gpio.c
@@ -0,0 +1,802 @@
+/*-
+ * 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.
+ */
+
+/**
+ * Very simple GPIO (general purpose IO) driver module for TI OMAP SoC's.
+ *
+ * Currently this driver only does the basics, get a value on a pin & set a
+ * value on a pin. Hopefully over time I'll expand this to be a bit more generic
+ * and support interrupts and other various bits on the SoC can do ... in the
+ * meantime this is all you get.
+ *
+ * Beware the OMA datasheet(s) lists GPIO banks 1-6, whereas I've used 0-5 here
+ * in the code.
+ *
+ *
+ */
+
+#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/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+ /* Register definitions */
+#define TI_GPIO_REVISION 0x0000
+#define TI_GPIO_SYSCONFIG 0x0010
+#if defined(SOC_OMAP3)
+#define TI_GPIO_REVISION 0x0000
+#define TI_GPIO_SYSCONFIG 0x0010
+#define TI_GPIO_SYSSTATUS 0x0014
+#define TI_GPIO_IRQSTATUS1 0x0018
+#define TI_GPIO_IRQENABLE1 0x001C
+#define TI_GPIO_WAKEUPENABLE 0x0020
+#define TI_GPIO_IRQSTATUS2 0x0028
+#define TI_GPIO_IRQENABLE2 0x002C
+#define TI_GPIO_CTRL 0x0030
+#define TI_GPIO_OE 0x0034
+#define TI_GPIO_DATAIN 0x0038
+#define TI_GPIO_DATAOUT 0x003C
+#define TI_GPIO_LEVELDETECT0 0x0040
+#define TI_GPIO_LEVELDETECT1 0x0044
+#define TI_GPIO_RISINGDETECT 0x0048
+#define TI_GPIO_FALLINGDETECT 0x004C
+#define TI_GPIO_DEBOUNCENABLE 0x0050
+#define TI_GPIO_DEBOUNCINGTIME 0x0054
+#define TI_GPIO_CLEARIRQENABLE1 0x0060
+#define TI_GPIO_SETIRQENABLE1 0x0064
+#define TI_GPIO_CLEARIRQENABLE2 0x0070
+#define TI_GPIO_SETIRQENABLE2 0x0074
+#define TI_GPIO_CLEARWKUENA 0x0080
+#define TI_GPIO_SETWKUENA 0x0084
+#define TI_GPIO_CLEARDATAOUT 0x0090
+#define TI_GPIO_SETDATAOUT 0x0094
+#elif defined(SOC_OMAP4) || defined(SOC_TI_AM335X)
+#define TI_GPIO_IRQSTATUS_RAW_0 0x0024
+#define TI_GPIO_IRQSTATUS_RAW_1 0x0028
+#define TI_GPIO_IRQSTATUS_0 0x002C
+#define TI_GPIO_IRQSTATUS_1 0x0030
+#define TI_GPIO_IRQSTATUS_SET_0 0x0034
+#define TI_GPIO_IRQSTATUS_SET_1 0x0038
+#define TI_GPIO_IRQSTATUS_CLR_0 0x003C
+#define TI_GPIO_IRQSTATUS_CLR_1 0x0040
+#define TI_GPIO_IRQWAKEN_0 0x0044
+#define TI_GPIO_IRQWAKEN_1 0x0048
+#define TI_GPIO_SYSSTATUS 0x0114
+#define TI_GPIO_IRQSTATUS1 0x0118
+#define TI_GPIO_IRQENABLE1 0x011C
+#define TI_GPIO_WAKEUPENABLE 0x0120
+#define TI_GPIO_IRQSTATUS2 0x0128
+#define TI_GPIO_IRQENABLE2 0x012C
+#define TI_GPIO_CTRL 0x0130
+#define TI_GPIO_OE 0x0134
+#define TI_GPIO_DATAIN 0x0138
+#define TI_GPIO_DATAOUT 0x013C
+#define TI_GPIO_LEVELDETECT0 0x0140
+#define TI_GPIO_LEVELDETECT1 0x0144
+#define TI_GPIO_RISINGDETECT 0x0148
+#define TI_GPIO_FALLINGDETECT 0x014C
+#define TI_GPIO_DEBOUNCENABLE 0x0150
+#define TI_GPIO_DEBOUNCINGTIME 0x0154
+#define TI_GPIO_CLEARIRQENABLE1 0x0160
+#define TI_GPIO_SETIRQENABLE1 0x0164
+#define TI_GPIO_CLEARIRQENABLE2 0x0170
+#define TI_GPIO_SETIRQENABLE2 0x0174
+#define TI_GPIO_CLEARWKUPENA 0x0180
+#define TI_GPIO_SETWKUENA 0x0184
+#define TI_GPIO_CLEARDATAOUT 0x0190
+#define TI_GPIO_SETDATAOUT 0x0194
+#else
+#error "Unknown SoC"
+#endif
+
+ /*Other SoC Specific definitions*/
+#if defined(SOC_OMAP3)
+#define MAX_GPIO_BANKS 6
+#define FIRST_GPIO_BANK 1
+#define PINS_PER_BANK 32
+#define TI_GPIO_REV 0x00000025
+#elif defined(SOC_OMAP4)
+#define MAX_GPIO_BANKS 6
+#define FIRST_GPIO_BANK 1
+#define PINS_PER_BANK 32
+#define TI_GPIO_REV 0x50600801
+#elif defined(SOC_TI_AM335X)
+#define MAX_GPIO_BANKS 4
+#define FIRST_GPIO_BANK 0
+#define PINS_PER_BANK 32
+#define TI_GPIO_REV 0x50600801
+#endif
+
+/**
+ * ti_gpio_mem_spec - Resource specification used when allocating resources
+ * ti_gpio_irq_spec - Resource specification used when allocating resources
+ *
+ * This driver module can have up to six independent memory regions, each
+ * region typically controls 32 GPIO pins.
+ */
+static struct resource_spec ti_gpio_mem_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_OPTIONAL },
+#if !defined(SOC_TI_AM335X)
+ { SYS_RES_MEMORY, 4, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_MEMORY, 5, RF_ACTIVE | RF_OPTIONAL },
+#endif
+ { -1, 0, 0 }
+};
+static struct resource_spec ti_gpio_irq_spec[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL },
+#if !defined(SOC_TI_AM335X)
+ { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL },
+#endif
+ { -1, 0, 0 }
+};
+
+/**
+ * Structure that stores the driver context.
+ *
+ * This structure is allocated during driver attach.
+ */
+struct ti_gpio_softc {
+ device_t sc_dev;
+
+ /* The memory resource(s) for the PRCM register set, when the device is
+ * created the caller can assign up to 4 memory regions.
+ */
+ struct resource* sc_mem_res[MAX_GPIO_BANKS];
+ struct resource* sc_irq_res[MAX_GPIO_BANKS];
+
+ /* The handle for the register IRQ handlers */
+ void* sc_irq_hdl[MAX_GPIO_BANKS];
+
+ /* The following describes the H/W revision of each of the GPIO banks */
+ uint32_t sc_revision[MAX_GPIO_BANKS];
+
+ struct mtx sc_mtx;
+};
+
+/**
+ * Macros for driver mutex locking
+ */
+#define TI_GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define TI_GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define TI_GPIO_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "ti_gpio", MTX_DEF)
+#define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+/**
+ * ti_gpio_read_4 - reads a 16-bit value from one of the PADCONFS registers
+ * @sc: GPIO device context
+ * @bank: The bank to read from
+ * @off: The offset of a register from the GPIO register address range
+ *
+ *
+ * RETURNS:
+ * 32-bit value read from the register.
+ */
+static inline uint32_t
+ti_gpio_read_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off)
+{
+ return (bus_read_4(sc->sc_mem_res[bank], off));
+}
+
+/**
+ * ti_gpio_write_4 - writes a 32-bit value to one of the PADCONFS registers
+ * @sc: GPIO device context
+ * @bank: The bank to write to
+ * @off: The offset of a register from the GPIO register address range
+ * @val: The value to write into the register
+ *
+ * RETURNS:
+ * nothing
+ */
+static inline void
+ti_gpio_write_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off,
+ uint32_t val)
+{
+ bus_write_4(sc->sc_mem_res[bank], off, val);
+}
+
+/**
+ * ti_gpio_pin_max - Returns the maximum number of GPIO pins
+ * @dev: gpio device handle
+ * @maxpin: pointer to a value that upon return will contain the maximum number
+ * of pins in the device.
+ *
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_max(device_t dev, int *maxpin)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ unsigned int i;
+ unsigned int banks = 0;
+
+ TI_GPIO_LOCK(sc);
+
+ /* Calculate how many valid banks we have and then multiply that by 32 to
+ * give use the total number of pins.
+ */
+ for (i = 0; i < MAX_GPIO_BANKS; i++) {
+ if (sc->sc_mem_res[i] != NULL)
+ banks++;
+ }
+
+ *maxpin = (banks * PINS_PER_BANK);
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_getcaps - Gets the capabilties of a given pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @caps: pointer to a value that upon return will contain the capabilities
+ *
+ * Currently all pins have the same capability, notably:
+ * - GPIO_PIN_INPUT
+ * - GPIO_PIN_OUTPUT
+ * - GPIO_PIN_PULLUP
+ * - GPIO_PIN_PULLDOWN
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |GPIO_PIN_PULLUP |
+ GPIO_PIN_PULLDOWN);
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_getflags - Gets the current flags of a given pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @flags: upon return will contain the current flags of the pin
+ *
+ * Reads the current flags of a given pin, here we actually read the H/W
+ * registers to determine the flags, rather than storing the value in the
+ * setflags call.
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Get the current pin state */
+ ti_scm_padconf_get_gpioflags(pin, flags);
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_getname - Gets the name of a given pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @name: buffer to put the name in
+ *
+ * The driver simply calls the pins gpio_n, where 'n' is obviously the number
+ * of the pin.
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Set a very simple name */
+ snprintf(name, GPIOMAXNAME, "gpio_%u", pin);
+ name[GPIOMAXNAME - 1] = '\0';
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_setflags - Sets the flags for a given pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @flags: the flags to set
+ *
+ * The flags of the pin correspond to things like input/output mode, pull-ups,
+ * pull-downs, etc. This driver doesn't support all flags, only the following:
+ * - GPIO_PIN_INPUT
+ * - GPIO_PIN_OUTPUT
+ * - GPIO_PIN_PULLUP
+ * - GPIO_PIN_PULLDOWN
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+ uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+ uint32_t reg_val;
+
+ /* Sanity check the flags supplied are valid, i.e. not input and output */
+ if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 0x0000)
+ return (EINVAL);
+ if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
+ (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
+ return (EINVAL);
+ if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) ==
+ (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN))
+ return (EINVAL);
+
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Set the GPIO mode and state */
+ if (ti_scm_padconf_set_gpioflags(pin, flags) != 0) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* If configuring as an output set the "output enable" bit */
+ reg_val = ti_gpio_read_4(sc, bank, TI_GPIO_OE);
+ if (flags & GPIO_PIN_INPUT)
+ reg_val |= mask;
+ else
+ reg_val &= ~mask;
+ ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_val);
+
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_set - Sets the current level on a GPIO pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @value: non-zero value will drive the pin high, otherwise the pin is
+ * driven low.
+ *
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+ uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ ti_gpio_write_4(sc, bank, (value == GPIO_PIN_LOW) ? TI_GPIO_CLEARDATAOUT
+ : TI_GPIO_SETDATAOUT, mask);
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_get - Gets the current level on a GPIO pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ * @value: pointer to a value that upond return will contain the pin value
+ *
+ * The pin must be configured as an input pin beforehand, otherwise this
+ * function will fail.
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+ uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+ uint32_t val = 0;
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Sanity check the pin is not configured as an output */
+ val = ti_gpio_read_4(sc, bank, TI_GPIO_OE);
+
+ if ((val & mask) == mask) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Read the value on the pin */
+ *value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAIN) & mask) ? 1 : 0;
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_pin_toggle - Toggles a given GPIO pin
+ * @dev: gpio device handle
+ * @pin: the number of the pin
+ *
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ * RETURNS:
+ * Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ uint32_t bank = (pin / PINS_PER_BANK);
+ uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+ uint32_t val;
+
+ TI_GPIO_LOCK(sc);
+
+ /* Sanity check the pin number is valid */
+ if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+ TI_GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Toggle the pin */
+ val = ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT);
+ if (val & mask)
+ ti_gpio_write_4(sc, bank, TI_GPIO_CLEARDATAOUT, mask);
+ else
+ ti_gpio_write_4(sc, bank, TI_GPIO_SETDATAOUT, mask);
+
+ TI_GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_gpio_intr - ISR for all GPIO modules
+ * @arg: the soft context pointer
+ *
+ * Unsused
+ *
+ * LOCKING:
+ * Internally locks the context
+ *
+ */
+static void
+ti_gpio_intr(void *arg)
+{
+ struct ti_gpio_softc *sc = arg;
+
+ TI_GPIO_LOCK(sc);
+ /* TODO: something useful */
+ TI_GPIO_UNLOCK(sc);
+}
+
+/**
+ * ti_gpio_probe - probe function for the driver
+ * @dev: gpio device handle
+ *
+ * Simply sets the name of the driver
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+ti_gpio_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,gpio"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI General Purpose I/O (GPIO)");
+ return (0);
+}
+
+/**
+ * ti_gpio_attach - attach function for the driver
+ * @dev: gpio device handle
+ *
+ * Allocates and sets up the driver context for all GPIO banks. This function
+ * expects the memory ranges and IRQs to already be allocated to the driver.
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+ti_gpio_attach(device_t dev)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ unsigned int i;
+ int err = 0;
+
+ sc->sc_dev = dev;
+
+ TI_GPIO_LOCK_INIT(sc);
+
+
+ /* There are up to 6 different GPIO register sets located in different
+ * memory areas on the chip. The memory range should have been set for
+ * the driver when it was added as a child.
+ */
+ err = bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate mem resources\n");
+ return (ENXIO);
+ }
+
+ /* Request the IRQ resources */
+ err = bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res);
+ if (err) {
+ device_printf(dev, "Error: could not allocate irq resources\n");
+ return (ENXIO);
+ }
+
+ /* Setup the IRQ resources */
+ for (i = 0; i < MAX_GPIO_BANKS; i++) {
+ if (sc->sc_irq_res[i] == NULL)
+ break;
+
+ /* Register an interrupt handler for each of the IRQ resources */
+ if ((bus_setup_intr(dev, sc->sc_irq_res[i], INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, ti_gpio_intr, sc, &(sc->sc_irq_hdl[i])))) {
+ device_printf(dev, "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+ }
+
+ /* Store the device handle back in the sc */
+ sc->sc_dev = dev;
+
+ /* We need to go through each block and ensure the clocks are running and
+ * the module is enabled. It might be better to do this only when the
+ * pins are configured which would result in less power used if the GPIO
+ * pins weren't used ...
+ */
+ for (i = 0; i < MAX_GPIO_BANKS; i++) {
+ if (sc->sc_mem_res[i] != NULL) {
+
+ /* Enable the interface and functional clocks for the module */
+ ti_prcm_clk_enable(GPIO0_CLK + FIRST_GPIO_BANK + i);
+
+ /* Read the revision number of the module. TI don't publish the
+ * actual revision numbers, so instead the values have been
+ * determined by experimentation.
+ */
+ sc->sc_revision[i] = ti_gpio_read_4(sc, i, TI_GPIO_REVISION);
+
+ /* Check the revision */
+ if (sc->sc_revision[i] != TI_GPIO_REV) {
+ device_printf(dev, "Warning: could not determine the revision"
+ "of %u GPIO module (revision:0x%08x)\n",
+ i, sc->sc_revision[i]);
+ continue;
+ }
+
+ /* Disable interrupts for all pins */
+ ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE1, 0xffffffff);
+ ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE2, 0xffffffff);
+ }
+ }
+
+ /* Finish of the probe call */
+ device_add_child(dev, "gpioc", device_get_unit(dev));
+ device_add_child(dev, "gpiobus", device_get_unit(dev));
+ return (bus_generic_attach(dev));
+}
+
+/**
+ * ti_gpio_detach - detach function for the driver
+ * @dev: scm device handle
+ *
+ * Allocates and sets up the driver context, this simply entails creating a
+ * bus mappings for the SCM register set.
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+ti_gpio_detach(device_t dev)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ unsigned int i;
+
+ KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
+
+ /* Disable all interrupts */
+ for (i = 0; i < MAX_GPIO_BANKS; i++) {
+ if (sc->sc_mem_res[i] != NULL) {
+ ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE1, 0xffffffff);
+ ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE2, 0xffffffff);
+ }
+ }
+
+ bus_generic_detach(dev);
+
+ /* Release the memory and IRQ resources */
+ for (i = 0; i < MAX_GPIO_BANKS; i++) {
+ if (sc->sc_mem_res[i] != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, i, sc->sc_mem_res[i]);
+ if (sc->sc_irq_res[i] != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, i, sc->sc_irq_res[i]);
+ }
+
+ TI_GPIO_LOCK_DESTROY(sc);
+
+ return(0);
+}
+
+static device_method_t ti_gpio_methods[] = {
+ DEVMETHOD(device_probe, ti_gpio_probe),
+ DEVMETHOD(device_attach, ti_gpio_attach),
+ DEVMETHOD(device_detach, ti_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_pin_max, ti_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, ti_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, ti_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle),
+ {0, 0},
+};
+
+static driver_t ti_gpio_driver = {
+ "gpio",
+ ti_gpio_methods,
+ sizeof(struct ti_gpio_softc),
+};
+static devclass_t ti_gpio_devclass;
+
+DRIVER_MODULE(ti_gpio, simplebus, ti_gpio_driver, ti_gpio_devclass, 0, 0);
diff --git a/sys/arm/ti/ti_i2c.c b/sys/arm/ti/ti_i2c.c
new file mode 100644
index 0000000..28bf3ca
--- /dev/null
+++ b/sys/arm/ti/ti_i2c.c
@@ -0,0 +1,1179 @@
+/*-
+ * 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.
+ */
+
+/**
+ * Driver for the I2C module on the TI SoC.
+ *
+ * This driver is heavily based on the TWI driver for the AT91 (at91_twi.c).
+ *
+ * CAUTION: The I2Ci registers are limited to 16 bit and 8 bit data accesses,
+ * 32 bit data access is not allowed and can corrupt register content.
+ *
+ * This driver currently doesn't use DMA for the transfer, although I hope to
+ * incorporate that sometime in the future. The idea being that for transaction
+ * larger than a certain size the DMA engine is used, for anything less the
+ * normal interrupt/fifo driven option is used.
+ *
+ *
+ * WARNING: This driver uses mtx_sleep and interrupts to perform transactions,
+ * which means you can't do a transaction during startup before the interrupts
+ * have been enabled. Hint - the freebsd function config_intrhook_establish().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_i2c.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include "iicbus_if.h"
+
+/**
+ * I2C device driver context, a pointer to this is stored in the device
+ * driver structure.
+ */
+struct ti_i2c_softc
+{
+ device_t sc_dev;
+ uint32_t device_id;
+ struct resource* sc_irq_res;
+ struct resource* sc_mem_res;
+ device_t sc_iicbus;
+
+ void* sc_irq_h;
+
+ struct mtx sc_mtx;
+
+ volatile uint16_t sc_stat_flags; /* contains the status flags last IRQ */
+
+ uint16_t sc_i2c_addr;
+ uint16_t sc_rev;
+};
+
+struct ti_i2c_clock_config
+{
+ int speed;
+ int bitrate;
+ uint8_t psc; /* Fast/Standard mode prescale divider */
+ uint8_t scll; /* Fast/Standard mode SCL low time */
+ uint8_t sclh; /* Fast/Standard mode SCL high time */
+ uint8_t hsscll; /* High Speed mode SCL low time */
+ uint8_t hssclh; /* High Speed mode SCL high time */
+};
+
+static struct ti_i2c_clock_config ti_i2c_clock_configs[] = {
+
+#if defined(SOC_OMAP4)
+ { IIC_SLOW, 100000, 23, 13, 15, 0, 0},
+ { IIC_FAST, 400000, 9, 5, 7, 0, 0},
+ { IIC_FASTEST, 3310000, 1, 113, 115, 7, 10},
+#elif defined(SOC_TI_AM335X)
+ { IIC_SLOW, 100000, 3, 53, 55, 0, 0},
+ { IIC_FAST, 400000, 3, 8, 10, 0, 0},
+ { IIC_FASTEST, 400000, 3, 8, 10, 0, 0}, /* This might be higher */
+#else
+#error "TI I2C driver is not supported on this SoC"
+#endif
+ { -1, 0 }
+};
+
+
+#define TI_I2C_REV1 0x003C /* OMAP3 */
+#define TI_I2C_REV2 0x000A /* OMAP4 */
+
+/**
+ * Locking macros used throughout the driver
+ */
+#define TI_I2C_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define TI_I2C_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define TI_I2C_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "ti_i2c", MTX_DEF)
+#define TI_I2C_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define TI_I2C_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_I2C_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+#ifdef DEBUG
+#define ti_i2c_dbg(_sc, fmt, args...) \
+ device_printf((_sc)->sc_dev, fmt, ##args)
+#else
+#define ti_i2c_dbg(_sc, fmt, args...)
+#endif
+
+static devclass_t ti_i2c_devclass;
+
+/* bus entry points */
+
+static int ti_i2c_probe(device_t dev);
+static int ti_i2c_attach(device_t dev);
+static int ti_i2c_detach(device_t dev);
+static void ti_i2c_intr(void *);
+
+/* OFW routine */
+static phandle_t ti_i2c_get_node(device_t bus, device_t dev);
+
+/* helper routines */
+static int ti_i2c_activate(device_t dev);
+static void ti_i2c_deactivate(device_t dev);
+
+/**
+ * ti_i2c_read_2 - reads a 16-bit value from one of the I2C registers
+ * @sc: I2C device context
+ * @off: the byte offset within the register bank to read from.
+ *
+ *
+ * LOCKING:
+ * No locking required
+ *
+ * RETURNS:
+ * 16-bit value read from the register.
+ */
+static inline uint16_t
+ti_i2c_read_2(struct ti_i2c_softc *sc, bus_size_t off)
+{
+ return bus_read_2(sc->sc_mem_res, off);
+}
+
+/**
+ * ti_i2c_write_2 - writes a 16-bit value to one of the I2C registers
+ * @sc: I2C device context
+ * @off: the byte offset within the register bank to read from.
+ * @val: the value to write into the register
+ *
+ * LOCKING:
+ * No locking required
+ *
+ * RETURNS:
+ * 16-bit value read from the register.
+ */
+static inline void
+ti_i2c_write_2(struct ti_i2c_softc *sc, bus_size_t off, uint16_t val)
+{
+ bus_write_2(sc->sc_mem_res, off, val);
+}
+
+/**
+ * ti_i2c_read_reg - reads a 16-bit value from one of the I2C registers
+ * take into account revision-dependent register offset
+ * @sc: I2C device context
+ * @off: the byte offset within the register bank to read from.
+ *
+ *
+ * LOCKING:
+ * No locking required
+ *
+ * RETURNS:
+ * 16-bit value read from the register.
+ */
+static inline uint16_t
+ti_i2c_read_reg(struct ti_i2c_softc *sc, bus_size_t off)
+{
+ /* XXXOMAP3: FIXME add registers mapping here */
+ return bus_read_2(sc->sc_mem_res, off);
+}
+
+/**
+ * ti_i2c_write_reg - writes a 16-bit value to one of the I2C registers
+ * take into account revision-dependent register offset
+ * @sc: I2C device context
+ * @off: the byte offset within the register bank to read from.
+ * @val: the value to write into the register
+ *
+ * LOCKING:
+ * No locking required
+ *
+ * RETURNS:
+ * 16-bit value read from the register.
+ */
+static inline void
+ti_i2c_write_reg(struct ti_i2c_softc *sc, bus_size_t off, uint16_t val)
+{
+ /* XXXOMAP3: FIXME add registers mapping here */
+ bus_write_2(sc->sc_mem_res, off, val);
+}
+
+/**
+ * ti_i2c_set_intr_enable - writes the interrupt enable register
+ * @sc: I2C device context
+ * @ie: bitmask of the interrupts to enable
+ *
+ * This function is needed as writing the I2C_IE register on the OMAP4 devices
+ * doesn't seem to actually enable the interrupt, rather you have to write
+ * through the I2C_IRQENABLE_CLR and I2C_IRQENABLE_SET registers.
+ *
+ * LOCKING:
+ * No locking required
+ *
+ * RETURNS:
+ * Nothing.
+ */
+static inline void
+ti_i2c_set_intr_enable(struct ti_i2c_softc *sc, uint16_t ie)
+{
+ /* XXXOMAP3: FIXME */
+ ti_i2c_write_2(sc, I2C_REG_IRQENABLE_CLR, 0xffff);
+ if (ie)
+ ti_i2c_write_2(sc, I2C_REG_IRQENABLE_SET, ie);
+}
+
+/**
+ * ti_i2c_reset - attach function for the driver
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+ti_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ struct ti_i2c_softc *sc = device_get_softc(dev);
+ struct ti_i2c_clock_config *clkcfg;
+ uint16_t con_reg;
+
+ clkcfg = ti_i2c_clock_configs;
+ while (clkcfg->speed != -1) {
+ if (clkcfg->speed == speed)
+ break;
+ /* take slow if speed is unknown */
+ if ((speed == IIC_UNKNOWN) && (clkcfg->speed == IIC_SLOW))
+ break;
+ clkcfg++;
+ }
+ if (clkcfg->speed == -1)
+ return (EINVAL);
+
+ TI_I2C_LOCK(sc);
+
+ if (oldaddr)
+ *oldaddr = sc->sc_i2c_addr;
+ sc->sc_i2c_addr = addr;
+
+ /* First disable the controller while changing the clocks */
+ con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+ ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+ /* Program the prescaler */
+ ti_i2c_write_reg(sc, I2C_REG_PSC, clkcfg->psc);
+
+ /* Set the bitrate */
+ ti_i2c_write_reg(sc, I2C_REG_SCLL, clkcfg->scll | (clkcfg->hsscll<<8));
+ ti_i2c_write_reg(sc, I2C_REG_SCLH, clkcfg->sclh | (clkcfg->hssclh<<8));
+
+ /* Set the remote slave address */
+ ti_i2c_write_reg(sc, I2C_REG_SA, addr);
+
+ /* Check if we are dealing with high speed mode */
+ if ((clkcfg->hsscll + clkcfg->hssclh) > 0)
+ con_reg = I2C_CON_OPMODE_HS;
+ else
+ con_reg = I2C_CON_OPMODE_STD;
+
+ /* Enable the I2C module again */
+ ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | con_reg);
+
+ TI_I2C_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_i2c_intr - interrupt handler for the I2C module
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+static void
+ti_i2c_intr(void *arg)
+{
+ struct ti_i2c_softc *sc = (struct ti_i2c_softc*) arg;
+ uint16_t status;
+
+ status = ti_i2c_read_reg(sc, I2C_REG_STAT);
+ if (status == 0)
+ return;
+
+ TI_I2C_LOCK(sc);
+
+ /* save the flags */
+ sc->sc_stat_flags |= status;
+
+ /* clear the status flags */
+ ti_i2c_write_reg(sc, I2C_REG_STAT, status);
+
+ /* wakeup the process the started the transaction */
+ wakeup(sc);
+
+ TI_I2C_UNLOCK(sc);
+
+ return;
+}
+
+/**
+ * ti_i2c_wait - waits for the specific event to occur
+ * @sc: i2c driver context
+ * @flags: the event(s) to wait on, this is a bitmask of the I2C_STAT_??? flags
+ * @statp: if not null will contain the status flags upon return
+ * @timo: the number of ticks to wait
+ *
+ *
+ *
+ * LOCKING:
+ * The driver context must be locked before calling this function. Internally
+ * the function sleeps, releasing the lock as it does so, however the lock is
+ * always retaken before this function returns.
+ *
+ * RETURNS:
+ * 0 if the event(s) were tripped within timeout period
+ * EBUSY if timedout waiting for the events
+ * ENXIO if a NACK event was received
+ */
+static int
+ti_i2c_wait(struct ti_i2c_softc *sc, uint16_t flags, uint16_t *statp, int timo)
+{
+ int waittime = timo;
+ int start_ticks = ticks;
+ int rc;
+
+ TI_I2C_ASSERT_LOCKED(sc);
+
+ /* check if the condition has already occured, the interrupt routine will
+ * clear the status flags.
+ */
+ if ((sc->sc_stat_flags & flags) == 0) {
+
+ /* condition(s) haven't occured so sleep on the IRQ */
+ while (waittime > 0) {
+
+ rc = mtx_sleep(sc, &sc->sc_mtx, 0, "I2Cwait", waittime);
+ if (rc == EWOULDBLOCK) {
+ /* timed-out, simply break out of the loop */
+ break;
+ } else {
+ /* IRQ has been tripped, but need to sanity check we have the
+ * right events in the status flag.
+ */
+ if ((sc->sc_stat_flags & flags) != 0)
+ break;
+
+ /* event hasn't been tripped so wait some more */
+ waittime -= (ticks - start_ticks);
+ start_ticks = ticks;
+ }
+ }
+ }
+
+ /* copy the actual status bits */
+ if (statp != NULL)
+ *statp = sc->sc_stat_flags;
+
+ /* return the status found */
+ if ((sc->sc_stat_flags & flags) != 0)
+ rc = 0;
+ else
+ rc = EBUSY;
+
+ /* clear the flags set by the interrupt handler */
+ sc->sc_stat_flags = 0;
+
+ return (rc);
+}
+
+/**
+ * ti_i2c_wait_for_free_bus - waits for the bus to become free
+ * @sc: i2c driver context
+ * @timo: the time to wait for the bus to become free
+ *
+ *
+ *
+ * LOCKING:
+ * The driver context must be locked before calling this function. Internally
+ * the function sleeps, releasing the lock as it does so, however the lock is
+ * always taken before this function returns.
+ *
+ * RETURNS:
+ * 0 if the event(s) were tripped within timeout period
+ * EBUSY if timedout waiting for the events
+ * ENXIO if a NACK event was received
+ */
+static int
+ti_i2c_wait_for_free_bus(struct ti_i2c_softc *sc, int timo)
+{
+ /* check if the bus is free, BB bit = 0 */
+ if ((ti_i2c_read_reg(sc, I2C_REG_STAT) & I2C_STAT_BB) == 0)
+ return 0;
+
+ /* enable bus free interrupts */
+ ti_i2c_set_intr_enable(sc, I2C_IE_BF);
+
+ /* wait for the bus free interrupt to be tripped */
+ return ti_i2c_wait(sc, I2C_STAT_BF, NULL, timo);
+}
+
+/**
+ * ti_i2c_read_bytes - attempts to perform a read operation
+ * @sc: i2c driver context
+ * @buf: buffer to hold the received bytes
+ * @len: the number of bytes to read
+ *
+ * This function assumes the slave address is already set
+ *
+ * LOCKING:
+ * The context lock should be held before calling this function
+ *
+ * RETURNS:
+ * 0 on function succeeded
+ * EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_read_bytes(struct ti_i2c_softc *sc, uint8_t *buf, uint16_t len)
+{
+ int timo = (hz / 4);
+ int err = 0;
+ uint16_t con_reg;
+ uint16_t events;
+ uint16_t status;
+ uint32_t amount = 0;
+ uint32_t sofar = 0;
+ uint32_t i;
+
+ /* wait for the bus to become free */
+ err = ti_i2c_wait_for_free_bus(sc, timo);
+ if (err != 0) {
+ device_printf(sc->sc_dev, "bus never freed\n");
+ return (err);
+ }
+
+ /* set the events to wait for */
+ events = I2C_IE_RDR | /* Receive draining interrupt */
+ I2C_IE_RRDY | /* Receive Data Ready interrupt */
+ I2C_IE_ARDY | /* Register Access Ready interrupt */
+ I2C_IE_NACK | /* No Acknowledgment interrupt */
+ I2C_IE_AL;
+
+ /* enable interrupts for the events we want */
+ ti_i2c_set_intr_enable(sc, events);
+
+ /* write the number of bytes to read */
+ ti_i2c_write_reg(sc, I2C_REG_CNT, len);
+
+ /* clear the write bit and initiate the read transaction. Setting the STT
+ * (start) bit initiates the transfer.
+ */
+ con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+ con_reg &= ~I2C_CON_TRX;
+ con_reg |= I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+ ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+ /* reading loop */
+ while (1) {
+
+ /* wait for an event */
+ err = ti_i2c_wait(sc, events, &status, timo);
+ if (err != 0) {
+ break;
+ }
+
+ /* check for the error conditions */
+ if (status & I2C_STAT_NACK) {
+ /* no ACK from slave */
+ ti_i2c_dbg(sc, "NACK\n");
+ err = ENXIO;
+ break;
+ }
+ if (status & I2C_STAT_AL) {
+ /* arbitration lost */
+ ti_i2c_dbg(sc, "Arbitration lost\n");
+ err = ENXIO;
+ break;
+ }
+
+ /* check if we have finished */
+ if (status & I2C_STAT_ARDY) {
+ /* register access ready - transaction complete basically */
+ ti_i2c_dbg(sc, "ARDY transaction complete\n");
+ err = 0;
+ break;
+ }
+
+ /* read some data */
+ if (status & I2C_STAT_RDR) {
+ /* Receive draining interrupt - last data received */
+ ti_i2c_dbg(sc, "Receive draining interrupt\n");
+
+ /* get the number of bytes in the FIFO */
+ amount = ti_i2c_read_reg(sc, I2C_REG_BUFSTAT);
+ amount >>= 8;
+ amount &= 0x3f;
+ }
+ else if (status & I2C_STAT_RRDY) {
+ /* Receive data ready interrupt - enough data received */
+ ti_i2c_dbg(sc, "Receive data ready interrupt\n");
+
+ /* get the number of bytes in the FIFO */
+ amount = ti_i2c_read_reg(sc, I2C_REG_BUF);
+ amount >>= 8;
+ amount &= 0x3f;
+ amount += 1;
+ }
+
+ /* sanity check we haven't overwritten the array */
+ if ((sofar + amount) > len) {
+ ti_i2c_dbg(sc, "to many bytes to read\n");
+ amount = (len - sofar);
+ }
+
+ /* read the bytes from the fifo */
+ for (i = 0; i < amount; i++) {
+ buf[sofar++] = (uint8_t)(ti_i2c_read_reg(sc, I2C_REG_DATA) & 0xff);
+ }
+
+ /* attempt to clear the receive ready bits */
+ ti_i2c_write_reg(sc, I2C_REG_STAT, I2C_STAT_RDR | I2C_STAT_RRDY);
+ }
+
+ /* reset the registers regardless if there was an error or not */
+ ti_i2c_set_intr_enable(sc, 0x0000);
+ ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP);
+
+ return (err);
+}
+
+/**
+ * ti_i2c_write_bytes - attempts to perform a read operation
+ * @sc: i2c driver context
+ * @buf: buffer containing the bytes to write
+ * @len: the number of bytes to write
+ *
+ * This function assumes the slave address is already set
+ *
+ * LOCKING:
+ * The context lock should be held before calling this function
+ *
+ * RETURNS:
+ * 0 on function succeeded
+ * EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_write_bytes(struct ti_i2c_softc *sc, const uint8_t *buf, uint16_t len)
+{
+ int timo = (hz / 4);
+ int err = 0;
+ uint16_t con_reg;
+ uint16_t events;
+ uint16_t status;
+ uint32_t amount = 0;
+ uint32_t sofar = 0;
+ uint32_t i;
+
+ /* wait for the bus to become free */
+ err = ti_i2c_wait_for_free_bus(sc, timo);
+ if (err != 0)
+ return (err);
+
+ /* set the events to wait for */
+ events = I2C_IE_XDR | /* Transmit draining interrupt */
+ I2C_IE_XRDY | /* Transmit Data Ready interrupt */
+ I2C_IE_ARDY | /* Register Access Ready interrupt */
+ I2C_IE_NACK | /* No Acknowledgment interrupt */
+ I2C_IE_AL;
+
+ /* enable interrupts for the events we want*/
+ ti_i2c_set_intr_enable(sc, events);
+
+ /* write the number of bytes to write */
+ ti_i2c_write_reg(sc, I2C_REG_CNT, len);
+
+ /* set the write bit and initiate the write transaction. Setting the STT
+ * (start) bit initiates the transfer.
+ */
+ con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+ con_reg |= I2C_CON_TRX | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+ ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+ /* writing loop */
+ while (1) {
+
+ /* wait for an event */
+ err = ti_i2c_wait(sc, events, &status, timo);
+ if (err != 0) {
+ break;
+ }
+
+ /* check for the error conditions */
+ if (status & I2C_STAT_NACK) {
+ /* no ACK from slave */
+ ti_i2c_dbg(sc, "NACK\n");
+ err = ENXIO;
+ break;
+ }
+ if (status & I2C_STAT_AL) {
+ /* arbitration lost */
+ ti_i2c_dbg(sc, "Arbitration lost\n");
+ err = ENXIO;
+ break;
+ }
+
+ /* check if we have finished */
+ if (status & I2C_STAT_ARDY) {
+ /* register access ready - transaction complete basically */
+ ti_i2c_dbg(sc, "ARDY transaction complete\n");
+ err = 0;
+ break;
+ }
+
+ /* read some data */
+ if (status & I2C_STAT_XDR) {
+ /* Receive draining interrupt - last data received */
+ ti_i2c_dbg(sc, "Transmit draining interrupt\n");
+
+ /* get the number of bytes in the FIFO */
+ amount = ti_i2c_read_reg(sc, I2C_REG_BUFSTAT);
+ amount &= 0x3f;
+ }
+ else if (status & I2C_STAT_XRDY) {
+ /* Receive data ready interrupt - enough data received */
+ ti_i2c_dbg(sc, "Transmit data ready interrupt\n");
+
+ /* get the number of bytes in the FIFO */
+ amount = ti_i2c_read_reg(sc, I2C_REG_BUF);
+ amount &= 0x3f;
+ amount += 1;
+ }
+
+ /* sanity check we haven't overwritten the array */
+ if ((sofar + amount) > len) {
+ ti_i2c_dbg(sc, "to many bytes to write\n");
+ amount = (len - sofar);
+ }
+
+ /* write the bytes from the fifo */
+ for (i = 0; i < amount; i++) {
+ ti_i2c_write_reg(sc, I2C_REG_DATA, buf[sofar++]);
+ }
+
+ /* attempt to clear the transmit ready bits */
+ ti_i2c_write_reg(sc, I2C_REG_STAT, I2C_STAT_XDR | I2C_STAT_XRDY);
+ }
+
+ /* reset the registers regardless if there was an error or not */
+ ti_i2c_set_intr_enable(sc, 0x0000);
+ ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP);
+
+ return (err);
+}
+
+/**
+ * ti_i2c_transfer - called to perform the transfer
+ * @dev: i2c device handle
+ * @msgs: the messages to send/receive
+ * @nmsgs: the number of messages in the msgs array
+ *
+ *
+ * LOCKING:
+ * Internally locked
+ *
+ * RETURNS:
+ * 0 on function succeeded
+ * EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+ struct ti_i2c_softc *sc = device_get_softc(dev);
+ int err = 0;
+ uint32_t i;
+ uint16_t len;
+ uint8_t *buf;
+
+ TI_I2C_LOCK(sc);
+
+ for (i = 0; i < nmsgs; i++) {
+
+ len = msgs[i].len;
+ buf = msgs[i].buf;
+
+ /* zero byte transfers aren't allowed */
+ if (len == 0 || buf == NULL) {
+ err = EINVAL;
+ goto out;
+ }
+
+ /* set the slave address */
+ ti_i2c_write_reg(sc, I2C_REG_SA, msgs[i].slave);
+
+ /* perform the read or write */
+ if (msgs[i].flags & IIC_M_RD) {
+ err = ti_i2c_read_bytes(sc, buf, len);
+ } else {
+ err = ti_i2c_write_bytes(sc, buf, len);
+ }
+
+ }
+
+out:
+ TI_I2C_UNLOCK(sc);
+
+ return (err);
+}
+
+/**
+ * ti_i2c_callback - not sure about this one
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+ti_i2c_callback(device_t dev, int index, caddr_t data)
+{
+ int error = 0;
+
+ switch (index) {
+ case IIC_REQUEST_BUS:
+ break;
+
+ case IIC_RELEASE_BUS:
+ break;
+
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+/**
+ * ti_i2c_activate - initialises and activates an I2C bus
+ * @dev: i2c device handle
+ * @num: the number of the I2C controller to activate; 1, 2 or 3
+ *
+ *
+ * LOCKING:
+ * Assumed called in an atomic context.
+ *
+ * RETURNS:
+ * nothing
+ */
+static int
+ti_i2c_activate(device_t dev)
+{
+ struct ti_i2c_softc *sc = (struct ti_i2c_softc*) device_get_softc(dev);
+ unsigned int timeout = 0;
+ uint16_t con_reg;
+ int err;
+ clk_ident_t clk;
+
+ /*
+ * The following sequence is taken from the OMAP3530 technical reference
+ *
+ * 1. Enable the functional and interface clocks (see Section 18.3.1.1.1).
+ */
+ clk = I2C0_CLK + sc->device_id;
+ err = ti_prcm_clk_enable(clk);
+ if (err)
+ return (err);
+
+ /* There seems to be a bug in the I2C reset mechanism, for some reason you
+ * need to disable the I2C module before issuing the reset and then enable
+ * it again after to detect the reset done.
+ *
+ * I found this out by looking at the Linux driver implementation, thanks
+ * linux guys!
+ */
+
+ /* Disable the I2C controller */
+ ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+ /* Issue a softreset to the controller */
+ /* XXXOMAP3: FIXME */
+ bus_write_2(sc->sc_mem_res, I2C_REG_SYSC, 0x0002);
+
+ /* Re-enable the module and then check for the reset done */
+ ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN);
+
+ while ((ti_i2c_read_reg(sc, I2C_REG_SYSS) & 0x01) == 0x00) {
+ if (timeout++ > 100) {
+ return (EBUSY);
+ }
+ DELAY(100);
+ }
+
+ /* Disable the I2C controller once again, now that the reset has finished */
+ ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+ /* 2. Program the prescaler to obtain an approximately 12-MHz internal
+ * sampling clock (I2Ci_INTERNAL_CLK) by programming the corresponding
+ * value in the I2Ci.I2C_PSC[3:0] PSC field.
+ * This value depends on the frequency of the functional clock (I2Ci_FCLK).
+ * Because this frequency is 96MHz, the I2Ci.I2C_PSC[7:0] PSC field value
+ * is 0x7.
+ */
+
+ /* Program the prescaler to obtain an approximately 12-MHz internal
+ * sampling clock.
+ */
+ ti_i2c_write_reg(sc, I2C_REG_PSC, 0x0017);
+
+ /* 3. Program the I2Ci.I2C_SCLL[7:0] SCLL and I2Ci.I2C_SCLH[7:0] SCLH fields
+ * to obtain a bit rate of 100K bps or 400K bps. These values depend on
+ * the internal sampling clock frequency (see Table 18-12).
+ */
+
+ /* Set the bitrate to 100kbps */
+ ti_i2c_write_reg(sc, I2C_REG_SCLL, 0x000d);
+ ti_i2c_write_reg(sc, I2C_REG_SCLH, 0x000f);
+
+ /* 4. (Optional) Program the I2Ci.I2C_SCLL[15:8] HSSCLL and
+ * I2Ci.I2C_SCLH[15:8] HSSCLH fields to obtain a bit rate of 400K bps or
+ * 3.4M bps (for the second phase of HS mode). These values depend on the
+ * internal sampling clock frequency (see Table 18-12).
+ *
+ * 5. (Optional) If a bit rate of 3.4M bps is used and the bus line
+ * capacitance exceeds 45 pF, program the CONTROL.CONTROL_DEVCONF1[12]
+ * I2C1HSMASTER bit for I2C1, the CONTROL.CONTROL_DEVCONF1[13]
+ * I2C2HSMASTER bit for I2C2, or the CONTROL.CONTROL_DEVCONF1[14]
+ * I2C3HSMASTER bit for I2C3.
+ */
+
+ /* 6. Configure the Own Address of the I2C controller by storing it in the
+ * I2Ci.I2C_OA0 register. Up to four Own Addresses can be programmed in
+ * the I2Ci.I2C_OAi registers (with I = 0, 1, 2, 3) for each I2C
+ * controller.
+ *
+ * Note: For a 10-bit address, set the corresponding expand Own Address bit
+ * in the I2Ci.I2C_CON register.
+ */
+
+ /* Driver currently always in single master mode so ignore this step */
+
+ /* 7. Set the TX threshold (in transmitter mode) and the RX threshold (in
+ * receiver mode) by setting the I2Ci.I2C_BUF[5:0]XTRSH field to (TX
+ * threshold - 1) and the I2Ci.I2C_BUF[13:8]RTRSH field to (RX threshold
+ * - 1), where the TX and RX thresholds are greater than or equal to 1.
+ */
+
+ /* Set the FIFO buffer threshold, note I2C1 & I2C2 have 8 byte FIFO, whereas
+ * I2C3 has 64 bytes. Threshold set to 5 for now.
+ */
+ ti_i2c_write_reg(sc, I2C_REG_BUF, 0x0404);
+
+ /*
+ * 8. Take the I2C controller out of reset by setting the I2Ci.I2C_CON[15]
+ * I2C_EN bit to 1.
+ */
+ ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_OPMODE_STD);
+
+ /*
+ * To initialize the I2C controller, perform the following steps:
+ *
+ * 1. Configure the I2Ci.I2C_CON register:
+ * · For master or slave mode, set the I2Ci.I2C_CON[10] MST bit (0: slave,
+ * 1: master).
+ * · For transmitter or receiver mode, set the I2Ci.I2C_CON[9] TRX bit
+ * (0: receiver, 1: transmitter).
+ */
+ con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+ con_reg |= I2C_CON_MST;
+ ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+ /* 2. If using an interrupt to transmit/receive data, set to 1 the
+ * corresponding bit in the I2Ci.I2C_IE register (the I2Ci.I2C_IE[4]
+ * XRDY_IE bit for the transmit interrupt, the I2Ci.I2C_IE[3] RRDY bit
+ * for the receive interrupt).
+ */
+ ti_i2c_set_intr_enable(sc, I2C_IE_XRDY | I2C_IE_RRDY);
+
+ /* 3. If using DMA to receive/transmit data, set to 1 the corresponding bit
+ * in the I2Ci.I2C_BUF register (the I2Ci.I2C_BUF[15] RDMA_EN bit for the
+ * receive DMA channel, the I2Ci.I2C_BUF[7] XDMA_EN bit for the transmit
+ * DMA channel).
+ */
+
+ /* not using DMA for now, so ignore this */
+
+ return (0);
+}
+
+/**
+ * ti_i2c_deactivate - deactivates the controller and releases resources
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ * Assumed called in an atomic context.
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_i2c_deactivate(device_t dev)
+{
+ struct ti_i2c_softc *sc = device_get_softc(dev);
+ clk_ident_t clk;
+
+ /* Disable the controller - cancel all transactions */
+ ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+ /* Release the interrupt handler */
+ if (sc->sc_irq_h) {
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
+ sc->sc_irq_h = 0;
+ }
+
+ bus_generic_detach(sc->sc_dev);
+
+ /* Unmap the I2C controller registers */
+ if (sc->sc_mem_res != 0) {
+ bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res),
+ sc->sc_mem_res);
+ sc->sc_mem_res = NULL;
+ }
+
+ /* Release the IRQ resource */
+ if (sc->sc_irq_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res),
+ sc->sc_irq_res);
+ sc->sc_irq_res = NULL;
+ }
+
+ /* Finally disable the functional and interface clocks */
+ clk = I2C0_CLK + sc->device_id;
+ ti_prcm_clk_disable(clk);
+
+ return;
+}
+
+/**
+ * ti_i2c_probe - probe function for the driver
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ *
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+ti_i2c_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,i2c"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI I2C Controller");
+ return (0);
+}
+
+/**
+ * ti_i2c_attach - attach function for the driver
+ * @dev: i2c device handle
+ *
+ * Initialised driver data structures and activates the I2C controller.
+ *
+ * LOCKING:
+ *
+ *
+ * RETURNS:
+ *
+ */
+static int
+ti_i2c_attach(device_t dev)
+{
+ struct ti_i2c_softc *sc = device_get_softc(dev);
+ phandle_t node;
+ pcell_t did;
+ int err;
+ int rid;
+
+ sc->sc_dev = dev;
+
+ /* Get the i2c device id from FDT */
+ node = ofw_bus_get_node(dev);
+ if ((OF_getprop(node, "i2c-device-id", &did, sizeof(did))) <= 0) {
+ device_printf(dev, "missing i2c-device-id attribute in FDT\n");
+ return (ENXIO);
+ }
+ sc->device_id = fdt32_to_cpu(did);
+
+ TI_I2C_LOCK_INIT(sc);
+
+ /* Get the memory resource for the register mapping */
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->sc_mem_res == NULL)
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ /* Allocate an IRQ resource for the MMC controller */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_irq_res == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ /* XXXOMAP3: FIXME get proper revision here */
+ /* First read the version number of the I2C module */
+ sc->sc_rev = ti_i2c_read_2(sc, I2C_REG_REVNB_HI) & 0xff;
+
+ device_printf(dev, "I2C revision %d.%d\n", sc->sc_rev >> 4,
+ sc->sc_rev & 0xf);
+
+ /* Activate the H/W */
+ err = ti_i2c_activate(dev);
+ if (err) {
+ device_printf(dev, "ti_i2c_activate failed\n");
+ goto out;
+ }
+
+ /* activate the interrupt */
+ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, ti_i2c_intr, sc, &sc->sc_irq_h);
+ if (err)
+ goto out;
+
+ /* Attach to the iicbus */
+ if ((sc->sc_iicbus = device_add_child(dev, "iicbus", -1)) == NULL)
+ device_printf(dev, "could not allocate iicbus instance\n");
+
+ /* Probe and attach the iicbus */
+ bus_generic_attach(dev);
+
+out:
+ if (err) {
+ ti_i2c_deactivate(dev);
+ TI_I2C_LOCK_DESTROY(sc);
+ }
+
+ return (err);
+}
+
+/**
+ * ti_i2c_detach - detach function for the driver
+ * @dev: i2c device handle
+ *
+ *
+ *
+ * LOCKING:
+ *
+ *
+ * RETURNS:
+ * Always returns 0
+ */
+static int
+ti_i2c_detach(device_t dev)
+{
+ struct ti_i2c_softc *sc = device_get_softc(dev);
+ int rv;
+
+ ti_i2c_deactivate(dev);
+
+ if (sc->sc_iicbus && (rv = device_delete_child(dev, sc->sc_iicbus)) != 0)
+ return (rv);
+
+ TI_I2C_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+
+static phandle_t
+ti_i2c_get_node(device_t bus, device_t dev)
+{
+ /*
+ * Share controller node with iibus device
+ */
+ return ofw_bus_get_node(bus);
+}
+
+static device_method_t ti_i2c_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ti_i2c_probe),
+ DEVMETHOD(device_attach, ti_i2c_attach),
+ DEVMETHOD(device_detach, ti_i2c_detach),
+
+ /* OFW methods */
+ DEVMETHOD(ofw_bus_get_node, ti_i2c_get_node),
+
+ /* iicbus interface */
+ DEVMETHOD(iicbus_callback, ti_i2c_callback),
+ DEVMETHOD(iicbus_reset, ti_i2c_reset),
+ DEVMETHOD(iicbus_transfer, ti_i2c_transfer),
+ { 0, 0 }
+};
+
+static driver_t ti_i2c_driver = {
+ "iichb",
+ ti_i2c_methods,
+ sizeof(struct ti_i2c_softc),
+};
+
+DRIVER_MODULE(ti_iic, simplebus, ti_i2c_driver, ti_i2c_devclass, 0, 0);
+DRIVER_MODULE(iicbus, ti_iic, iicbus_driver, iicbus_devclass, 0, 0);
+
+MODULE_DEPEND(ti_iic, ti_prcm, 1, 1, 1);
+MODULE_DEPEND(ti_iic, iicbus, 1, 1, 1);
diff --git a/sys/arm/ti/ti_i2c.h b/sys/arm/ti/ti_i2c.h
new file mode 100644
index 0000000..f569f87
--- /dev/null
+++ b/sys/arm/ti/ti_i2c.h
@@ -0,0 +1,115 @@
+/*-
+ * 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_I2C_H_
+#define _TI_I2C_H_
+
+/**
+ * Header file for the OMAP I2C driver.
+ *
+ * Simply contains register bit flags.
+ */
+
+/*
+ * OMAP4 I2C Registers, Summary 1
+ */
+#define I2C_REG_IE 0x84
+#define I2C_IE_XDR (1UL << 14) /* Transmit draining interrupt */
+#define I2C_IE_RDR (1UL << 13) /* Receive draining interrupt */
+#define I2C_IE_AAS (1UL << 9) /* Addressed as Slave interrupt */
+#define I2C_IE_BF (1UL << 8) /* Bus Free interrupt */
+#define I2C_IE_AERR (1UL << 7) /* Access Error interrupt */
+#define I2C_IE_STC (1UL << 6) /* Start Condition interrupt */
+#define I2C_IE_GC (1UL << 5) /* General Call interrupt */
+#define I2C_IE_XRDY (1UL << 4) /* Transmit Data Ready interrupt */
+#define I2C_IE_RRDY (1UL << 3) /* Receive Data Ready interrupt */
+#define I2C_IE_ARDY (1UL << 2) /* Register Access Ready interrupt */
+#define I2C_IE_NACK (1UL << 1) /* No Acknowledgment interrupt */
+#define I2C_IE_AL (1UL << 0) /* Arbitration Lost interrupt */
+#define I2C_REG_STAT 0x88
+#define I2C_STAT_XDR (1UL << 14)
+#define I2C_STAT_RDR (1UL << 13)
+#define I2C_STAT_BB (1UL << 12)
+#define I2C_STAT_ROVR (1UL << 11)
+#define I2C_STAT_XUDF (1UL << 10)
+#define I2C_STAT_AAS (1UL << 9)
+#define I2C_STAT_BF (1UL << 8)
+#define I2C_STAT_AERR (1UL << 7)
+#define I2C_STAT_STC (1UL << 6)
+#define I2C_STAT_GC (1UL << 5)
+#define I2C_STAT_XRDY (1UL << 4)
+#define I2C_STAT_RRDY (1UL << 3)
+#define I2C_STAT_ARDY (1UL << 2)
+#define I2C_STAT_NACK (1UL << 1)
+#define I2C_STAT_AL (1UL << 0)
+#define I2C_REG_SYSS 0x90
+#define I2C_REG_BUF 0x94
+#define I2C_REG_CNT 0x98
+#define I2C_REG_DATA 0x9c
+#define I2C_REG_CON 0xa4
+#define I2C_CON_I2C_EN (1UL << 15)
+#define I2C_CON_OPMODE_STD (0UL << 12)
+#define I2C_CON_OPMODE_HS (1UL << 12)
+#define I2C_CON_OPMODE_SCCB (2UL << 12)
+#define I2C_CON_OPMODE_MASK (3UL << 13)
+#define I2C_CON_I2C_STB (1UL << 11)
+#define I2C_CON_MST (1UL << 10)
+#define I2C_CON_TRX (1UL << 9)
+#define I2C_CON_XSA (1UL << 8)
+#define I2C_CON_XOA0 (1UL << 7)
+#define I2C_CON_XOA1 (1UL << 6)
+#define I2C_CON_XOA2 (1UL << 5)
+#define I2C_CON_XOA3 (1UL << 4)
+#define I2C_CON_STP (1UL << 1)
+#define I2C_CON_STT (1UL << 0)
+#define I2C_REG_OA0 0xa8
+#define I2C_REG_SA 0xac
+#define I2C_REG_PSC 0xb0
+#define I2C_REG_SCLL 0xb4
+#define I2C_REG_SCLH 0xb8
+#define I2C_REG_SYSTEST 0xbc
+#define I2C_REG_BUFSTAT 0xc0
+#define I2C_REG_OA1 0xc4
+#define I2C_REG_OA2 0xc8
+#define I2C_REG_OA3 0xcc
+#define I2C_REG_ACTOA 0xd0
+#define I2C_REG_SBLOCK 0xd4
+
+/*
+ * OMAP4 I2C Registers, Summary 2
+ */
+#define I2C_REG_REVNB_LO 0x00
+#define I2C_REG_REVNB_HI 0x04
+#define I2C_REG_SYSC 0x10
+#define I2C_REG_IRQENABLE_SET 0x2C
+#define I2C_REG_IRQENABLE_CLR 0x30
+
+
+
+#endif /* _TI_I2C_H_ */
diff --git a/sys/arm/ti/ti_machdep.c b/sys/arm/ti/ti_machdep.c
new file mode 100644
index 0000000..3a5fe85
--- /dev/null
+++ b/sys/arm/ti/ti_machdep.c
@@ -0,0 +1,618 @@
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Brini.
+ * 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 BRINI ``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 BRINI 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+#include "opt_global.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/cons.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/exec.h>
+#include <sys/kdb.h>
+#include <sys/msgbuf.h>
+#include <machine/reg.h>
+#include <machine/cpu.h>
+#include <machine/fdt.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/armreg.h>
+#include <machine/bus.h>
+#include <sys/reboot.h>
+
+#include <arm/ti/omap4/omap4_reg.h>
+
+#define DEBUG
+#ifdef DEBUG
+#define debugf(fmt, args...) printf(fmt, ##args)
+#else
+#define debugf(fmt, args...)
+#endif
+
+/* Start of address space used for bootstrap map */
+#define DEVMAP_BOOTSTRAP_MAP_START 0xE0000000
+
+/*
+ * This is the number of L2 page tables required for covering max
+ * (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf,
+ * stacks etc.), uprounded to be divisible by 4.
+ */
+#define KERNEL_PT_MAX 78
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE 1
+#define ABT_STACK_SIZE 1
+#define UND_STACK_SIZE 1
+
+extern unsigned char kernbase[];
+extern unsigned char _etext[];
+extern unsigned char _edata[];
+extern unsigned char __bss_start[];
+extern unsigned char _end[];
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+extern vm_offset_t pmap_bootstrap_lastaddr;
+extern int *end;
+
+struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
+
+/* Physical and virtual addresses for some global pages */
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+vm_offset_t physical_pages;
+vm_offset_t pmap_bootstrap_lastaddr;
+vm_paddr_t pmap_pa;
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+
+void set_stackptrs(int cpu);
+
+static struct mem_region availmem_regions[FDT_MEM_REGIONS];
+static int availmem_regions_sz;
+
+static void print_kenv(void);
+static void print_kernel_section_addr(void);
+
+static void physmap_init(void);
+static int platform_devmap_init(void);
+void (*ti_cpu_reset)(void);
+
+static char *
+kenv_next(char *cp)
+{
+
+ if (cp != NULL) {
+ while (*cp != 0)
+ cp++;
+ cp++;
+ if (*cp == 0)
+ cp = NULL;
+ }
+ return (cp);
+}
+
+static void
+print_kenv(void)
+{
+ int len;
+ char *cp;
+
+ debugf("loader passed (static) kenv:\n");
+ if (kern_envp == NULL) {
+ debugf(" no env, null ptr\n");
+ return;
+ }
+ debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
+
+ len = 0;
+ for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
+ debugf(" %x %s\n", (uint32_t)cp, cp);
+}
+
+static void
+print_kernel_section_addr(void)
+{
+
+ debugf("kernel image addresses:\n");
+ debugf(" kernbase = 0x%08x\n", (uint32_t)kernbase);
+ debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
+ debugf(" _edata = 0x%08x\n", (uint32_t)_edata);
+ debugf(" __bss_start = 0x%08x\n", (uint32_t)__bss_start);
+ debugf(" _end = 0x%08x\n", (uint32_t)_end);
+}
+
+static void
+physmap_init(void)
+{
+ int i, j, cnt;
+ vm_offset_t phys_kernelend, kernload;
+ uint32_t s, e, sz;
+ struct mem_region *mp, *mp1;
+
+ phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
+ kernload = KERNPHYSADDR;
+ ti_cpu_reset = NULL;
+
+ /*
+ * Remove kernel physical address range from avail
+ * regions list. Page align all regions.
+ * Non-page aligned memory isn't very interesting to us.
+ * Also, sort the entries for ascending addresses.
+ */
+ sz = 0;
+ cnt = availmem_regions_sz;
+ debugf("processing avail regions:\n");
+ for (mp = availmem_regions; mp->mr_size; mp++) {
+ s = mp->mr_start;
+ e = mp->mr_start + mp->mr_size;
+ debugf(" %08x-%08x -> ", s, e);
+ /* Check whether this region holds all of the kernel. */
+ if (s < kernload && e > phys_kernelend) {
+ availmem_regions[cnt].mr_start = phys_kernelend;
+ availmem_regions[cnt++].mr_size = e - phys_kernelend;
+ e = kernload;
+ }
+ /* Look whether this regions starts within the kernel. */
+ if (s >= kernload && s < phys_kernelend) {
+ if (e <= phys_kernelend)
+ goto empty;
+ s = phys_kernelend;
+ }
+ /* Now look whether this region ends within the kernel. */
+ if (e > kernload && e <= phys_kernelend) {
+ if (s >= kernload) {
+ goto empty;
+ }
+ e = kernload;
+ }
+ /* Now page align the start and size of the region. */
+ s = round_page(s);
+ e = trunc_page(e);
+ if (e < s)
+ e = s;
+ sz = e - s;
+ debugf("%08x-%08x = %x\n", s, e, sz);
+
+ /* Check whether some memory is left here. */
+ if (sz == 0) {
+ empty:
+ printf("skipping\n");
+ bcopy(mp + 1, mp,
+ (cnt - (mp - availmem_regions)) * sizeof(*mp));
+ cnt--;
+ mp--;
+ continue;
+ }
+
+ /* Do an insertion sort. */
+ for (mp1 = availmem_regions; mp1 < mp; mp1++)
+ if (s < mp1->mr_start)
+ break;
+ if (mp1 < mp) {
+ bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
+ mp1->mr_start = s;
+ mp1->mr_size = sz;
+ } else {
+ mp->mr_start = s;
+ mp->mr_size = sz;
+ }
+ }
+ availmem_regions_sz = cnt;
+
+ /* Fill in phys_avail table, based on availmem_regions */
+ debugf("fill in phys_avail:\n");
+ for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
+
+ debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
+ availmem_regions[i].mr_start,
+ availmem_regions[i].mr_start + availmem_regions[i].mr_size,
+ availmem_regions[i].mr_size);
+
+ phys_avail[j] = availmem_regions[i].mr_start;
+ phys_avail[j + 1] = availmem_regions[i].mr_start +
+ availmem_regions[i].mr_size;
+ }
+ phys_avail[j] = 0;
+ phys_avail[j + 1] = 0;
+}
+
+void *
+initarm(struct arm_boot_params *abp)
+{
+ struct pv_addr kernel_l1pt;
+ struct pv_addr dpcpu;
+ vm_offset_t dtbp, freemempos, l2_start, lastaddr;
+ uint32_t memsize, l2size;
+ void *kmdp;
+ u_int l1pagetable;
+ int i = 0, j = 0, err_devmap = 0;
+
+ lastaddr = parse_boot_param(abp);
+ memsize = 0;
+ set_cpufuncs();
+
+
+ kmdp = preload_search_by_type("elf kernel");
+ if (kmdp != NULL)
+ dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+ else
+ dtbp = (vm_offset_t)NULL;
+
+#if defined(FDT_DTB_STATIC)
+ /*
+ * In case the device tree blob was not retrieved (from metadata) try
+ * to use the statically embedded one.
+ */
+ if (dtbp == (vm_offset_t)NULL)
+ dtbp = (vm_offset_t)&fdt_static_dtb;
+#endif
+
+ if (OF_install(OFW_FDT, 0) == FALSE)
+ while (1);
+
+ if (OF_init((void *)dtbp) != 0)
+ while (1);
+
+ /* Grab physical memory regions information from device tree. */
+ if (fdt_get_mem_regions(availmem_regions, &availmem_regions_sz,
+ &memsize) != 0)
+ while(1);
+
+// if (fdt_immr_addr(OMAP44XX_L4_PERIPH_VBASE) != 0)
+// while (1);
+
+ /* Platform-specific initialisation */
+ pmap_bootstrap_lastaddr = DEVMAP_BOOTSTRAP_MAP_START - ARM_NOCACHE_KVA_SIZE;
+
+ pcpu0_init();
+
+ /* Calculate number of L2 tables needed for mapping vm_page_array */
+ l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
+ l2size = (l2size >> L1_S_SHIFT) + 1;
+
+ /*
+ * Add one table for end of kernel map, one for stacks, msgbuf and
+ * L1 and L2 tables map and one for vectors map.
+ */
+ l2size += 3;
+
+ /* Make it divisible by 4 */
+ l2size = (l2size + 3) & ~3;
+
+#define KERNEL_TEXT_BASE (KERNBASE)
+ freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK;
+
+ /* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np) \
+ alloc_pages((var).pv_va, (np)); \
+ (var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
+
+#define alloc_pages(var, np) \
+ (var) = freemempos; \
+ freemempos += (np * PAGE_SIZE); \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
+ freemempos += PAGE_SIZE;
+ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+
+ for (i = 0; i < l2size; ++i) {
+ if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+ valloc_pages(kernel_pt_table[i],
+ L2_TABLE_SIZE / PAGE_SIZE);
+ j = i;
+ } else {
+ kernel_pt_table[i].pv_va = kernel_pt_table[j].pv_va +
+ L2_TABLE_SIZE_REAL * (i - j);
+ kernel_pt_table[i].pv_pa =
+ kernel_pt_table[i].pv_va - KERNVIRTADDR +
+ KERNPHYSADDR;
+
+ }
+ }
+ /*
+ * Allocate a page for the system page mapped to 0x00000000
+ * or 0xffff0000. This page will just contain the system vectors
+ * and can be shared by all processes.
+ */
+ valloc_pages(systempage, 1);
+
+ /* Allocate dynamic per-cpu area. */
+ valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE);
+ dpcpu_init((void *)dpcpu.pv_va, 0);
+
+ /* Allocate stacks for all modes */
+ valloc_pages(irqstack, (IRQ_STACK_SIZE * MAXCPU));
+ valloc_pages(abtstack, (ABT_STACK_SIZE * MAXCPU));
+ valloc_pages(undstack, (UND_STACK_SIZE * MAXCPU));
+ valloc_pages(kernelstack, (KSTACK_PAGES * MAXCPU));
+
+ init_param1();
+
+ valloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE);
+
+ /*
+ * Now we start construction of the L1 page table
+ * We start by mapping the L2 page tables into the L1.
+ * This means that we can replace L1 mappings later on if necessary
+ */
+ l1pagetable = kernel_l1pt.pv_va;
+
+ /*
+ * Try to map as much as possible of kernel text and data using
+ * 1MB section mapping and for the rest of initial kernel address
+ * space use L2 coarse tables.
+ *
+ * Link L2 tables for mapping remainder of kernel (modulo 1MB)
+ * and kernel structures
+ */
+ l2_start = lastaddr & ~(L1_S_OFFSET);
+ for (i = 0 ; i < l2size - 1; i++)
+ pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
+ &kernel_pt_table[i]);
+
+ pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
+
+ /* Map kernel code and data */
+ pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
+ (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+ /* Map L1 directory and allocated L2 page tables */
+ pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+ L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+ pmap_map_chunk(l1pagetable, kernel_pt_table[0].pv_va,
+ kernel_pt_table[0].pv_pa,
+ L2_TABLE_SIZE_REAL * l2size,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+ /* Map allocated DPCPU, stacks and msgbuf */
+ pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa,
+ freemempos - dpcpu.pv_va,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+ /* Link and map the vector page */
+ pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+ &kernel_pt_table[l2size - 1]);
+ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+
+ /* Map pmap_devmap[] entries */
+ err_devmap = platform_devmap_init();
+ pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
+
+ cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
+ DOMAIN_CLIENT);
+ pmap_pa = kernel_l1pt.pv_pa;
+ setttb(kernel_l1pt.pv_pa);
+ cpu_tlb_flushID();
+ cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
+
+ /*
+ * Only after the SOC registers block is mapped we can perform device
+ * tree fixups, as they may attempt to read parameters from hardware.
+ */
+ OF_interpret("perform-fixup", 0);
+
+ cninit();
+
+ physmem = memsize / PAGE_SIZE;
+
+ debugf("initarm: console initialized\n");
+ debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp);
+ debugf(" boothowto = 0x%08x\n", boothowto);
+ debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
+ print_kernel_section_addr();
+ print_kenv();
+
+ if (err_devmap != 0)
+ printf("WARNING: could not fully configure devmap, error=%d\n",
+ err_devmap);
+
+ /*
+ * Pages were allocated during the secondary bootstrap for the
+ * stacks for different CPU modes.
+ * We must now set the r13 registers in the different CPU modes to
+ * point to these stacks.
+ * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+ * of the stack memory.
+ */
+ cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
+
+ set_stackptrs(0);
+
+ /*
+ * We must now clean the cache again....
+ * Cleaning may be done by reading new data to displace any
+ * dirty data in the cache. This will have happened in setttb()
+ * but since we are boot strapping the addresses used for the read
+ * may have just been remapped and thus the cache could be out
+ * of sync. A re-clean after the switch will cure this.
+ * After booting there are no gross relocations of the kernel thus
+ * this problem will not occur after initarm().
+ */
+ cpu_idcache_wbinv_all();
+
+ /* Set stack for exception handlers */
+ data_abort_handler_address = (u_int)data_abort_handler;
+ prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+ undefined_handler_address = (u_int)undefinedinstruction_bounce;
+ undefined_init();
+
+ init_proc0(kernelstack.pv_va);
+ arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+ arm_dump_avail_init(memsize, sizeof(dump_avail) / sizeof(dump_avail[0]));
+ pmap_bootstrap(freemempos, pmap_bootstrap_lastaddr, &kernel_l1pt);
+ msgbufp = (void *)msgbufpv.pv_va;
+ msgbufinit(msgbufp, msgbufsize);
+ mutex_init();
+
+ /*
+ * Prepare map of physical memory regions available to vm subsystem.
+ */
+ physmap_init();
+
+ /* Do basic tuning, hz etc */
+ init_param2(physmem);
+ kdb_init();
+
+ return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+ sizeof(struct pcb)));
+}
+
+void
+set_stackptrs(int cpu)
+{
+
+ set_stackptr(PSR_IRQ32_MODE,
+ irqstack.pv_va + ((IRQ_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+ set_stackptr(PSR_ABT32_MODE,
+ abtstack.pv_va + ((ABT_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+ set_stackptr(PSR_UND32_MODE,
+ undstack.pv_va + ((UND_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+}
+
+#define FDT_DEVMAP_MAX (2) // FIXME
+static struct pmap_devmap fdt_devmap[FDT_DEVMAP_MAX] = {
+ { 0, 0, 0, 0, 0, }
+};
+
+
+/*
+ * Construct pmap_devmap[] with DT-derived config data.
+ */
+static int
+platform_devmap_init(void)
+{
+ int i = 0;
+#if defined(SOC_OMAP4)
+ fdt_devmap[i].pd_va = 0xE8000000;
+ fdt_devmap[i].pd_pa = 0x48000000;
+ fdt_devmap[i].pd_size = 0x1000000;
+ fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ fdt_devmap[i].pd_cache = PTE_DEVICE;
+ i++;
+#elif defined(SOC_TI_AM335X)
+ fdt_devmap[i].pd_va = 0xE4C00000;
+ fdt_devmap[i].pd_pa = 0x44C00000; /* L4_WKUP */
+ fdt_devmap[i].pd_size = 0x400000; /* 4 MB */
+ fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ fdt_devmap[i].pd_cache = PTE_DEVICE;
+ i++;
+#else
+#error "Unknown SoC"
+#endif
+
+ pmap_devmap_bootstrap_table = &fdt_devmap[0];
+ return (0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+void
+cpu_reset()
+{
+ if (ti_cpu_reset)
+ (*ti_cpu_reset)();
+ else
+ printf("no cpu_reset implementation\n");
+ printf("Reset failed!\n");
+ while (1);
+}
+
diff --git a/sys/arm/ti/ti_mmchs.c b/sys/arm/ti/ti_mmchs.c
new file mode 100644
index 0000000..cf9dc21
--- /dev/null
+++ b/sys/arm/ti/ti_mmchs.c
@@ -0,0 +1,1839 @@
+/*-
+ * 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.
+ */
+
+/**
+ * Driver for the MMC/SD/SDIO module on the TI OMAP series of SoCs.
+ *
+ * This driver is heavily based on the SD/MMC driver for the AT91 (at91_mci.c).
+ *
+ * It's important to realise that the MMC state machine is already in the kernel
+ * and this driver only exposes the specific interfaces of the controller.
+ *
+ * This driver is still very much a work in progress, I've verified that basic
+ * sector reading can be performed. But I've yet to test it with a file system
+ * or even writing. In addition I've only tested the driver with an SD card,
+ * I've no idea if MMC cards work.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+#include "mmcbr_if.h"
+#include "mmcbus_if.h"
+
+#include <arm/ti/ti_sdma.h>
+#include <arm/ti/ti_edma3.h>
+#include <arm/ti/ti_mmchs.h>
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <arm/ti/twl/twl.h>
+#include <arm/ti/twl/twl_vreg.h>
+
+#ifdef DEBUG
+#define ti_mmchs_dbg(sc, fmt, args...) \
+ device_printf((sc)->sc_dev, fmt, ## args);
+#else
+#define ti_mmchs_dbg(sc, fmt, args...)
+#endif
+
+/**
+ * Structure that stores the driver context
+ */
+struct ti_mmchs_softc {
+ device_t sc_dev;
+ uint32_t device_id;
+ struct resource* sc_irq_res;
+ struct resource* sc_mem_res;
+
+ void* sc_irq_h;
+
+ bus_dma_tag_t sc_dmatag;
+ bus_dmamap_t sc_dmamap;
+ int sc_dmamapped;
+
+ unsigned int sc_dmach_rd;
+ unsigned int sc_dmach_wr;
+ int dma_rx_trig;
+ int dma_tx_trig;
+
+ device_t sc_gpio_dev;
+ int sc_wp_gpio_pin; /* GPIO pin for MMC write protect */
+
+ device_t sc_vreg_dev;
+ const char* sc_vreg_name;
+
+ struct mtx sc_mtx;
+
+ struct mmc_host host;
+ struct mmc_request* req;
+ struct mmc_command* curcmd;
+
+ int flags;
+#define CMD_STARTED 1
+#define STOP_STARTED 2
+
+ int bus_busy; /* TODO: Needed ? */
+
+ void* sc_cmd_data_vaddr;
+ int sc_cmd_data_len;
+
+ /* The offset applied to each of the register base addresses, OMAP4
+ * register sets are offset 0x100 from the OMAP3 series.
+ */
+ unsigned long sc_reg_off;
+
+ /* The physical address of the MMCHS_DATA register, used for the DMA xfers */
+ unsigned long sc_data_reg_paddr;
+
+ /* The reference clock frequency */
+ unsigned int sc_ref_freq;
+
+ enum mmc_power_mode sc_cur_power_mode;
+};
+
+/**
+ * Macros for driver mutex locking
+ */
+#define TI_MMCHS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define TI_MMCHS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define TI_MMCHS_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "ti_mmchs", MTX_DEF)
+#define TI_MMCHS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define TI_MMCHS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_MMCHS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+static void ti_mmchs_start(struct ti_mmchs_softc *sc);
+
+/**
+ * ti_mmchs_read_4 - reads a 32-bit value from a register
+ * ti_mmchs_write_4 - writes a 32-bit value to a register
+ * @sc: pointer to the driver context
+ * @off: register offset to read from
+ * @val: the value to write into the register
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * The 32-bit value read from the register
+ */
+static inline uint32_t
+ti_mmchs_read_4(struct ti_mmchs_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->sc_mem_res, (sc->sc_reg_off + off));
+}
+
+static inline void
+ti_mmchs_write_4(struct ti_mmchs_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->sc_mem_res, (sc->sc_reg_off + off), val);
+}
+
+/**
+ * ti_mmchs_reset_controller -
+ * @arg: caller supplied arg
+ * @segs: array of segments (although in our case should only be one)
+ * @nsegs: number of segments (in our case should be 1)
+ * @error:
+ *
+ *
+ *
+ */
+static void
+ti_mmchs_reset_controller(struct ti_mmchs_softc *sc, uint32_t bit)
+{
+ unsigned long attempts;
+ uint32_t sysctl;
+
+ ti_mmchs_dbg(sc, "reseting controller - bit 0x%08x\n", bit);
+
+ sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | bit);
+
+ if ((ti_chip() == CHIP_OMAP_4) && (ti_revision() > OMAP4430_REV_ES1_0)) {
+ /* OMAP4 ES2 and greater has an updated reset logic.
+ * Monitor a 0->1 transition first
+ */
+ attempts = 10000;
+ while (!(ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
+ continue;
+ }
+
+ attempts = 10000;
+ while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
+ continue;
+
+ if (ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit)
+ device_printf(sc->sc_dev, "Error - Timeout waiting on controller reset\n");
+}
+
+/**
+ * ti_mmchs_getaddr - called by the DMA function to simply return the phys addr
+ * @arg: caller supplied arg
+ * @segs: array of segments (although in our case should only be one)
+ * @nsegs: number of segments (in our case should be 1)
+ * @error:
+ *
+ * This function is called by bus_dmamap_load() after it has compiled an array
+ * of segments, each segment is a phsyical chunk of memory. However in our case
+ * we should only have one segment, because we don't (yet?) support DMA scatter
+ * gather. To ensure we only have one segment, the DMA tag was created by
+ * bus_dma_tag_create() (called from ti_mmchs_attach) with nsegments set to 1.
+ *
+ */
+static void
+ti_mmchs_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ if (error != 0)
+ return;
+
+ *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+#ifndef SOC_TI_AM335X
+/**
+ * ti_mmchs_dma_intr - interrupt handler for DMA events triggered by the controller
+ * @ch: the dma channel number
+ * @status: bit field of the status bytes
+ * @data: callback data, in this case a pointer to the controller struct
+ *
+ *
+ * LOCKING:
+ * Called from interrupt context
+ *
+ */
+static void
+ti_mmchs_dma_intr(unsigned int ch, uint32_t status, void *data)
+{
+ /* Ignore for now ... we don't need this interrupt as we already have the
+ * interrupt from the MMC controller.
+ */
+}
+#endif
+
+/**
+ * ti_mmchs_intr_xfer_compl - called if a 'transfer complete' IRQ was received
+ * @sc: pointer to the driver context
+ * @cmd: the command that was sent previously
+ *
+ * This function is simply responsible for syncing up the DMA buffer.
+ *
+ * LOCKING:
+ * Called from interrupt context
+ *
+ * RETURNS:
+ * Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_xfer_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+ uint32_t cmd_reg;
+
+ /* Read command register to test whether this command was a read or write. */
+ cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
+
+ /* Sync-up the DMA buffer so the caller can access the new memory */
+ if (cmd_reg & MMCHS_CMD_DDIR) {
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+ }
+ else {
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+ }
+ sc->sc_dmamapped--;
+
+ /* Debugging dump of the data received */
+#if 0
+ {
+ int i;
+ uint8_t *p = (uint8_t*) sc->sc_cmd_data_vaddr;
+ for (i=0; i<sc->sc_cmd_data_len; i++) {
+ if ((i % 16) == 0)
+ printf("\n0x%04x : ", i);
+ printf("%02X ", *p++);
+ }
+ printf("\n");
+ }
+#endif
+
+ /* We are done, transfer complete */
+ return 1;
+}
+
+/**
+ * ti_mmchs_intr_cmd_compl - called if a 'command complete' IRQ was received
+ * @sc: pointer to the driver context
+ * @cmd: the command that was sent previously
+ *
+ *
+ * LOCKING:
+ * Called from interrupt context
+ *
+ * RETURNS:
+ * Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_cmd_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+ uint32_t cmd_reg;
+
+ /* Copy the response into the request struct ... if a response was
+ * expected */
+ if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) {
+ if (cmd->flags & MMC_RSP_136) {
+ cmd->resp[3] = ti_mmchs_read_4(sc, MMCHS_RSP10);
+ cmd->resp[2] = ti_mmchs_read_4(sc, MMCHS_RSP32);
+ cmd->resp[1] = ti_mmchs_read_4(sc, MMCHS_RSP54);
+ cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP76);
+ } else {
+ cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP10);
+ }
+ }
+
+ /* Check if the command was expecting some data transfer, if not
+ * we are done. */
+ cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
+ return ((cmd_reg & MMCHS_CMD_DP) == 0);
+}
+
+/**
+ * ti_mmchs_intr_error - handles error interrupts
+ * @sc: pointer to the driver context
+ * @cmd: the command that was sent previously
+ * @stat_reg: the value that was in the status register
+ *
+ *
+ * LOCKING:
+ * Called from interrupt context
+ *
+ * RETURNS:
+ * Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_error(struct ti_mmchs_softc *sc, struct mmc_command *cmd,
+ uint32_t stat_reg)
+{
+ ti_mmchs_dbg(sc, "error in xfer - stat 0x%08x\n", stat_reg);
+
+ /* Ignore CRC errors on CMD2 and ACMD47, per relevant standards */
+ if ((stat_reg & MMCHS_STAT_CCRC) && (cmd->opcode == MMC_SEND_OP_COND ||
+ cmd->opcode == ACMD_SD_SEND_OP_COND))
+ cmd->error = MMC_ERR_NONE;
+ else if (stat_reg & (MMCHS_STAT_CTO | MMCHS_STAT_DTO))
+ cmd->error = MMC_ERR_TIMEOUT;
+ else if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_DCRC))
+ cmd->error = MMC_ERR_BADCRC;
+ else
+ cmd->error = MMC_ERR_FAILED;
+
+ /* If a dma transaction we should also stop the dma transfer */
+ if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DE) {
+
+ /* Abort the DMA transfer (DDIR bit tells direction) */
+ if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DDIR)
+#ifdef SOC_TI_AM335X
+ printf("%s: DMA unimplemented\n", __func__);
+#else
+ ti_sdma_stop_xfer(sc->sc_dmach_rd);
+#endif
+ else
+#ifdef SOC_TI_AM335X
+ printf("%s: DMA unimplemented\n", __func__);
+#else
+ ti_sdma_stop_xfer(sc->sc_dmach_wr);
+#endif
+
+ /* If an error occure abort the DMA operation and free the dma map */
+ if ((sc->sc_dmamapped > 0) && (cmd->error != MMC_ERR_NONE)) {
+ bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+ sc->sc_dmamapped--;
+ }
+ }
+
+ /* Command error occured? ... if so issue a soft reset for the cmd fsm */
+ if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_CTO)) {
+ ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRC);
+ }
+
+ /* Data error occured? ... if so issue a soft reset for the data line */
+ if (stat_reg & (MMCHS_STAT_DEB | MMCHS_STAT_DCRC | MMCHS_STAT_DTO)) {
+ ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRD);
+ }
+
+ /* On any error the command is cancelled ... so we are done */
+ return 1;
+}
+
+/**
+ * ti_mmchs_intr - interrupt handler for MMC/SD/SDIO controller
+ * @arg: pointer to the driver context
+ *
+ * Interrupt handler for the MMC/SD/SDIO controller, responsible for handling
+ * the IRQ and clearing the status flags.
+ *
+ * LOCKING:
+ * Called from interrupt context
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_intr(void *arg)
+{
+ struct ti_mmchs_softc *sc = (struct ti_mmchs_softc *) arg;
+ uint32_t stat_reg;
+ int done = 0;
+
+ TI_MMCHS_LOCK(sc);
+
+ stat_reg = ti_mmchs_read_4(sc, MMCHS_STAT) & (ti_mmchs_read_4(sc,
+ MMCHS_IE) | MMCHS_STAT_ERRI);
+
+ if (sc->curcmd == NULL) {
+ device_printf(sc->sc_dev, "Error: current cmd NULL, already done?\n");
+ ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
+ TI_MMCHS_UNLOCK(sc);
+ return;
+ }
+
+ if (stat_reg & MMCHS_STAT_ERRI) {
+ /* An error has been tripped in the status register */
+ done = ti_mmchs_intr_error(sc, sc->curcmd, stat_reg);
+
+ } else {
+
+ /* NOTE: This implementation could be a bit inefficent, I don't think
+ * it is necessary to handle both the 'command complete' and 'transfer
+ * complete' for data transfers ... presumably just transfer complete
+ * is enough.
+ */
+
+ /* No error */
+ sc->curcmd->error = MMC_ERR_NONE;
+
+ /* Check if the command completed */
+ if (stat_reg & MMCHS_STAT_CC) {
+ done = ti_mmchs_intr_cmd_compl(sc, sc->curcmd);
+ }
+
+ /* Check if the transfer has completed */
+ if (stat_reg & MMCHS_STAT_TC) {
+ done = ti_mmchs_intr_xfer_compl(sc, sc->curcmd);
+ }
+
+ }
+
+ /* Clear all the interrupt status bits by writing the value back */
+ ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
+
+ /* This may mark the command as done if there is no stop request */
+ /* TODO: This is a bit ugly, needs fix-up */
+ if (done) {
+ ti_mmchs_start(sc);
+ }
+
+ TI_MMCHS_UNLOCK(sc);
+}
+
+#ifdef SOC_TI_AM335X
+static void
+ti_mmchs_edma3_rx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
+ uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
+{
+ struct ti_edma3cc_param_set ps;
+
+ bzero(&ps, sizeof(struct ti_edma3cc_param_set));
+ ps.src = src_paddr;
+ ps.dst = dst_paddr;
+ ps.dstbidx = 4;
+ ps.dstcidx = blk_size;
+ ps.acnt = 4;
+ ps.bcnt = blk_size/4;
+ ps.ccnt = num_blks;
+ ps.link = 0xffff;
+ ps.opt.tcc = sc->dma_rx_trig;
+ ps.opt.tcinten = 1;
+ ps.opt.fwid = 2; /* fifo width is 32 */
+ ps.opt.sam = 1;
+ ps.opt.syncdim = 1;
+
+ ti_edma3_param_write(sc->dma_rx_trig, &ps);
+ ti_edma3_enable_transfer_event(sc->dma_rx_trig);
+}
+
+static void
+ti_mmchs_edma3_tx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
+ uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
+{
+ struct ti_edma3cc_param_set ps;
+
+ bzero(&ps, sizeof(struct ti_edma3cc_param_set));
+ ps.src = src_paddr;
+ ps.dst = dst_paddr;
+ ps.srccidx = blk_size;
+ ps.bcnt = blk_size/4;
+ ps.ccnt = num_blks;
+ ps.srcbidx = 4;
+ ps.acnt = 0x4;
+ ps.link = 0xffff;
+ ps.opt.tcc = sc->dma_tx_trig;
+ ps.opt.tcinten = 1;
+ ps.opt.fwid = 2; /* fifo width is 32 */
+ ps.opt.dam = 1;
+ ps.opt.syncdim = 1;
+
+ ti_edma3_param_write(sc->dma_tx_trig, &ps);
+ ti_edma3_enable_transfer_event(sc->dma_tx_trig);
+}
+#endif
+
+/**
+ * ti_mmchs_start_cmd - starts the given command
+ * @sc: pointer to the driver context
+ * @cmd: the command to start
+ *
+ * The call tree for this function is
+ * - ti_mmchs_start_cmd
+ * - ti_mmchs_start
+ * - ti_mmchs_request
+ *
+ * LOCKING:
+ * Caller should be holding the OMAP_MMC lock.
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_start_cmd(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+ uint32_t cmd_reg, con_reg, ise_reg;
+ struct mmc_data *data;
+ struct mmc_request *req;
+ void *vaddr;
+ bus_addr_t paddr;
+#ifndef SOC_TI_AM335X
+ uint32_t pktsize;
+#endif
+ sc->curcmd = cmd;
+ data = cmd->data;
+ req = cmd->mrq;
+
+ /* Ensure the STR and MIT bits are cleared, these are only used for special
+ * command types.
+ */
+ con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+ con_reg &= ~(MMCHS_CON_STR | MMCHS_CON_MIT);
+
+ /* Load the command into bits 29:24 of the CMD register */
+ cmd_reg = (uint32_t)(cmd->opcode & 0x3F) << 24;
+
+ /* Set the default set of interrupts */
+ ise_reg = (MMCHS_STAT_CERR | MMCHS_STAT_CTO | MMCHS_STAT_CC | MMCHS_STAT_CEB);
+
+ /* Enable CRC checking if requested */
+ if (cmd->flags & MMC_RSP_CRC)
+ ise_reg |= MMCHS_STAT_CCRC;
+
+ /* Enable reply index checking if the response supports it */
+ if (cmd->flags & MMC_RSP_OPCODE)
+ ise_reg |= MMCHS_STAT_CIE;
+
+ /* Set the expected response length */
+ if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) {
+ cmd_reg |= MMCHS_CMD_RSP_TYPE_NO;
+ } else {
+ if (cmd->flags & MMC_RSP_136)
+ cmd_reg |= MMCHS_CMD_RSP_TYPE_136;
+ else if (cmd->flags & MMC_RSP_BUSY)
+ cmd_reg |= MMCHS_CMD_RSP_TYPE_48_BSY;
+ else
+ cmd_reg |= MMCHS_CMD_RSP_TYPE_48;
+
+ /* Enable command index/crc checks if necessary expected */
+ if (cmd->flags & MMC_RSP_CRC)
+ cmd_reg |= MMCHS_CMD_CCCE;
+ if (cmd->flags & MMC_RSP_OPCODE)
+ cmd_reg |= MMCHS_CMD_CICE;
+ }
+
+ /* Set the bits for the special commands CMD12 (MMC_STOP_TRANSMISSION) and
+ * CMD52 (SD_IO_RW_DIRECT) */
+ if (cmd->opcode == MMC_STOP_TRANSMISSION)
+ cmd_reg |= MMCHS_CMD_CMD_TYPE_IO_ABORT;
+
+ /* Check if there is any data to write */
+ if (data == NULL) {
+ /* Clear the block count */
+ ti_mmchs_write_4(sc, MMCHS_BLK, 0);
+
+ /* The no data case is fairly simple */
+ ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+ ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
+ ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
+ ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
+ ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
+ return;
+ }
+
+ /* Indicate that data is present */
+ cmd_reg |= MMCHS_CMD_DP | MMCHS_CMD_MSBS | MMCHS_CMD_BCE;
+
+ /* Indicate a read operation */
+ if (data->flags & MMC_DATA_READ)
+ cmd_reg |= MMCHS_CMD_DDIR;
+
+ /* Streaming mode */
+ if (data->flags & MMC_DATA_STREAM) {
+ con_reg |= MMCHS_CON_STR;
+ }
+
+ /* Multi-block mode */
+ if (data->flags & MMC_DATA_MULTI) {
+ cmd_reg |= MMCHS_CMD_MSBS;
+ }
+
+ /* Enable extra interrupt sources for the transfer */
+ ise_reg |= (MMCHS_STAT_TC | MMCHS_STAT_DTO | MMCHS_STAT_DEB | MMCHS_STAT_CEB);
+ if (cmd->flags & MMC_RSP_CRC)
+ ise_reg |= MMCHS_STAT_DCRC;
+
+ /* Enable the DMA transfer bit */
+ cmd_reg |= MMCHS_CMD_DE;
+
+ /* Set the block size and block count */
+ ti_mmchs_write_4(sc, MMCHS_BLK, (1 << 16) | data->len);
+
+ /* Setup the DMA stuff */
+ if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) {
+
+ vaddr = data->data;
+ data->xfer_len = 0;
+
+ /* Map the buffer buf into bus space using the dmamap map. */
+ if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, vaddr, data->len,
+ ti_mmchs_getaddr, &paddr, 0) != 0) {
+
+ if (req->cmd->flags & STOP_STARTED)
+ req->stop->error = MMC_ERR_NO_MEMORY;
+ else
+ req->cmd->error = MMC_ERR_NO_MEMORY;
+ sc->req = NULL;
+ sc->curcmd = NULL;
+ req->done(req);
+ return;
+ }
+
+#ifndef SOC_TI_AM335X
+ /* Calculate the packet size, the max packet size is 512 bytes
+ * (or 128 32-bit elements).
+ */
+ pktsize = min((data->len / 4), (512 / 4));
+#endif
+ /* Sync the DMA buffer and setup the DMA controller */
+ if (data->flags & MMC_DATA_READ) {
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREREAD);
+#ifdef SOC_TI_AM335X
+ ti_mmchs_edma3_rx_xfer_setup(sc, sc->sc_data_reg_paddr,
+ paddr, data->len, 1);
+#else
+ ti_sdma_start_xfer_packet(sc->sc_dmach_rd, sc->sc_data_reg_paddr,
+ paddr, 1, (data->len / 4), pktsize);
+#endif
+ } else {
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREWRITE);
+#ifdef SOC_TI_AM335X
+ ti_mmchs_edma3_tx_xfer_setup(sc, paddr,
+ sc->sc_data_reg_paddr, data->len, 1);
+#else
+ ti_sdma_start_xfer_packet(sc->sc_dmach_wr, paddr,
+ sc->sc_data_reg_paddr, 1, (data->len / 4), pktsize);
+#endif
+ }
+
+ /* Increase the mapped count */
+ sc->sc_dmamapped++;
+
+ sc->sc_cmd_data_vaddr = vaddr;
+ sc->sc_cmd_data_len = data->len;
+ }
+
+ /* Finally kick off the command */
+ ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+ ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
+ ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
+ ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
+ ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
+
+ /* and we're done */
+}
+
+/**
+ * ti_mmchs_start - starts a request stored in the driver context
+ * @sc: pointer to the driver context
+ *
+ * This function is called by ti_mmchs_request() in response to a read/write
+ * request from the MMC core module.
+ *
+ * LOCKING:
+ * Caller should be holding the OMAP_MMC lock.
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_start(struct ti_mmchs_softc *sc)
+{
+ struct mmc_request *req;
+
+ /* Sanity check we have a request */
+ req = sc->req;
+ if (req == NULL)
+ return;
+
+ /* assert locked */
+ if (!(sc->flags & CMD_STARTED)) {
+ sc->flags |= CMD_STARTED;
+ ti_mmchs_start_cmd(sc, req->cmd);
+ return;
+ }
+
+ if (!(sc->flags & STOP_STARTED) && req->stop) {
+ sc->flags |= STOP_STARTED;
+ ti_mmchs_start_cmd(sc, req->stop);
+ return;
+ }
+
+ /* We must be done -- bad idea to do this while locked? */
+ sc->req = NULL;
+ sc->curcmd = NULL;
+ req->done(req);
+}
+
+/**
+ * ti_mmchs_request - entry point for all read/write/cmd requests
+ * @brdev: mmc bridge device handle
+ * @reqdev: the device doing the requesting ?
+ * @req: the action requested
+ *
+ * LOCKING:
+ * None, internally takes the OMAP_MMC lock.
+ *
+ * RETURNS:
+ * 0 on success
+ * EBUSY if the driver is already performing a request
+ */
+static int
+ti_mmchs_request(device_t brdev, device_t reqdev, struct mmc_request *req)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(brdev);
+
+ TI_MMCHS_LOCK(sc);
+
+ /*
+ * XXX do we want to be able to queue up multiple commands?
+ * XXX sounds like a good idea, but all protocols are sync, so
+ * XXX maybe the idea is naive...
+ */
+ if (sc->req != NULL) {
+ TI_MMCHS_UNLOCK(sc);
+ return (EBUSY);
+ }
+
+ /* Store the request and start the command */
+ sc->req = req;
+ sc->flags = 0;
+ ti_mmchs_start(sc);
+
+ TI_MMCHS_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_mmchs_get_ro - returns the status of the read-only setting
+ * @brdev: mmc bridge device handle
+ * @reqdev: device doing the request
+ *
+ * This function is relies on hint'ed values to determine which GPIO is used
+ * to determine if the write protect is enabled. On the BeagleBoard the pin
+ * is GPIO_23.
+ *
+ * LOCKING:
+ * -
+ *
+ * RETURNS:
+ * 0 if not read-only
+ * 1 if read only
+ */
+static int
+ti_mmchs_get_ro(device_t brdev, device_t reqdev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(brdev);
+ unsigned int readonly = 0;
+
+ TI_MMCHS_LOCK(sc);
+
+ if ((sc->sc_wp_gpio_pin != -1) && (sc->sc_gpio_dev != NULL)) {
+ if (GPIO_PIN_GET(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, &readonly) != 0)
+ readonly = 0;
+ else
+ readonly = (readonly == 0) ? 0 : 1;
+ }
+
+ TI_MMCHS_UNLOCK(sc);
+
+ return (readonly);
+}
+
+/**
+ * ti_mmchs_send_init_stream - sets bus/controller settings
+ * @brdev: mmc bridge device handle
+ * @reqdev: device doing the request
+ *
+ * Send init stream sequence to card before sending IDLE command
+ *
+ * LOCKING:
+ *
+ *
+ * RETURNS:
+ * 0 if function succeeded
+ */
+static void
+ti_mmchs_send_init_stream(struct ti_mmchs_softc *sc)
+{
+ unsigned long timeout;
+ uint32_t ie, ise, con;
+
+ ti_mmchs_dbg(sc, "Performing init sequence\n");
+
+ /* Prior to issuing any command, the MMCHS controller has to execute a
+ * special INIT procedure. The MMCHS controller has to generate a clock
+ * during 1ms. During the INIT procedure, the MMCHS controller generates 80
+ * clock periods. In order to keep the 1ms gap, the MMCHS controller should
+ * be configured to generate a clock whose frequency is smaller or equal to
+ * 80 KHz. If the MMCHS controller divider bitfield width doesn't allow to
+ * choose big values, the MMCHS controller driver should perform the INIT
+ * procedure twice or three times. Twice is generally enough.
+ *
+ * The INIt procedure is executed by setting MMCHS1.MMCHS_CON[1] INIT
+ * bitfield to 1 and by sending a dummy command, writing 0x00000000 in
+ * MMCHS1.MMCHS_CMD register.
+ */
+
+ /* Disable interrupt status events but enable interrupt generation.
+ * This doesn't seem right to me, but if the interrupt generation is not
+ * enabled the CC bit doesn't seem to be set in the STAT register.
+ */
+
+ /* Enable interrupt generation */
+ ie = ti_mmchs_read_4(sc, MMCHS_IE);
+ ti_mmchs_write_4(sc, MMCHS_IE, 0x307F0033);
+
+ /* Disable generation of status events (stops interrupt triggering) */
+ ise = ti_mmchs_read_4(sc, MMCHS_ISE);
+ ti_mmchs_write_4(sc, MMCHS_ISE, 0);
+
+ /* Set the initialise stream bit */
+ con = ti_mmchs_read_4(sc, MMCHS_CON);
+ con |= MMCHS_CON_INIT;
+ ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+ /* Write a dummy command 0x00 */
+ ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
+
+ /* Loop waiting for the command to finish */
+ timeout = hz;
+ do {
+ pause("MMCINIT", 1);
+ if (timeout-- == 0) {
+ device_printf(sc->sc_dev, "Error: first stream init timed out\n");
+ break;
+ }
+ } while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
+
+ /* Clear the command complete status bit */
+ ti_mmchs_write_4(sc, MMCHS_STAT, MMCHS_STAT_CC);
+
+ /* Write another dummy command 0x00 */
+ ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
+
+ /* Loop waiting for the second command to finish */
+ timeout = hz;
+ do {
+ pause("MMCINIT", 1);
+ if (timeout-- == 0) {
+ device_printf(sc->sc_dev, "Error: second stream init timed out\n");
+ break;
+ }
+ } while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
+
+ /* Clear the stream init bit */
+ con &= ~MMCHS_CON_INIT;
+ ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+ /* Clear the status register, then restore the IE and ISE registers */
+ ti_mmchs_write_4(sc, MMCHS_STAT, 0xffffffff);
+ ti_mmchs_read_4(sc, MMCHS_STAT);
+
+ ti_mmchs_write_4(sc, MMCHS_ISE, ise);
+ ti_mmchs_write_4(sc, MMCHS_IE, ie);
+}
+
+/**
+ * ti_mmchs_update_ios - sets bus/controller settings
+ * @brdev: mmc bridge device handle
+ * @reqdev: device doing the request
+ *
+ * Called to set the bus and controller settings that need to be applied to
+ * the actual HW. Currently this function just sets the bus width and the
+ * clock speed.
+ *
+ * LOCKING:
+ *
+ *
+ * RETURNS:
+ * 0 if function succeeded
+ */
+static int
+ti_mmchs_update_ios(device_t brdev, device_t reqdev)
+{
+ struct ti_mmchs_softc *sc;
+ struct mmc_host *host;
+ struct mmc_ios *ios;
+ uint32_t clkdiv;
+ uint32_t hctl_reg;
+ uint32_t con_reg;
+ uint32_t sysctl_reg;
+#ifndef SOC_TI_AM335X
+ uint16_t mv;
+#endif
+ unsigned long timeout;
+ int do_card_init = 0;
+
+ sc = device_get_softc(brdev);
+ host = &sc->host;
+ ios = &host->ios;
+
+ /* Read the initial values of the registers */
+ hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+ con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+
+ /* Set the bus width */
+ switch (ios->bus_width) {
+ case bus_width_1:
+ hctl_reg &= ~MMCHS_HCTL_DTW;
+ con_reg &= ~MMCHS_CON_DW8;
+ break;
+ case bus_width_4:
+ hctl_reg |= MMCHS_HCTL_DTW;
+ con_reg &= ~MMCHS_CON_DW8;
+ break;
+ case bus_width_8:
+ con_reg |= MMCHS_CON_DW8;
+ break;
+ }
+
+ /* Finally write all these settings back to the registers */
+ ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
+ ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+
+ /* Check if we need to change the external voltage regulator */
+ if (sc->sc_cur_power_mode != ios->power_mode) {
+
+ if (ios->power_mode == power_up) {
+
+ /* Set the power level */
+ hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+ hctl_reg &= ~(MMCHS_HCTL_SDVS_MASK | MMCHS_HCTL_SDBP);
+
+ if ((ios->vdd == -1) || (ios->vdd >= vdd_240)) {
+#ifndef SOC_TI_AM335X
+ mv = 3000;
+#endif
+ hctl_reg |= MMCHS_HCTL_SDVS_V30;
+ } else {
+#ifndef SOC_TI_AM335X
+ mv = 1800;
+#endif
+ hctl_reg |= MMCHS_HCTL_SDVS_V18;
+ }
+
+ ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
+
+#ifdef SOC_TI_AM335X
+ printf("%s: TWL unimplemented\n", __func__);
+#else
+ /* Set the desired voltage on the regulator */
+ if (sc->sc_vreg_dev && sc->sc_vreg_name)
+ twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, mv);
+#endif
+ /* Enable the bus power */
+ ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg | MMCHS_HCTL_SDBP));
+ timeout = hz;
+ while (!(ti_mmchs_read_4(sc, MMCHS_HCTL) & MMCHS_HCTL_SDBP)) {
+ if (timeout-- == 0)
+ break;
+ pause("MMC_PWRON", 1);
+ }
+
+ } else if (ios->power_mode == power_off) {
+ /* Disable the bus power */
+ hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+ ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg & ~MMCHS_HCTL_SDBP));
+
+#ifdef SOC_TI_AM335X
+ printf("%s: TWL unimplemented\n", __func__);
+#else
+ /* Turn the power off on the voltage regulator */
+ if (sc->sc_vreg_dev && sc->sc_vreg_name)
+ twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, 0);
+#endif
+ } else if (ios->power_mode == power_on) {
+ /* Force a card re-initialisation sequence */
+ do_card_init = 1;
+ }
+
+ /* Save the new power state */
+ sc->sc_cur_power_mode = ios->power_mode;
+ }
+
+ /* need the MMCHS_SYSCTL register */
+ sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+
+ /* Just in case this hasn't been setup before, set the timeout to the default */
+ sysctl_reg &= ~MMCHS_SYSCTL_DTO_MASK;
+ sysctl_reg |= MMCHS_SYSCTL_DTO(0xe);
+
+ /* Disable the clock output while configuring the new clock */
+ sysctl_reg &= ~(MMCHS_SYSCTL_ICE | MMCHS_SYSCTL_CEN);
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+
+ /* bus mode? */
+ if (ios->clock == 0) {
+ clkdiv = 0;
+ } else {
+ clkdiv = sc->sc_ref_freq / ios->clock;
+ if (clkdiv < 1)
+ clkdiv = 1;
+ if ((sc->sc_ref_freq / clkdiv) > ios->clock)
+ clkdiv += 1;
+ if (clkdiv > 250)
+ clkdiv = 250;
+ }
+
+ /* Set the new clock divider */
+ sysctl_reg &= ~MMCHS_SYSCTL_CLKD_MASK;
+ sysctl_reg |= MMCHS_SYSCTL_CLKD(clkdiv);
+
+ /* Write the new settings ... */
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+ /* ... write the internal clock enable bit ... */
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg | MMCHS_SYSCTL_ICE);
+ /* ... wait for the clock to stablise ... */
+ while (((sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL)) &
+ MMCHS_SYSCTL_ICS) == 0) {
+ continue;
+ }
+ /* ... then enable */
+ sysctl_reg |= MMCHS_SYSCTL_CEN;
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+
+ /* If the power state has changed to 'power_on' then run the init sequence*/
+ if (do_card_init) {
+ ti_mmchs_send_init_stream(sc);
+ }
+
+ /* Set the bus mode (opendrain or normal) */
+ con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+ if (ios->bus_mode == opendrain)
+ con_reg |= MMCHS_CON_OD;
+ else
+ con_reg &= ~MMCHS_CON_OD;
+ ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+
+ return (0);
+}
+
+/**
+ * ti_mmchs_acquire_host -
+ * @brdev: mmc bridge device handle
+ * @reqdev: device doing the request
+ *
+ * TODO: Is this function needed ?
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 function succeeded
+ *
+ */
+static int
+ti_mmchs_acquire_host(device_t brdev, device_t reqdev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(brdev);
+ int err = 0;
+
+ TI_MMCHS_LOCK(sc);
+
+ while (sc->bus_busy) {
+ msleep(sc, &sc->sc_mtx, PZERO, "mmc", hz / 5);
+ }
+
+ sc->bus_busy++;
+
+ TI_MMCHS_UNLOCK(sc);
+
+ return (err);
+}
+
+/**
+ * ti_mmchs_release_host -
+ * @brdev: mmc bridge device handle
+ * @reqdev: device doing the request
+ *
+ * TODO: Is this function needed ?
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 function succeeded
+ *
+ */
+static int
+ti_mmchs_release_host(device_t brdev, device_t reqdev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(brdev);
+
+ TI_MMCHS_LOCK(sc);
+
+ sc->bus_busy--;
+ wakeup(sc);
+
+ TI_MMCHS_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_mmchs_read_ivar - returns driver conf variables
+ * @bus:
+ * @child:
+ * @which: The variable to get the result for
+ * @result: Upon return will store the variable value
+ *
+ *
+ *
+ * LOCKING:
+ * None, caller must hold locks
+ *
+ * RETURNS:
+ * 0 on success
+ * EINVAL if the variable requested is invalid
+ */
+static int
+ti_mmchs_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(bus);
+
+ switch (which) {
+ case MMCBR_IVAR_BUS_MODE:
+ *(int *)result = sc->host.ios.bus_mode;
+ break;
+ case MMCBR_IVAR_BUS_WIDTH:
+ *(int *)result = sc->host.ios.bus_width;
+ break;
+ case MMCBR_IVAR_CHIP_SELECT:
+ *(int *)result = sc->host.ios.chip_select;
+ break;
+ case MMCBR_IVAR_CLOCK:
+ *(int *)result = sc->host.ios.clock;
+ break;
+ case MMCBR_IVAR_F_MIN:
+ *(int *)result = sc->host.f_min;
+ break;
+ case MMCBR_IVAR_F_MAX:
+ *(int *)result = sc->host.f_max;
+ break;
+ case MMCBR_IVAR_HOST_OCR:
+ *(int *)result = sc->host.host_ocr;
+ break;
+ case MMCBR_IVAR_MODE:
+ *(int *)result = sc->host.mode;
+ break;
+ case MMCBR_IVAR_OCR:
+ *(int *)result = sc->host.ocr;
+ break;
+ case MMCBR_IVAR_POWER_MODE:
+ *(int *)result = sc->host.ios.power_mode;
+ break;
+ case MMCBR_IVAR_VDD:
+ *(int *)result = sc->host.ios.vdd;
+ break;
+ case MMCBR_IVAR_CAPS:
+ *(int *)result = sc->host.caps;
+ break;
+ case MMCBR_IVAR_MAX_DATA:
+ *(int *)result = 1;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+/**
+ * ti_mmchs_write_ivar - writes a driver conf variables
+ * @bus:
+ * @child:
+ * @which: The variable to set
+ * @value: The value to write into the variable
+ *
+ *
+ *
+ * LOCKING:
+ * None, caller must hold locks
+ *
+ * RETURNS:
+ * 0 on success
+ * EINVAL if the variable requested is invalid
+ */
+static int
+ti_mmchs_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(bus);
+
+ switch (which) {
+ case MMCBR_IVAR_BUS_MODE:
+ sc->host.ios.bus_mode = value;
+ break;
+ case MMCBR_IVAR_BUS_WIDTH:
+ sc->host.ios.bus_width = value;
+ break;
+ case MMCBR_IVAR_CHIP_SELECT:
+ sc->host.ios.chip_select = value;
+ break;
+ case MMCBR_IVAR_CLOCK:
+ sc->host.ios.clock = value;
+ break;
+ case MMCBR_IVAR_MODE:
+ sc->host.mode = value;
+ break;
+ case MMCBR_IVAR_OCR:
+ sc->host.ocr = value;
+ break;
+ case MMCBR_IVAR_POWER_MODE:
+ sc->host.ios.power_mode = value;
+ break;
+ case MMCBR_IVAR_VDD:
+ sc->host.ios.vdd = value;
+ break;
+ /* These are read-only */
+ case MMCBR_IVAR_CAPS:
+ case MMCBR_IVAR_HOST_OCR:
+ case MMCBR_IVAR_F_MIN:
+ case MMCBR_IVAR_F_MAX:
+ case MMCBR_IVAR_MAX_DATA:
+ return (EINVAL);
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+/**
+ * ti_mmchs_hw_init - initialises the MMC/SD/SIO controller
+ * @dev: mmc device handle
+ *
+ * Called by the driver attach function during driver initialisation. This
+ * function is responsibly to setup the controller ready for transactions.
+ *
+ * LOCKING:
+ * No locking, assumed to only be called during initialisation.
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_hw_init(device_t dev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(dev);
+ clk_ident_t clk;
+ unsigned long timeout;
+ uint32_t sysctl;
+ uint32_t capa;
+ uint32_t con;
+
+ /* 1: Enable the controller and interface/functional clocks */
+ clk = MMC0_CLK + sc->device_id;
+
+ if (ti_prcm_clk_enable(clk) != 0) {
+ device_printf(dev, "Error: failed to enable MMC clock\n");
+ return;
+ }
+
+ /* 1a: Get the frequency of the source clock */
+ if (ti_prcm_clk_get_source_freq(clk, &sc->sc_ref_freq) != 0) {
+ device_printf(dev, "Error: failed to get source clock freq\n");
+ return;
+ }
+
+ /* 2: Issue a softreset to the controller */
+ ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, 0x0002);
+ timeout = 100;
+ while ((ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & 0x01) == 0x0) {
+ DELAY(1000);
+ if (timeout-- == 0) {
+ device_printf(dev, "Error: reset operation timed out\n");
+ return;
+ }
+ }
+
+ /* 3: Reset both the command and data state machines */
+ sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+ ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | MMCHS_SYSCTL_SRA);
+ timeout = 100;
+ while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & MMCHS_SYSCTL_SRA) != 0x0) {
+ DELAY(1000);
+ if (timeout-- == 0) {
+ device_printf(dev, "Error: reset operation timed out\n");
+ return;
+ }
+ }
+
+ /* 4: Set initial host configuration (1-bit mode, pwroff) and capabilities */
+ ti_mmchs_write_4(sc, MMCHS_HCTL, MMCHS_HCTL_SDVS_V30);
+
+ capa = ti_mmchs_read_4(sc, MMCHS_CAPA);
+ ti_mmchs_write_4(sc, MMCHS_CAPA, capa | MMCHS_CAPA_VS30 | MMCHS_CAPA_VS18);
+
+ /* 5: Set the initial bus configuration
+ * 0 CTPL_MMC_SD : Control Power for DAT1 line
+ * 0 WPP_ACTIVE_HIGH : Write protect polarity
+ * 0 CDP_ACTIVE_HIGH : Card detect polarity
+ * 0 CTO_ENABLED : MMC interrupt command
+ * 0 DW8_DISABLED : 8-bit mode MMC select
+ * 0 MODE_FUNC : Mode select
+ * 0 STREAM_DISABLED : Stream command
+ * 0 HR_DISABLED : Broadcast host response
+ * 0 INIT_DISABLED : Send initialization stream
+ * 0 OD_DISABLED : No Open Drain
+ */
+ con = ti_mmchs_read_4(sc, MMCHS_CON) & MMCHS_CON_DVAL_MASK;
+ ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+}
+
+/**
+ * ti_mmchs_fini - shutdown the MMC/SD/SIO controller
+ * @dev: mmc device handle
+ *
+ * Responsible for shutting done the MMC controller, this function may be
+ * called as part of a reset sequence.
+ *
+ * LOCKING:
+ * No locking, assumed to be called during tear-down/reset.
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_hw_fini(device_t dev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(dev);
+
+ /* Disable all interrupts */
+ ti_mmchs_write_4(sc, MMCHS_ISE, 0x00000000);
+ ti_mmchs_write_4(sc, MMCHS_IE, 0x00000000);
+
+ /* Disable the functional and interface clocks */
+ ti_prcm_clk_disable(MMC0_CLK + sc->device_id);
+}
+
+/**
+ * ti_mmchs_init_dma_channels - initalise the DMA channels
+ * @sc: driver soft context
+ *
+ * Attempts to activate an RX and TX DMA channel for the MMC device.
+ *
+ * LOCKING:
+ * No locking, assumed to be called during tear-down/reset.
+ *
+ * RETURNS:
+ * 0 on success, a negative error code on failure.
+ */
+static int
+ti_mmchs_init_dma_channels(struct ti_mmchs_softc *sc)
+{
+#ifdef SOC_TI_AM335X
+ switch (sc->device_id) {
+ case 0:
+ sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT0;
+ sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT0;
+ break;
+ case 1:
+ sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT1;
+ sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT1;
+ break;
+ default:
+ return(EINVAL);
+ }
+
+#define EVTQNUM 0
+ /* TODO EDMA3 have 3 queues, so we need some queue allocation call */
+ ti_edma3_init(EVTQNUM);
+ ti_edma3_request_dma_ch(sc->dma_tx_trig, sc->dma_tx_trig, EVTQNUM);
+ ti_edma3_request_dma_ch(sc->dma_rx_trig, sc->dma_rx_trig, EVTQNUM);
+#else
+ int err;
+ uint32_t rev;
+
+ /* Get the current chip revision */
+ rev = ti_revision();
+ if ((OMAP_REV_DEVICE(rev) != OMAP4430_DEV) && (sc->device_id > 3))
+ return(EINVAL);
+
+ /* Get the DMA MMC triggers */
+ switch (sc->device_id) {
+ case 1:
+ sc->dma_tx_trig = 60;
+ sc->dma_rx_trig = 61;
+ break;
+ case 2:
+ sc->dma_tx_trig = 46;
+ sc->dma_rx_trig = 47;
+ break;
+ case 3:
+ sc->dma_tx_trig = 76;
+ sc->dma_rx_trig = 77;
+ break;
+ /* The following are OMAP4 only */
+ case 4:
+ sc->dma_tx_trig = 56;
+ sc->dma_rx_trig = 57;
+ break;
+ case 5:
+ sc->dma_tx_trig = 58;
+ sc->dma_rx_trig = 59;
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ /* Activate a RX channel from the OMAP DMA driver */
+ err = ti_sdma_activate_channel(&sc->sc_dmach_rd, ti_mmchs_dma_intr, sc);
+ if (err != 0)
+ return(err);
+
+ /* Setup the RX channel for MMC data transfers */
+ ti_sdma_set_xfer_burst(sc->sc_dmach_rd, TI_SDMA_BURST_NONE,
+ TI_SDMA_BURST_64);
+ ti_sdma_set_xfer_data_type(sc->sc_dmach_rd, TI_SDMA_DATA_32BITS_SCALAR);
+ ti_sdma_sync_params(sc->sc_dmach_rd, sc->dma_rx_trig,
+ TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_SRC);
+ ti_sdma_set_addr_mode(sc->sc_dmach_rd, TI_SDMA_ADDR_CONSTANT,
+ TI_SDMA_ADDR_POST_INCREMENT);
+
+ /* Activate and configure the TX DMA channel */
+ err = ti_sdma_activate_channel(&sc->sc_dmach_wr, ti_mmchs_dma_intr, sc);
+ if (err != 0)
+ return(err);
+
+ /* Setup the TX channel for MMC data transfers */
+ ti_sdma_set_xfer_burst(sc->sc_dmach_wr, TI_SDMA_BURST_64,
+ TI_SDMA_BURST_NONE);
+ ti_sdma_set_xfer_data_type(sc->sc_dmach_wr, TI_SDMA_DATA_32BITS_SCALAR);
+ ti_sdma_sync_params(sc->sc_dmach_wr, sc->dma_tx_trig,
+ TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_DST);
+ ti_sdma_set_addr_mode(sc->sc_dmach_wr, TI_SDMA_ADDR_POST_INCREMENT,
+ TI_SDMA_ADDR_CONSTANT);
+#endif
+ return(0);
+}
+
+/**
+ * ti_mmchs_deactivate - deactivates the driver
+ * @dev: mmc device handle
+ *
+ * Unmaps the register set and releases the IRQ resource.
+ *
+ * LOCKING:
+ * None required
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_mmchs_deactivate(device_t dev)
+{
+ struct ti_mmchs_softc *sc= device_get_softc(dev);
+
+ /* Remove the IRQ handler */
+ if (sc->sc_irq_h != NULL) {
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
+ sc->sc_irq_h = NULL;
+ }
+
+ /* Do the generic detach */
+ bus_generic_detach(sc->sc_dev);
+
+#ifdef SOC_TI_AM335X
+ printf("%s: DMA unimplemented\n", __func__);
+#else
+ /* Deactivate the DMA channels */
+ ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+ ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+#endif
+
+ /* Unmap the MMC controller registers */
+ if (sc->sc_mem_res != 0) {
+ bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res),
+ sc->sc_mem_res);
+ sc->sc_mem_res = NULL;
+ }
+
+ /* Release the IRQ resource */
+ if (sc->sc_irq_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res),
+ sc->sc_irq_res);
+ sc->sc_irq_res = NULL;
+ }
+
+ return;
+}
+
+/**
+ * ti_mmchs_activate - activates the driver
+ * @dev: mmc device handle
+ *
+ * Maps in the register set and requests an IRQ handler for the MMC controller.
+ *
+ * LOCKING:
+ * None required
+ *
+ * RETURNS:
+ * 0 on sucess
+ * ENOMEM if failed to map register set
+ */
+static int
+ti_mmchs_activate(device_t dev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(dev);
+ unsigned long addr;
+ int rid;
+ int err;
+
+ /* Get the memory resource for the register mapping */
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->sc_mem_res == NULL)
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ /* Allocate an IRQ resource for the MMC controller */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_irq_res == NULL)
+ goto errout;
+
+ /* Allocate DMA tags and maps */
+ err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
+ NULL, MAXPHYS, 1, MAXPHYS, BUS_DMA_ALLOCNOW, NULL,
+ NULL, &sc->sc_dmatag);
+ if (err != 0)
+ goto errout;
+
+ err = bus_dmamap_create(sc->sc_dmatag, 0, &sc->sc_dmamap);
+ if (err != 0)
+ goto errout;
+
+ /* Initialise the DMA channels to be used by the controller */
+ err = ti_mmchs_init_dma_channels(sc);
+ if (err != 0)
+ goto errout;
+
+ /* Set the register offset */
+ if (ti_chip() == CHIP_OMAP_3)
+ sc->sc_reg_off = OMAP3_MMCHS_REG_OFFSET;
+ else if (ti_chip() == CHIP_OMAP_4)
+ sc->sc_reg_off = OMAP4_MMCHS_REG_OFFSET;
+ else if (ti_chip() == CHIP_AM335X)
+ sc->sc_reg_off = AM335X_MMCHS_REG_OFFSET;
+ else
+ panic("Unknown OMAP device\n");
+
+ /* Get the physical address of the MMC data register, needed for DMA */
+ addr = vtophys(rman_get_start(sc->sc_mem_res));
+ sc->sc_data_reg_paddr = addr + sc->sc_reg_off + MMCHS_DATA;
+
+ /* Set the initial power state to off */
+ sc->sc_cur_power_mode = power_off;
+
+ return (0);
+
+errout:
+ ti_mmchs_deactivate(dev);
+ return (ENOMEM);
+}
+
+/**
+ * ti_mmchs_probe - probe function for the driver
+ * @dev: mmc device handle
+ *
+ *
+ *
+ * RETURNS:
+ * always returns 0
+ */
+static int
+ti_mmchs_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,mmchs"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI MMC/SD/SDIO High Speed Interface");
+ return (0);
+}
+
+/**
+ * ti_mmchs_attach - attach function for the driver
+ * @dev: mmc device handle
+ *
+ * Driver initialisation, sets-up the bus mappings, DMA mapping/channels and
+ * the actual controller by calling ti_mmchs_init().
+ *
+ * RETURNS:
+ * Returns 0 on success or a negative error code.
+ */
+static int
+ti_mmchs_attach(device_t dev)
+{
+ struct ti_mmchs_softc *sc = device_get_softc(dev);
+ int unit = device_get_unit(dev);
+ phandle_t node;
+ pcell_t did;
+ int err;
+
+ /* Save the device and bus tag */
+ sc->sc_dev = dev;
+
+ /* Get the mmchs device id from FDT */
+ node = ofw_bus_get_node(dev);
+ if ((OF_getprop(node, "mmchs-device-id", &did, sizeof(did))) <= 0) {
+ device_printf(dev, "missing mmchs-device-id attribute in FDT\n");
+ return (ENXIO);
+ }
+ sc->device_id = fdt32_to_cpu(did);
+
+ /* Initiate the mtex lock */
+ TI_MMCHS_LOCK_INIT(sc);
+
+ /* Indicate the DMA channels haven't yet been allocated */
+ sc->sc_dmach_rd = (unsigned int)-1;
+ sc->sc_dmach_wr = (unsigned int)-1;
+
+ /* Get the hint'ed write detect pin */
+ /* TODO: take this from FDT */
+ if (resource_int_value("ti_mmchs", unit, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){
+ sc->sc_wp_gpio_pin = -1;
+ } else {
+ /* Get the GPIO device, we need this for the write protect pin */
+ sc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
+ if (sc->sc_gpio_dev == NULL)
+ device_printf(dev, "Error: failed to get the GPIO device\n");
+ else
+ GPIO_PIN_SETFLAGS(sc->sc_gpio_dev, sc->sc_wp_gpio_pin,
+ GPIO_PIN_INPUT);
+ }
+
+ /* Get the TWL voltage regulator device, we need this to for setting the
+ * voltage of the bus on certain OMAP platforms.
+ */
+ sc->sc_vreg_name = NULL;
+
+ /* TODO: add voltage regulator knob to FDT */
+#ifdef notyet
+ sc->sc_vreg_dev = devclass_get_device(devclass_find("twl_vreg"), 0);
+ if (sc->sc_vreg_dev == NULL) {
+ device_printf(dev, "Error: failed to get the votlage regulator"
+ " device\n");
+ sc->sc_vreg_name = NULL;
+ }
+#endif
+
+ /* Activate the device */
+ err = ti_mmchs_activate(dev);
+ if (err)
+ goto out;
+
+ /* Initialise the controller */
+ ti_mmchs_hw_init(dev);
+
+ /* Activate the interrupt and attach a handler */
+ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, ti_mmchs_intr, sc, &sc->sc_irq_h);
+ if (err != 0)
+ goto out;
+
+ /* Add host details */
+ sc->host.f_min = sc->sc_ref_freq / 1023;
+ sc->host.f_max = sc->sc_ref_freq;
+ sc->host.host_ocr = MMC_OCR_290_300 | MMC_OCR_300_310;
+ sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+
+ device_add_child(dev, "mmc", 0);
+
+ device_set_ivars(dev, &sc->host);
+ err = bus_generic_attach(dev);
+
+out:
+ if (err) {
+ TI_MMCHS_LOCK_DESTROY(sc);
+ ti_mmchs_deactivate(dev);
+
+#ifdef SOC_TI_AM335X
+ printf("%s: DMA unimplemented\n", __func__);
+#else
+ if (sc->sc_dmach_rd != (unsigned int)-1)
+ ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+ if (sc->sc_dmach_wr != (unsigned int)-1)
+ ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+#endif
+ }
+
+ return (err);
+}
+
+/**
+ * ti_mmchs_detach - dettach function for the driver
+ * @dev: mmc device handle
+ *
+ * Shutdowns the controll and release resources allocated by the driver.
+ *
+ * RETURNS:
+ * Always returns 0.
+ */
+static int
+ti_mmchs_detach(device_t dev)
+{
+#ifndef SOC_TI_AM335X
+ struct ti_mmchs_softc *sc = device_get_softc(dev);
+#endif
+
+ ti_mmchs_hw_fini(dev);
+ ti_mmchs_deactivate(dev);
+
+#ifdef SOC_TI_AM335X
+ printf("%s: DMA unimplemented\n", __func__);
+#else
+ ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+ ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+#endif
+
+ return (0);
+}
+
+static device_method_t ti_mmchs_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, ti_mmchs_probe),
+ DEVMETHOD(device_attach, ti_mmchs_attach),
+ DEVMETHOD(device_detach, ti_mmchs_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_read_ivar, ti_mmchs_read_ivar),
+ DEVMETHOD(bus_write_ivar, ti_mmchs_write_ivar),
+
+ /* mmcbr_if - MMC state machine callbacks */
+ DEVMETHOD(mmcbr_update_ios, ti_mmchs_update_ios),
+ DEVMETHOD(mmcbr_request, ti_mmchs_request),
+ DEVMETHOD(mmcbr_get_ro, ti_mmchs_get_ro),
+ DEVMETHOD(mmcbr_acquire_host, ti_mmchs_acquire_host),
+ DEVMETHOD(mmcbr_release_host, ti_mmchs_release_host),
+
+ {0, 0},
+};
+
+static driver_t ti_mmchs_driver = {
+ "ti_mmchs",
+ ti_mmchs_methods,
+ sizeof(struct ti_mmchs_softc),
+};
+static devclass_t ti_mmchs_devclass;
+
+DRIVER_MODULE(ti_mmchs, simplebus, ti_mmchs_driver, ti_mmchs_devclass, 0, 0);
+MODULE_DEPEND(ti_mmchs, ti_prcm, 1, 1, 1);
+#ifdef SOC_TI_AM335X
+MODULE_DEPEND(ti_mmchs, ti_edma, 1, 1, 1);
+#else
+MODULE_DEPEND(ti_mmchs, ti_sdma, 1, 1, 1);
+#endif
+MODULE_DEPEND(ti_mmchs, ti_gpio, 1, 1, 1);
+
+/* FIXME: MODULE_DEPEND(ti_mmchs, twl_vreg, 1, 1, 1); */
diff --git a/sys/arm/ti/ti_mmchs.h b/sys/arm/ti/ti_mmchs.h
new file mode 100644
index 0000000..5a7f3f4
--- /dev/null
+++ b/sys/arm/ti/ti_mmchs.h
@@ -0,0 +1,170 @@
+/*-
+ * 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_MMCHS_H_
+#define _TI_MMCHS_H_
+
+/**
+ * Header file for the TI MMC/SD/SDIO driver.
+ *
+ * Simply contains register addresses and bit flags.
+ */
+
+/* Register offsets within each of the MMC/SD/SDIO controllers */
+#define MMCHS_SYSCONFIG 0x010
+#define MMCHS_SYSSTATUS 0x014
+#define MMCHS_CSRE 0x024
+#define MMCHS_SYSTEST 0x028
+#define MMCHS_CON 0x02C
+#define MMCHS_PWCNT 0x030
+#define MMCHS_BLK 0x104
+#define MMCHS_ARG 0x108
+#define MMCHS_CMD 0x10C
+#define MMCHS_RSP10 0x110
+#define MMCHS_RSP32 0x114
+#define MMCHS_RSP54 0x118
+#define MMCHS_RSP76 0x11C
+#define MMCHS_DATA 0x120
+#define MMCHS_PSTATE 0x124
+#define MMCHS_HCTL 0x128
+#define MMCHS_SYSCTL 0x12C
+#define MMCHS_STAT 0x130
+#define MMCHS_IE 0x134
+#define MMCHS_ISE 0x138
+#define MMCHS_AC12 0x13C
+#define MMCHS_CAPA 0x140
+#define MMCHS_CUR_CAPA 0x148
+#define MMCHS_REV 0x1FC
+
+/* OMAP4 and OMAP4 have different register addresses */
+#define OMAP3_MMCHS_REG_OFFSET 0x000
+#define OMAP4_MMCHS_REG_OFFSET 0x100
+#define AM335X_MMCHS_REG_OFFSET 0x100
+
+/* Register bit settings */
+#define MMCHS_STAT_BADA (1UL << 29)
+#define MMCHS_STAT_CERR (1UL << 28)
+#define MMCHS_STAT_ACE (1UL << 24)
+#define MMCHS_STAT_DEB (1UL << 22)
+#define MMCHS_STAT_DCRC (1UL << 21)
+#define MMCHS_STAT_DTO (1UL << 20)
+#define MMCHS_STAT_CIE (1UL << 19)
+#define MMCHS_STAT_CEB (1UL << 18)
+#define MMCHS_STAT_CCRC (1UL << 17)
+#define MMCHS_STAT_CTO (1UL << 16)
+#define MMCHS_STAT_ERRI (1UL << 15)
+#define MMCHS_STAT_OBI (1UL << 9)
+#define MMCHS_STAT_CIRQ (1UL << 8)
+#define MMCHS_STAT_BRR (1UL << 5)
+#define MMCHS_STAT_BWR (1UL << 4)
+#define MMCHS_STAT_BGE (1UL << 2)
+#define MMCHS_STAT_TC (1UL << 1)
+#define MMCHS_STAT_CC (1UL << 0)
+
+#define MMCHS_STAT_CLEAR_MASK 0x3BFF8337UL
+
+#define MMCHS_SYSCTL_SRD (1UL << 26)
+#define MMCHS_SYSCTL_SRC (1UL << 25)
+#define MMCHS_SYSCTL_SRA (1UL << 24)
+#define MMCHS_SYSCTL_DTO(x) (((x) & 0xf) << 16)
+#define MMCHS_SYSCTL_DTO_MASK MMCHS_SYSCTL_DTO(0xf)
+#define MMCHS_SYSCTL_CLKD(x) (((x) & 0x3ff) << 6)
+#define MMCHS_SYSCTL_CLKD_MASK MMCHS_SYSCTL_CLKD(0x3ff)
+#define MMCHS_SYSCTL_CEN (1UL << 2)
+#define MMCHS_SYSCTL_ICS (1UL << 1)
+#define MMCHS_SYSCTL_ICE (1UL << 0)
+
+#define MMCHS_HCTL_OBWE (1UL << 27)
+#define MMCHS_HCTL_REM (1UL << 26)
+#define MMCHS_HCTL_INS (1UL << 25)
+#define MMCHS_HCTL_IWE (1UL << 24)
+#define MMCHS_HCTL_IBG (1UL << 19)
+#define MMCHS_HCTL_RWC (1UL << 18)
+#define MMCHS_HCTL_CR (1UL << 17)
+#define MMCHS_HCTL_SBGR (1UL << 16)
+#define MMCHS_HCTL_SDVS_MASK (7UL << 9)
+#define MMCHS_HCTL_SDVS_V18 (5UL << 9)
+#define MMCHS_HCTL_SDVS_V30 (6UL << 9)
+#define MMCHS_HCTL_SDVS_V33 (7UL << 9)
+#define MMCHS_HCTL_SDBP (1UL << 8)
+#define MMCHS_HCTL_DTW (1UL << 1)
+
+#define MMCHS_CAPA_VS18 (1UL << 26)
+#define MMCHS_CAPA_VS30 (1UL << 25)
+#define MMCHS_CAPA_VS33 (1UL << 24)
+
+#define MMCHS_CMD_CMD_TYPE_IO_ABORT (3UL << 21)
+#define MMCHS_CMD_CMD_TYPE_FUNC_SEL (2UL << 21)
+#define MMCHS_CMD_CMD_TYPE_SUSPEND (1UL << 21)
+#define MMCHS_CMD_CMD_TYPE_OTHERS (0UL << 21)
+#define MMCHS_CMD_CMD_TYPE_MASK (3UL << 22)
+
+#define MMCHS_CMD_DP (1UL << 21)
+#define MMCHS_CMD_CICE (1UL << 20)
+#define MMCHS_CMD_CCCE (1UL << 19)
+
+#define MMCHS_CMD_RSP_TYPE_MASK (3UL << 16)
+#define MMCHS_CMD_RSP_TYPE_NO (0UL << 16)
+#define MMCHS_CMD_RSP_TYPE_136 (1UL << 16)
+#define MMCHS_CMD_RSP_TYPE_48 (2UL << 16)
+#define MMCHS_CMD_RSP_TYPE_48_BSY (3UL << 16)
+
+#define MMCHS_CMD_MSBS (1UL << 5)
+#define MMCHS_CMD_DDIR (1UL << 4)
+#define MMCHS_CMD_ACEN (1UL << 2)
+#define MMCHS_CMD_BCE (1UL << 1)
+#define MMCHS_CMD_DE (1UL << 0)
+
+#define MMCHS_CON_CLKEXTFREE (1UL << 16)
+#define MMCHS_CON_PADEN (1UL << 15)
+#define MMCHS_CON_OBIE (1UL << 14)
+#define MMCHS_CON_OBIP (1UL << 13)
+#define MMCHS_CON_CEATA (1UL << 12)
+#define MMCHS_CON_CTPL (1UL << 11)
+
+#define MMCHS_CON_DVAL_8_4MS (3UL << 9)
+#define MMCHS_CON_DVAL_1MS (2UL << 9)
+#define MMCHS_CON_DVAL_231US (1UL << 9)
+#define MMCHS_CON_DVAL_33US (0UL << 9)
+#define MMCHS_CON_DVAL_MASK (3UL << 9)
+
+#define MMCHS_CON_WPP (1UL << 8)
+#define MMCHS_CON_CDP (1UL << 7)
+#define MMCHS_CON_MIT (1UL << 6)
+#define MMCHS_CON_DW8 (1UL << 5)
+#define MMCHS_CON_MODE (1UL << 4)
+#define MMCHS_CON_STR (1UL << 3)
+#define MMCHS_CON_HR (1UL << 2)
+#define MMCHS_CON_INIT (1UL << 1)
+#define MMCHS_CON_OD (1UL << 0)
+
+#define MMCHS_CAPA_VS18 (1UL << 26)
+#define MMCHS_CAPA_VS30 (1UL << 25)
+#define MMCHS_CAPA_VS33 (1UL << 24)
+
+#endif /* _TI_MMCHS_H_ */
diff --git a/sys/arm/ti/ti_prcm.c b/sys/arm/ti/ti_prcm.c
new file mode 100644
index 0000000..57709ad
--- /dev/null
+++ b/sys/arm/ti/ti_prcm.c
@@ -0,0 +1,309 @@
+/*
+ * 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 Managment 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 <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.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_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 = &(ti_clk_devmap[0]);
+ 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);
+}
diff --git a/sys/arm/ti/ti_prcm.h b/sys/arm/ti/ti_prcm.h
new file mode 100644
index 0000000..7f6b99d
--- /dev/null
+++ b/sys/arm/ti/ti_prcm.h
@@ -0,0 +1,185 @@
+/*
+ * 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 {
+
+ /* 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 */
+ MMC0_CLK = 100,
+ MMC1_CLK,
+ MMC2_CLK,
+ MMC3_CLK,
+ MMC4_CLK,
+ MMC5_CLK,
+
+ /* I2C modules */
+ I2C0_CLK = 200,
+ I2C1_CLK,
+ I2C2_CLK,
+ I2C3_CLK,
+ I2C4_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,
+
+ /* General purpose timer modules */
+ GPTIMER1_CLK = 500,
+ GPTIMER2_CLK,
+ GPTIMER3_CLK,
+ GPTIMER4_CLK,
+ GPTIMER5_CLK,
+ GPTIMER6_CLK,
+ GPTIMER7_CLK,
+ GPTIMER8_CLK,
+ GPTIMER9_CLK,
+ GPTIMER10_CLK,
+ GPTIMER11_CLK,
+ GPTIMER12_CLK,
+
+ /* McBSP module(s) */
+ MCBSP1_CLK = 600,
+ MCBSP2_CLK,
+ MCBSP3_CLK,
+ MCBSP4_CLK,
+ MCBSP5_CLK,
+
+ /* General purpose I/O modules */
+ GPIO0_CLK = 700,
+ GPIO1_CLK,
+ GPIO2_CLK,
+ GPIO3_CLK,
+ GPIO4_CLK,
+ GPIO5_CLK,
+ GPIO6_CLK,
+
+ /* sDMA module */
+ SDMA_CLK = 800,
+
+ /* DMTimer modules */
+ DMTIMER0_CLK = 900,
+ DMTIMER1_CLK,
+ DMTIMER2_CLK,
+ DMTIMER3_CLK,
+ DMTIMER4_CLK,
+ DMTIMER5_CLK,
+ DMTIMER6_CLK,
+ DMTIMER7_CLK,
+
+ /* 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,
+
+ INVALID_CLK_IDENT
+
+} 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_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_get_source_freq(clk_ident_t clk, unsigned int *freq);
+void ti_prcm_reset(void);
+
+#endif /* _TI_PRCM_H_ */
diff --git a/sys/arm/ti/ti_scm.c b/sys/arm/ti/ti_scm.c
new file mode 100644
index 0000000..0ae39e9
--- /dev/null
+++ b/sys/arm/ti/ti_scm.c
@@ -0,0 +1,493 @@
+/*
+ * 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 <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "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_2(sc, reg) \
+ bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define ti_scm_write_2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#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))
+
+
+/**
+ * ti_padconf_devmap - Array of pins, should be defined one per SoC
+ *
+ * This array is typically defined in one of the targeted *_scm_pinumx.c
+ * files and is specific to the given SoC platform. Each entry in the array
+ * corresponds to an individual pin.
+ */
+extern const struct ti_scm_device ti_scm_dev;
+
+
+/**
+ * ti_scm_padconf_from_name - searches the list of pads and returns entry
+ * with matching ball name.
+ * @ballname: the name of the ball
+ *
+ * RETURNS:
+ * A pointer to the matching padconf or NULL if the ball wasn't found.
+ */
+static const struct ti_scm_padconf*
+ti_scm_padconf_from_name(const char *ballname)
+{
+ const struct ti_scm_padconf *padconf;
+
+ padconf = ti_scm_dev.padconf;
+ while (padconf->ballname != NULL) {
+ if (strcmp(ballname, padconf->ballname) == 0)
+ return(padconf);
+ padconf++;
+ }
+
+ return (NULL);
+}
+
+/**
+ * ti_scm_padconf_set_internal - sets the muxmode and state for a pad/pin
+ * @padconf: pointer to the pad structure
+ * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or already in use.
+ */
+static int
+ti_scm_padconf_set_internal(struct ti_scm_softc *sc,
+ const struct ti_scm_padconf *padconf,
+ const char *muxmode, unsigned int state)
+{
+ unsigned int mode;
+ uint16_t reg_val;
+
+ /* populate the new value for the PADCONF register */
+ reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
+
+ /* find the new mode requested */
+ for (mode = 0; mode < 8; mode++) {
+ if ((padconf->muxmodes[mode] != NULL) &&
+ (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
+ break;
+ }
+ }
+
+ /* couldn't find the mux mode */
+ if (mode >= 8)
+ return (EINVAL);
+
+ /* set the mux mode */
+ reg_val |= (uint16_t)(mode & ti_scm_dev.padconf_muxmode_mask);
+
+ printf("setting internal %x for %s\n", reg_val, muxmode);
+ /* write the register value (16-bit writes) */
+ ti_scm_write_2(sc, padconf->reg_off, reg_val);
+
+ return (0);
+}
+
+/**
+ * ti_scm_padconf_set - sets the muxmode and state for a pad/pin
+ * @padname: the name of the pad, i.e. "c12"
+ * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
+{
+ const struct ti_scm_padconf *padconf;
+
+ if (!ti_scm_sc)
+ return (ENXIO);
+
+ /* find the pin in the devmap */
+ padconf = ti_scm_padconf_from_name(padname);
+ if (padconf == NULL)
+ return (EINVAL);
+
+ return (ti_scm_padconf_set_internal(ti_scm_sc, padconf, muxmode, state));
+}
+
+/**
+ * ti_scm_padconf_get - gets the muxmode and state for a pad/pin
+ * @padname: the name of the pad, i.e. "c12"
+ * @muxmode: upon return will contain the name of the muxmode of the pin
+ * @state: upon return will contain the state of the the pad/pin
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_get(const char *padname, const char **muxmode,
+ unsigned int *state)
+{
+ const struct ti_scm_padconf *padconf;
+ uint16_t reg_val;
+
+ if (!ti_scm_sc)
+ return (ENXIO);
+
+ /* find the pin in the devmap */
+ padconf = ti_scm_padconf_from_name(padname);
+ if (padconf == NULL)
+ return (EINVAL);
+
+ /* read the register value (16-bit reads) */
+ reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
+
+ /* save the state */
+ if (state)
+ *state = (reg_val & ti_scm_dev.padconf_sate_mask);
+
+ /* save the mode */
+ if (muxmode)
+ *muxmode = padconf->muxmodes[(reg_val & ti_scm_dev.padconf_muxmode_mask)];
+
+ return (0);
+}
+
+/**
+ * ti_scm_padconf_set_gpiomode - converts a pad to GPIO mode.
+ * @gpio: the GPIO pin number (0-195)
+ * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
+{
+ const struct ti_scm_padconf *padconf;
+ uint16_t reg_val;
+
+ if (!ti_scm_sc)
+ return (ENXIO);
+
+ /* find the gpio pin in the padconf array */
+ padconf = ti_scm_dev.padconf;
+ while (padconf->ballname != NULL) {
+ if (padconf->gpio_pin == gpio)
+ break;
+ padconf++;
+ }
+ if (padconf->ballname == NULL)
+ return (EINVAL);
+
+ /* populate the new value for the PADCONF register */
+ reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
+
+ /* set the mux mode */
+ reg_val |= (uint16_t)(padconf->gpio_mode & ti_scm_dev.padconf_muxmode_mask);
+
+ /* write the register value (16-bit writes) */
+ ti_scm_write_2(ti_scm_sc, padconf->reg_off, reg_val);
+
+ return (0);
+}
+
+/**
+ * ti_scm_padconf_get_gpiomode - gets the current GPIO mode of the pin
+ * @gpio: the GPIO pin number (0-195)
+ * @state: upon return will contain the state
+ *
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or not configured as GPIO.
+ */
+int
+ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
+{
+ const struct ti_scm_padconf *padconf;
+ uint16_t reg_val;
+
+ if (!ti_scm_sc)
+ return (ENXIO);
+
+ /* find the gpio pin in the padconf array */
+ padconf = ti_scm_dev.padconf;
+ while (padconf->ballname != NULL) {
+ if (padconf->gpio_pin == gpio)
+ break;
+ padconf++;
+ }
+ if (padconf->ballname == NULL)
+ return (EINVAL);
+
+ /* read the current register settings */
+ reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
+
+ /* check to make sure the pins is configured as GPIO in the first state */
+ if ((reg_val & ti_scm_dev.padconf_muxmode_mask) != padconf->gpio_mode)
+ return (EINVAL);
+
+ /* read and store the reset of the state, i.e. pull-up, pull-down, etc */
+ if (state)
+ *state = (reg_val & ti_scm_dev.padconf_sate_mask);
+
+ return (0);
+}
+
+/**
+ * ti_scm_padconf_init_from_hints - processes the hints for padconf
+ * @sc: the driver soft context
+ *
+ *
+ *
+ * LOCKING:
+ * Internally locks it's own context.
+ *
+ * RETURNS:
+ * 0 on success.
+ * EINVAL if pin requested is outside valid range or already in use.
+ */
+static int
+ti_scm_padconf_init_from_fdt(struct ti_scm_softc *sc)
+{
+ const struct ti_scm_padconf *padconf;
+ const struct ti_scm_padstate *padstates;
+ int err;
+ phandle_t node;
+ int len;
+ char *fdt_pad_config;
+ int i;
+ char *padname, *muxname, *padstate;
+
+ node = ofw_bus_get_node(sc->sc_dev);
+ len = OF_getproplen(node, "scm-pad-config");
+ OF_getprop_alloc(node, "scm-pad-config", 1, (void **)&fdt_pad_config);
+
+ i = len;
+ while (i > 0) {
+ padname = fdt_pad_config;
+ fdt_pad_config += strlen(padname) + 1;
+ i -= strlen(padname) + 1;
+ if (i <= 0)
+ break;
+
+ muxname = fdt_pad_config;
+ fdt_pad_config += strlen(muxname) + 1;
+ i -= strlen(muxname) + 1;
+ if (i <= 0)
+ break;
+
+ padstate = fdt_pad_config;
+ fdt_pad_config += strlen(padstate) + 1;
+ i -= strlen(padstate) + 1;
+ if (i < 0)
+ break;
+
+ padconf = ti_scm_dev.padconf;
+
+ while (padconf->ballname != NULL) {
+ if (strcmp(padconf->ballname, padname) == 0) {
+ padstates = ti_scm_dev.padstate;
+ err = 1;
+ while (padstates->state != NULL) {
+ if (strcmp(padstates->state, padstate) == 0) {
+ err = ti_scm_padconf_set_internal(sc,
+ padconf, muxname, padstates->reg);
+ }
+ padstates++;
+ }
+ if (err)
+ device_printf(sc->sc_dev, "err: failed to configure"
+ "pin \"%s\"\n", padconf->ballname);
+ }
+ padconf++;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Device part of OMAP SCM driver
+ */
+
+static int
+ti_scm_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,scm"))
+ return (ENXIO);
+
+ 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 sucess or ENXIO if an error occuried.
+ */
+static int
+ti_scm_attach(device_t dev)
+{
+ struct ti_scm_softc *sc = device_get_softc(dev);
+
+ if (ti_scm_sc)
+ return (ENXIO);
+
+ 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;
+
+ ti_scm_padconf_init_from_fdt(sc);
+
+ return (0);
+}
+
+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;
+
+DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0);
diff --git a/sys/arm/ti/ti_scm.h b/sys/arm/ti/ti_scm.h
new file mode 100644
index 0000000..a2b1194
--- /dev/null
+++ b/sys/arm/ti/ti_scm.h
@@ -0,0 +1,84 @@
+/*
+ * 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_padconf {
+ uint16_t reg_off;
+ uint16_t gpio_pin;
+ uint16_t gpio_mode;
+ const char *ballname;
+ const char *muxmodes[8];
+};
+
+struct ti_scm_padstate {
+ const char *state;
+ uint16_t reg;
+};
+
+struct ti_scm_device {
+ uint16_t padconf_muxmode_mask;
+ uint16_t padconf_sate_mask;
+ struct ti_scm_padstate *padstate;
+ struct ti_scm_padconf *padconf;
+};
+
+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_padconf_set(const char *padname, const char *muxmode,
+ unsigned int state);
+int ti_scm_padconf_get(const char *padname, const char **muxmode,
+ unsigned int *state);
+int ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state);
+int ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state);
+int ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags);
+void ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags);
+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/sys/arm/ti/ti_sdma.c b/sys/arm/ti/ti_sdma.c
new file mode 100644
index 0000000..4c55c41
--- /dev/null
+++ b/sys/arm/ti/ti_sdma.c
@@ -0,0 +1,1246 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/interrupt.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/timetc.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sdma.h>
+#include <arm/ti/ti_sdmareg.h>
+
+/**
+ * Kernel functions for using the DMA controller
+ *
+ *
+ * DMA TRANSFERS:
+ * A DMA transfer block consists of a number of frames (FN). Each frame
+ * consists of a number of elements, and each element can have a size of 8, 16,
+ * or 32 bits.
+ *
+ * OMAP44xx and newer chips support linked list (aka scatter gather) transfers,
+ * where a linked list of source/destination pairs can be placed in memory
+ * for the H/W to process. Earlier chips only allowed you to chain multiple
+ * channels together. However currently this linked list feature is not
+ * supported by the driver.
+ *
+ */
+
+/**
+ * Data structure per DMA channel.
+ *
+ *
+ */
+struct ti_sdma_channel {
+
+ /*
+ * The configuration registers for the given channel, these are modified
+ * by the set functions and only written to the actual registers when a
+ * transaction is started.
+ */
+ uint32_t reg_csdp;
+ uint32_t reg_ccr;
+ uint32_t reg_cicr;
+
+ /* Set when one of the configuration registers above change */
+ uint32_t need_reg_write;
+
+ /* Callback function used when an interrupt is tripped on the given channel */
+ void (*callback)(unsigned int ch, uint32_t ch_status, void *data);
+
+ /* Callback data passed in the callback ... duh */
+ void* callback_data;
+
+};
+
+/**
+ * DMA driver context, allocated and stored globally, this driver is not
+ * intetned to ever be unloaded (see ti_sdma_sc).
+ *
+ */
+struct ti_sdma_softc {
+ device_t sc_dev;
+ struct resource* sc_irq_res;
+ struct resource* sc_mem_res;
+
+ /*
+ * I guess in theory we should have a mutex per DMA channel for register
+ * modifications. But since we know we are never going to be run on a SMP
+ * system, we can use just the single lock for all channels.
+ */
+ struct mtx sc_mtx;
+
+ /* Stores the H/W revision read from the registers */
+ uint32_t sc_hw_rev;
+
+ /*
+ * Bits in the sc_active_channels data field indicate if the channel has
+ * been activated.
+ */
+ uint32_t sc_active_channels;
+
+ struct ti_sdma_channel sc_channel[NUM_DMA_CHANNELS];
+
+};
+
+static struct ti_sdma_softc *ti_sdma_sc = NULL;
+
+/**
+ * Macros for driver mutex locking
+ */
+#define TI_SDMA_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)
+#define TI_SDMA_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
+#define TI_SDMA_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "ti_sdma", MTX_SPIN)
+#define TI_SDMA_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define TI_SDMA_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_SDMA_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+/**
+ * Function prototypes
+ *
+ */
+static void ti_sdma_intr(void *);
+
+/**
+ * ti_sdma_read_4 - reads a 32-bit value from one of the DMA registers
+ * @sc: DMA device context
+ * @off: The offset of a register from the DMA register address range
+ *
+ *
+ * RETURNS:
+ * 32-bit value read from the register.
+ */
+static inline uint32_t
+ti_sdma_read_4(struct ti_sdma_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->sc_mem_res, off);
+}
+
+/**
+ * ti_sdma_write_4 - writes a 32-bit value to one of the DMA registers
+ * @sc: DMA device context
+ * @off: The offset of a register from the DMA register address range
+ *
+ *
+ * RETURNS:
+ * 32-bit value read from the register.
+ */
+static inline void
+ti_sdma_write_4(struct ti_sdma_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->sc_mem_res, off, val);
+}
+
+/**
+ * ti_sdma_is_omap3_rev - returns true if H/W is from OMAP3 series
+ * @sc: DMA device context
+ *
+ */
+static inline int
+ti_sdma_is_omap3_rev(struct ti_sdma_softc *sc)
+{
+ return (sc->sc_hw_rev == DMA4_OMAP3_REV);
+}
+
+/**
+ * ti_sdma_is_omap4_rev - returns true if H/W is from OMAP4 series
+ * @sc: DMA device context
+ *
+ */
+static inline int
+ti_sdma_is_omap4_rev(struct ti_sdma_softc *sc)
+{
+ return (sc->sc_hw_rev == DMA4_OMAP4_REV);
+}
+
+/**
+ * ti_sdma_intr - interrupt handler for all 4 DMA IRQs
+ * @arg: ignored
+ *
+ * Called when any of the four DMA IRQs are triggered.
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+ti_sdma_intr(void *arg)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t intr;
+ uint32_t csr;
+ unsigned int ch, j;
+ struct ti_sdma_channel* channel;
+
+ TI_SDMA_LOCK(sc);
+
+ for (j = 0; j < NUM_DMA_IRQS; j++) {
+
+ /* Get the flag interrupts (enabled) */
+ intr = ti_sdma_read_4(sc, DMA4_IRQSTATUS_L(j));
+ intr &= ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
+ if (intr == 0x00000000)
+ continue;
+
+ /* Loop through checking the status bits */
+ for (ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
+ if (intr & (1 << ch)) {
+ channel = &sc->sc_channel[ch];
+
+ /* Read the CSR regsiter and verify we don't have a spurious IRQ */
+ csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
+ if (csr == 0) {
+ device_printf(sc->sc_dev, "Spurious DMA IRQ for channel "
+ "%d\n", ch);
+ continue;
+ }
+
+ /* Sanity check this channel is active */
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ device_printf(sc->sc_dev, "IRQ %d for a non-activated "
+ "channel %d\n", j, ch);
+ continue;
+ }
+
+ /* Check the status error codes */
+ if (csr & DMA4_CSR_DROP)
+ device_printf(sc->sc_dev, "Synchronization event drop "
+ "occurred during the transfer on channel %u\n",
+ ch);
+ if (csr & DMA4_CSR_SECURE_ERR)
+ device_printf(sc->sc_dev, "Secure transaction error event "
+ "on channel %u\n", ch);
+ if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR)
+ device_printf(sc->sc_dev, "Misaligned address error event "
+ "on channel %u\n", ch);
+ if (csr & DMA4_CSR_TRANS_ERR) {
+ device_printf(sc->sc_dev, "Transaction error event on "
+ "channel %u\n", ch);
+ /*
+ * Apparently according to linux code, there is an errata
+ * that says the channel is not disabled upon this error.
+ * They explicitly disable the channel here .. since I
+ * haven't seen the errata, I'm going to ignore for now.
+ */
+ }
+
+ /* Clear the status flags for the IRQ */
+ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+ ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+
+ /* Call the callback for the given channel */
+ if (channel->callback)
+ channel->callback(ch, csr, channel->callback_data);
+ }
+ }
+ }
+
+ TI_SDMA_UNLOCK(sc);
+
+ return;
+}
+
+/**
+ * ti_sdma_activate_channel - activates a DMA channel
+ * @ch: upon return contains the channel allocated
+ * @callback: a callback function to associate with the channel
+ * @data: optional data supplied when the callback is called
+ *
+ * Simply activates a channel be enabling and writing default values to the
+ * channel's register set. It doesn't start a transaction, just populates the
+ * internal data structures and sets defaults.
+ *
+ * Note this function doesn't enable interrupts, for that you need to call
+ * ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the
+ * transfer, you can use ti_sdma_status_poll() to detect a change in the
+ * status.
+ *
+ * A channel must be activated before any of the other DMA functions can be
+ * called on it.
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * 0 on success, otherwise an error code
+ */
+int
+ti_sdma_activate_channel(unsigned int *ch,
+ void (*callback)(unsigned int ch, uint32_t status, void *data),
+ void *data)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ struct ti_sdma_channel *channel = NULL;
+ uint32_t addr;
+ unsigned int i;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ if (ch == NULL)
+ return (EINVAL);
+
+ TI_SDMA_LOCK(sc);
+
+ /* Check to see if all channels are in use */
+ if (sc->sc_active_channels == 0xffffffff) {
+ TI_SDMA_UNLOCK(sc);
+ return (ENOMEM);
+ }
+
+ /* Find the first non-active channel */
+ for (i = 0; i < NUM_DMA_CHANNELS; i++) {
+ if (!(sc->sc_active_channels & (0x1 << i))) {
+ sc->sc_active_channels |= (0x1 << i);
+ *ch = i;
+ break;
+ }
+ }
+
+ /* Get the channel struct and populate the fields */
+ channel = &sc->sc_channel[*ch];
+
+ channel->callback = callback;
+ channel->callback_data = data;
+
+ channel->need_reg_write = 1;
+
+ /* Set the default configuration for the DMA channel */
+ channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2)
+ | DMA4_CSDP_SRC_BURST_MODE(0)
+ | DMA4_CSDP_DST_BURST_MODE(0)
+ | DMA4_CSDP_SRC_ENDIANISM(0)
+ | DMA4_CSDP_DST_ENDIANISM(0)
+ | DMA4_CSDP_WRITE_MODE(0)
+ | DMA4_CSDP_SRC_PACKED(0)
+ | DMA4_CSDP_DST_PACKED(0);
+
+ channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1)
+ | DMA4_CCR_SRC_ADDRESS_MODE(1)
+ | DMA4_CCR_READ_PRIORITY(0)
+ | DMA4_CCR_WRITE_PRIORITY(0)
+ | DMA4_CCR_SYNC_TRIGGER(0)
+ | DMA4_CCR_FRAME_SYNC(0)
+ | DMA4_CCR_BLOCK_SYNC(0);
+
+ channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE
+ | DMA4_CICR_SECURE_ERR_IE
+ | DMA4_CICR_SUPERVISOR_ERR_IE
+ | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
+
+ /* Clear all the channel registers, this should abort any transaction */
+ for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4)
+ ti_sdma_write_4(sc, addr, 0x00000000);
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_deactivate_channel - deactivates a channel
+ * @ch: the channel to deactivate
+ *
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_deactivate_channel(unsigned int ch)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ unsigned int j;
+ unsigned int addr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ /* First check if the channel is currently active */
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EBUSY);
+ }
+
+ /* Mark the channel as inactive */
+ sc->sc_active_channels &= ~(1 << ch);
+
+ /* Disable all DMA interrupts for the channel. */
+ ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
+
+ /* Make sure the DMA transfer is stopped. */
+ ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
+
+ /* Clear the CSR register and IRQ status register */
+ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+ for (j = 0; j < NUM_DMA_IRQS; j++) {
+ ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+ }
+
+ /* Clear all the channel registers, this should abort any transaction */
+ for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4)
+ ti_sdma_write_4(sc, addr, 0x00000000);
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_disable_channel_irq - disables IRQ's on the given channel
+ * @ch: the channel to disable IRQ's on
+ *
+ * Disable interupt generation for the given channel.
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_disable_channel_irq(unsigned int ch)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t irq_enable;
+ unsigned int j;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Disable all the individual error conditions */
+ sc->sc_channel[ch].reg_cicr = 0x0000;
+ ti_sdma_write_4(sc, DMA4_CICR(ch), 0x0000);
+
+ /* Disable the channel interrupt enable */
+ for (j = 0; j < NUM_DMA_IRQS; j++) {
+ irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
+ irq_enable &= ~(1 << ch);
+
+ ti_sdma_write_4(sc, DMA4_IRQENABLE_L(j), irq_enable);
+ }
+
+ /* Indicate the registers need to be rewritten on the next transaction */
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_sdma_disable_channel_irq - enables IRQ's on the given channel
+ * @ch: the channel to enable IRQ's on
+ * @flags: bitmask of interrupt types to enable
+ *
+ * Flags can be a bitmask of the following options:
+ * DMA_IRQ_FLAG_DROP
+ * DMA_IRQ_FLAG_HALF_FRAME_COMPL
+ * DMA_IRQ_FLAG_FRAME_COMPL
+ * DMA_IRQ_FLAG_START_LAST_FRAME
+ * DMA_IRQ_FLAG_BLOCK_COMPL
+ * DMA_IRQ_FLAG_ENDOF_PKT
+ * DMA_IRQ_FLAG_DRAIN
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t irq_enable;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Always enable the error interrupts if we have interrupts enabled */
+ flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE |
+ DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
+
+ sc->sc_channel[ch].reg_cicr = flags;
+
+ /* Write the values to the register */
+ ti_sdma_write_4(sc, DMA4_CICR(ch), flags);
+
+ /* Enable the channel interrupt enable */
+ irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(0));
+ irq_enable |= (1 << ch);
+
+ ti_sdma_write_4(sc, DMA4_IRQENABLE_L(0), irq_enable);
+
+ /* Indicate the registers need to be rewritten on the next transaction */
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_sdma_get_channel_status - returns the status of a given channel
+ * @ch: the channel number to get the status of
+ * @status: upon return will contain the status bitmask, see below for possible
+ * values.
+ *
+ * DMA_STATUS_DROP
+ * DMA_STATUS_HALF
+ * DMA_STATUS_FRAME
+ * DMA_STATUS_LAST
+ * DMA_STATUS_BLOCK
+ * DMA_STATUS_SYNC
+ * DMA_STATUS_PKT
+ * DMA_STATUS_TRANS_ERR
+ * DMA_STATUS_SECURE_ERR
+ * DMA_STATUS_SUPERVISOR_ERR
+ * DMA_STATUS_MISALIGNED_ADRS_ERR
+ * DMA_STATUS_DRAIN_END
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_get_channel_status(unsigned int ch, uint32_t *status)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t csr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ TI_SDMA_UNLOCK(sc);
+
+ csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
+
+ if (status != NULL)
+ *status = csr;
+
+ return (0);
+}
+
+/**
+ * ti_sdma_start_xfer - starts a DMA transfer
+ * @ch: the channel number to set the endianess of
+ * @src_paddr: the source phsyical address
+ * @dst_paddr: the destination phsyical address
+ * @frmcnt: the number of frames per block
+ * @elmcnt: the number of elements in a frame, an element is either an 8, 16
+ * or 32-bit value as defined by ti_sdma_set_xfer_burst()
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
+ unsigned long dst_paddr,
+ unsigned int frmcnt, unsigned int elmcnt)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ struct ti_sdma_channel *channel;
+ uint32_t ccr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ channel = &sc->sc_channel[ch];
+
+ /* a) Write the CSDP register */
+ ti_sdma_write_4(sc, DMA4_CSDP(ch),
+ channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
+
+ /* b) Set the number of element per frame CEN[23:0] */
+ ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
+
+ /* c) Set the number of frame per block CFN[15:0] */
+ ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
+
+ /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
+ ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
+ ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
+
+ /* e) Write the CCR register */
+ ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr);
+
+ /* f) - Set the source element index increment CSEI[15:0] */
+ ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
+
+ /* - Set the source frame index increment CSFI[15:0] */
+ ti_sdma_write_4(sc, DMA4_CSF(ch), 0x0001);
+
+ /* - Set the destination element index increment CDEI[15:0]*/
+ ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
+
+ /* - Set the destination frame index increment CDFI[31:0] */
+ ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001);
+
+ /* Clear the status register */
+ ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
+
+ /* Write the start-bit and away we go */
+ ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
+ ccr |= (1 << 7);
+ ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
+
+ /* Clear the reg write flag */
+ channel->need_reg_write = 0;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_sdma_start_xfer_packet - starts a packet DMA transfer
+ * @ch: the channel number to use for the transfer
+ * @src_paddr: the source physical address
+ * @dst_paddr: the destination physical address
+ * @frmcnt: the number of frames to transfer
+ * @elmcnt: the number of elements in a frame, an element is either an 8, 16
+ * or 32-bit value as defined by ti_sdma_set_xfer_burst()
+ * @pktsize: the number of elements in each transfer packet
+ *
+ * The @frmcnt and @elmcnt define the overall number of bytes to transfer,
+ * typically @frmcnt is 1 and @elmcnt contains the total number of elements.
+ * @pktsize is the size of each individual packet, there might be multiple
+ * packets per transfer. i.e. for the following with element size of 32-bits
+ *
+ * frmcnt = 1, elmcnt = 512, pktsize = 128
+ *
+ * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes
+ * Packets transfered = 128 / 512 = 4
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
+ unsigned long dst_paddr, unsigned int frmcnt,
+ unsigned int elmcnt, unsigned int pktsize)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ struct ti_sdma_channel *channel;
+ uint32_t ccr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ channel = &sc->sc_channel[ch];
+
+ /* a) Write the CSDP register */
+ if (channel->need_reg_write)
+ ti_sdma_write_4(sc, DMA4_CSDP(ch),
+ channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
+
+ /* b) Set the number of elements to transfer CEN[23:0] */
+ ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
+
+ /* c) Set the number of frames to transfer CFN[15:0] */
+ ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
+
+ /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
+ ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
+ ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
+
+ /* e) Write the CCR register */
+ ti_sdma_write_4(sc, DMA4_CCR(ch),
+ channel->reg_ccr | DMA4_CCR_PACKET_TRANS);
+
+ /* f) - Set the source element index increment CSEI[15:0] */
+ ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
+
+ /* - Set the packet size, this is dependent on the sync source */
+ if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1))
+ ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize);
+ else
+ ti_sdma_write_4(sc, DMA4_CDF(ch), pktsize);
+
+ /* - Set the destination frame index increment CDFI[31:0] */
+ ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
+
+ /* Clear the status register */
+ ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
+
+ /* Write the start-bit and away we go */
+ ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
+ ccr |= (1 << 7);
+ ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
+
+ /* Clear the reg write flag */
+ channel->need_reg_write = 0;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_sdma_stop_xfer - stops any currently active transfers
+ * @ch: the channel number to set the endianess of
+ *
+ * This function call is effectively a NOP if no transaction is in progress.
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_stop_xfer(unsigned int ch)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ unsigned int j;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ /* Disable all DMA interrupts for the channel. */
+ ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
+
+ /* Make sure the DMA transfer is stopped. */
+ ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
+
+ /* Clear the CSR register and IRQ status register */
+ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+ for (j = 0; j < NUM_DMA_IRQS; j++) {
+ ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+ }
+
+ /* Configuration registers need to be re-written on the next xfer */
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return (0);
+}
+
+/**
+ * ti_sdma_set_xfer_endianess - sets the endianess of subsequent transfers
+ * @ch: the channel number to set the endianess of
+ * @src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
+ * @dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1);
+ sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src);
+
+ sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1);
+ sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst);
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_set_xfer_burst - sets the source and destination element size
+ * @ch: the channel number to set the burst settings of
+ * @src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32
+ * or DMA_BURST_64)
+ * @dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16,
+ * DMA_BURST_32 or DMA_BURST_64)
+ *
+ * This function sets the size of the elements for all subsequent transfers.
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3);
+ sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src);
+
+ sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3);
+ sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst);
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_set_xfer_data_type - driver attach function
+ * @ch: the channel number to set the endianess of
+ * @type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR
+ * or DMA_DATA_32BITS_SCALAR)
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3);
+ sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type);
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_set_callback - driver attach function
+ * @dev: dma device handle
+ *
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_callback(unsigned int ch,
+ void (*callback)(unsigned int ch, uint32_t status, void *data),
+ void *data)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ sc->sc_channel[ch].callback = callback;
+ sc->sc_channel[ch].callback_data = data;
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_sync_params - sets channel sync settings
+ * @ch: the channel number to set the sync on
+ * @trigger: the number of the sync trigger, this depends on what other H/W
+ * module is triggering/receiving the DMA transactions
+ * @mode: flags describing the sync mode to use, it may have one or more of
+ * the following bits set; TI_SDMA_SYNC_FRAME,
+ * TI_SDMA_SYNC_BLOCK, TI_SDMA_SYNC_TRIG_ON_SRC.
+ *
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t ccr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ ccr = sc->sc_channel[ch].reg_ccr;
+
+ ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F);
+ ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1);
+
+ if (mode & TI_SDMA_SYNC_FRAME)
+ ccr |= DMA4_CCR_FRAME_SYNC(1);
+ else
+ ccr &= ~DMA4_CCR_FRAME_SYNC(1);
+
+ if (mode & TI_SDMA_SYNC_BLOCK)
+ ccr |= DMA4_CCR_BLOCK_SYNC(1);
+ else
+ ccr &= ~DMA4_CCR_BLOCK_SYNC(1);
+
+ if (mode & TI_SDMA_SYNC_TRIG_ON_SRC)
+ ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1);
+ else
+ ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1);
+
+ sc->sc_channel[ch].reg_ccr = ccr;
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_set_addr_mode - driver attach function
+ * @ch: the channel number to set the endianess of
+ * @rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT,
+ * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
+ * DMA_ADDR_DOUBLE_INDEX)
+ * @wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT,
+ * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
+ * DMA_ADDR_DOUBLE_INDEX)
+ *
+ *
+ * LOCKING:
+ * DMA registers protected by internal mutex
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode,
+ unsigned int dst_mode)
+{
+ struct ti_sdma_softc *sc = ti_sdma_sc;
+ uint32_t ccr;
+
+ /* Sanity check */
+ if (sc == NULL)
+ return (ENOMEM);
+
+ TI_SDMA_LOCK(sc);
+
+ if ((sc->sc_active_channels & (1 << ch)) == 0) {
+ TI_SDMA_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ ccr = sc->sc_channel[ch].reg_ccr;
+
+ ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3);
+ ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode);
+
+ ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3);
+ ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode);
+
+ sc->sc_channel[ch].reg_ccr = ccr;
+
+ sc->sc_channel[ch].need_reg_write = 1;
+
+ TI_SDMA_UNLOCK(sc);
+
+ return 0;
+}
+
+/**
+ * ti_sdma_probe - driver probe function
+ * @dev: dma device handle
+ *
+ *
+ *
+ * RETURNS:
+ * Always returns 0.
+ */
+static int
+ti_sdma_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,sdma"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI sDMA Controller");
+ return (0);
+}
+
+/**
+ * ti_sdma_attach - driver attach function
+ * @dev: dma device handle
+ *
+ * Initialises memory mapping/pointers to the DMA register set and requests
+ * IRQs. This is effectively the setup function for the driver.
+ *
+ * RETURNS:
+ * 0 on success or a negative error code failure.
+ */
+static int
+ti_sdma_attach(device_t dev)
+{
+ struct ti_sdma_softc *sc = device_get_softc(dev);
+ unsigned int timeout;
+ unsigned int i;
+ int rid;
+ void *ihl;
+ int err;
+
+ /* Setup the basics */
+ sc->sc_dev = dev;
+
+ /* No channels active at the moment */
+ sc->sc_active_channels = 0x00000000;
+
+ /* Mutex to protect the shared data structures */
+ TI_SDMA_LOCK_INIT(sc);
+
+ /* Get the memory resource for the register mapping */
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->sc_mem_res == NULL)
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ /* Enable the interface and functional clocks */
+ ti_prcm_clk_enable(SDMA_CLK);
+
+ /* Read the sDMA revision register and sanity check it's known */
+ sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION);
+ device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev);
+
+ if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) {
+ device_printf(sc->sc_dev, "error - unknown sDMA H/W revision\n");
+ return (EINVAL);
+ }
+
+ /* Disable all interrupts */
+ for (i = 0; i < NUM_DMA_IRQS; i++) {
+ ti_sdma_write_4(sc, DMA4_IRQENABLE_L(i), 0x00000000);
+ }
+
+ /* Soft-reset is only supported on pre-OMAP44xx devices */
+ if (ti_sdma_is_omap3_rev(sc)) {
+
+ /* Soft-reset */
+ ti_sdma_write_4(sc, DMA4_OCP_SYSCONFIG, 0x0002);
+
+ /* Set the timeout to 100ms*/
+ timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+
+ /* Wait for DMA reset to complete */
+ while ((ti_sdma_read_4(sc, DMA4_SYSSTATUS) & 0x1) == 0x0) {
+
+ /* Sleep for a tick */
+ pause("DMARESET", 1);
+
+ if (timeout-- == 0) {
+ device_printf(sc->sc_dev, "sDMA reset operation timed out\n");
+ return (EINVAL);
+ }
+ }
+ }
+
+ /*
+ * Install interrupt handlers for the for possible interrupts. Any channel
+ * can trip one of the four IRQs
+ */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_irq_res == NULL)
+ panic("Unable to setup the dma irq handler.\n");
+
+ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, ti_sdma_intr, NULL, &ihl);
+ if (err)
+ panic("%s: Cannot register IRQ", device_get_name(dev));
+
+ /* Store the DMA structure globally ... this driver should never be unloaded */
+ ti_sdma_sc = sc;
+
+ return (0);
+}
+
+static device_method_t ti_sdma_methods[] = {
+ DEVMETHOD(device_probe, ti_sdma_probe),
+ DEVMETHOD(device_attach, ti_sdma_attach),
+ {0, 0},
+};
+
+static driver_t ti_sdma_driver = {
+ "ti_sdma",
+ ti_sdma_methods,
+ sizeof(struct ti_sdma_softc),
+};
+static devclass_t ti_sdma_devclass;
+
+DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0);
+MODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1);
diff --git a/sys/arm/ti/ti_sdma.h b/sys/arm/ti/ti_sdma.h
new file mode 100644
index 0000000..2d7e626
--- /dev/null
+++ b/sys/arm/ti/ti_sdma.h
@@ -0,0 +1,111 @@
+/*-
+ * 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$
+ */
+
+/**
+ * sDMA device driver interface for the TI SoC
+ *
+ * See the ti_sdma.c file for implementation details.
+ *
+ * Reference:
+ * OMAP35x Applications Processor
+ * Technical Reference Manual
+ * (omap35xx_techref.pdf)
+ */
+#ifndef _TI_DMA_H_
+#define _TI_DMA_H_
+
+#define TI_SDMA_ENDIAN_BIG 0x1
+#define TI_SDMA_ENDIAN_LITTLE 0x0
+
+#define TI_SDMA_BURST_NONE 0x0
+#define TI_SDMA_BURST_16 0x1
+#define TI_SDMA_BURST_32 0x2
+#define TI_SDMA_BURST_64 0x3
+
+#define TI_SDMA_DATA_8BITS_SCALAR 0x0
+#define TI_SDMA_DATA_16BITS_SCALAR 0x1
+#define TI_SDMA_DATA_32BITS_SCALAR 0x2
+
+#define TI_SDMA_ADDR_CONSTANT 0x0
+#define TI_SDMA_ADDR_POST_INCREMENT 0x1
+#define TI_SDMA_ADDR_SINGLE_INDEX 0x2
+#define TI_SDMA_ADDR_DOUBLE_INDEX 0x3
+
+/**
+ * Status flags for the DMA callback
+ *
+ */
+#define TI_SDMA_STATUS_DROP (1UL << 1)
+#define TI_SDMA_STATUS_HALF (1UL << 2)
+#define TI_SDMA_STATUS_FRAME (1UL << 3)
+#define TI_SDMA_STATUS_LAST (1UL << 4)
+#define TI_SDMA_STATUS_BLOCK (1UL << 5)
+#define TI_SDMA_STATUS_SYNC (1UL << 6)
+#define TI_SDMA_STATUS_PKT (1UL << 7)
+#define TI_SDMA_STATUS_TRANS_ERR (1UL << 8)
+#define TI_SDMA_STATUS_SECURE_ERR (1UL << 9)
+#define TI_SDMA_STATUS_SUPERVISOR_ERR (1UL << 10)
+#define TI_SDMA_STATUS_MISALIGNED_ADRS_ERR (1UL << 11)
+#define TI_SDMA_STATUS_DRAIN_END (1UL << 12)
+
+#define TI_SDMA_SYNC_FRAME (1UL << 0)
+#define TI_SDMA_SYNC_BLOCK (1UL << 1)
+#define TI_SDMA_SYNC_PACKET (TI_SDMA_SYNC_FRAME | TI_SDMA_SYNC_BLOCK)
+#define TI_SDMA_SYNC_TRIG_ON_SRC (1UL << 8)
+#define TI_SDMA_SYNC_TRIG_ON_DST (1UL << 9)
+
+#define TI_SDMA_IRQ_FLAG_DROP (1UL << 1)
+#define TI_SDMA_IRQ_FLAG_HALF_FRAME_COMPL (1UL << 2)
+#define TI_SDMA_IRQ_FLAG_FRAME_COMPL (1UL << 3)
+#define TI_SDMA_IRQ_FLAG_START_LAST_FRAME (1UL << 4)
+#define TI_SDMA_IRQ_FLAG_BLOCK_COMPL (1UL << 5)
+#define TI_SDMA_IRQ_FLAG_ENDOF_PKT (1UL << 7)
+#define TI_SDMA_IRQ_FLAG_DRAIN (1UL << 12)
+
+int ti_sdma_activate_channel(unsigned int *ch,
+ void (*callback)(unsigned int ch, uint32_t status, void *data), void *data);
+int ti_sdma_deactivate_channel(unsigned int ch);
+int ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
+ unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt);
+int ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
+ unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt,
+ unsigned int pktsize);
+int ti_sdma_stop_xfer(unsigned int ch);
+int ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags);
+int ti_sdma_disable_channel_irq(unsigned int ch);
+int ti_sdma_get_channel_status(unsigned int ch, uint32_t *status);
+int ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst);
+int ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst);
+int ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type);
+int ti_sdma_set_callback(unsigned int ch,
+ void (*callback)(unsigned int ch, uint32_t status, void *data), void *data);
+int ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode);
+int ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode, unsigned int dst_mode);
+
+#endif /* _TI_SDMA_H_ */
diff --git a/sys/arm/ti/ti_sdmareg.h b/sys/arm/ti/ti_sdmareg.h
new file mode 100644
index 0000000..c19af12
--- /dev/null
+++ b/sys/arm/ti/ti_sdmareg.h
@@ -0,0 +1,133 @@
+/*-
+ * 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_SDMAREG_H__
+#define __TI_SDMAREG_H__
+
+/**
+ * The number of DMA channels possible on the controller.
+ */
+#define NUM_DMA_CHANNELS 32
+#define NUM_DMA_IRQS 4
+
+/**
+ * Register offsets
+ */
+#define DMA4_REVISION 0x0000
+#define DMA4_IRQSTATUS_L(j) (0x0008 + ((j) * 0x4))
+#define DMA4_IRQENABLE_L(j) (0x0018 + ((j) * 0x4))
+#define DMA4_SYSSTATUS 0x0028
+#define DMA4_OCP_SYSCONFIG 0x002C
+#define DMA4_CAPS_0 0x0064
+#define DMA4_CAPS_2 0x006C
+#define DMA4_CAPS_3 0x0070
+#define DMA4_CAPS_4 0x0074
+#define DMA4_GCR 0x0078
+#define DMA4_CCR(i) (0x0080 + ((i) * 0x60))
+#define DMA4_CLNK_CTRL(i) (0x0084 + ((i) * 0x60))
+#define DMA4_CICR(i) (0x0088 + ((i) * 0x60))
+#define DMA4_CSR(i) (0x008C + ((i) * 0x60))
+#define DMA4_CSDP(i) (0x0090 + ((i) * 0x60))
+#define DMA4_CEN(i) (0x0094 + ((i) * 0x60))
+#define DMA4_CFN(i) (0x0098 + ((i) * 0x60))
+#define DMA4_CSSA(i) (0x009C + ((i) * 0x60))
+#define DMA4_CDSA(i) (0x00A0 + ((i) * 0x60))
+#define DMA4_CSE(i) (0x00A4 + ((i) * 0x60))
+#define DMA4_CSF(i) (0x00A8 + ((i) * 0x60))
+#define DMA4_CDE(i) (0x00AC + ((i) * 0x60))
+#define DMA4_CDF(i) (0x00B0 + ((i) * 0x60))
+#define DMA4_CSAC(i) (0x00B4 + ((i) * 0x60))
+#define DMA4_CDAC(i) (0x00B8 + ((i) * 0x60))
+#define DMA4_CCEN(i) (0x00BC + ((i) * 0x60))
+#define DMA4_CCFN(i) (0x00C0 + ((i) * 0x60))
+#define DMA4_COLOR(i) (0x00C4 + ((i) * 0x60))
+
+/* The following register are only defined on OMAP44xx (and newer?) */
+#define DMA4_CDP(i) (0x00D0 + ((i) * 0x60))
+#define DMA4_CNDP(i) (0x00D4 + ((i) * 0x60))
+#define DMA4_CCDN(i) (0x00D8 + ((i) * 0x60))
+
+/**
+ * Various register field settings
+ */
+#define DMA4_CSDP_DATA_TYPE(x) (((x) & 0x3) << 0)
+#define DMA4_CSDP_SRC_BURST_MODE(x) (((x) & 0x3) << 7)
+#define DMA4_CSDP_DST_BURST_MODE(x) (((x) & 0x3) << 14)
+#define DMA4_CSDP_SRC_ENDIANISM(x) (((x) & 0x1) << 21)
+#define DMA4_CSDP_DST_ENDIANISM(x) (((x) & 0x1) << 19)
+#define DMA4_CSDP_WRITE_MODE(x) (((x) & 0x3) << 16)
+#define DMA4_CSDP_SRC_PACKED(x) (((x) & 0x1) << 6)
+#define DMA4_CSDP_DST_PACKED(x) (((x) & 0x1) << 13)
+
+#define DMA4_CCR_DST_ADDRESS_MODE(x) (((x) & 0x3) << 14)
+#define DMA4_CCR_SRC_ADDRESS_MODE(x) (((x) & 0x3) << 12)
+#define DMA4_CCR_READ_PRIORITY(x) (((x) & 0x1) << 6)
+#define DMA4_CCR_WRITE_PRIORITY(x) (((x) & 0x1) << 26)
+#define DMA4_CCR_SYNC_TRIGGER(x) ((((x) & 0x60) << 14) \
+ | ((x) & 0x1f))
+#define DMA4_CCR_FRAME_SYNC(x) (((x) & 0x1) << 5)
+#define DMA4_CCR_BLOCK_SYNC(x) (((x) & 0x1) << 18)
+#define DMA4_CCR_SEL_SRC_DST_SYNC(x) (((x) & 0x1) << 24)
+
+#define DMA4_CCR_PACKET_TRANS (DMA4_CCR_FRAME_SYNC(1) | \
+ DMA4_CCR_BLOCK_SYNC(1) )
+
+#define DMA4_CSR_DROP (1UL << 1)
+#define DMA4_CSR_HALF (1UL << 2)
+#define DMA4_CSR_FRAME (1UL << 3)
+#define DMA4_CSR_LAST (1UL << 4)
+#define DMA4_CSR_BLOCK (1UL << 5)
+#define DMA4_CSR_SYNC (1UL << 6)
+#define DMA4_CSR_PKT (1UL << 7)
+#define DMA4_CSR_TRANS_ERR (1UL << 8)
+#define DMA4_CSR_SECURE_ERR (1UL << 9)
+#define DMA4_CSR_SUPERVISOR_ERR (1UL << 10)
+#define DMA4_CSR_MISALIGNED_ADRS_ERR (1UL << 11)
+#define DMA4_CSR_DRAIN_END (1UL << 12)
+#define DMA4_CSR_CLEAR_MASK (0xffe)
+
+#define DMA4_CICR_DROP_IE (1UL << 1)
+#define DMA4_CICR_HALF_IE (1UL << 2)
+#define DMA4_CICR_FRAME_IE (1UL << 3)
+#define DMA4_CICR_LAST_IE (1UL << 4)
+#define DMA4_CICR_BLOCK_IE (1UL << 5)
+#define DMA4_CICR_PKT_IE (1UL << 7)
+#define DMA4_CICR_TRANS_ERR_IE (1UL << 8)
+#define DMA4_CICR_SECURE_ERR_IE (1UL << 9)
+#define DMA4_CICR_SUPERVISOR_ERR_IE (1UL << 10)
+#define DMA4_CICR_MISALIGNED_ADRS_ERR_IE (1UL << 11)
+#define DMA4_CICR_DRAIN_IE (1UL << 12)
+
+/**
+ * The following H/W revision values were found be experimentation, TI don't
+ * publish the revision numbers. The TRM says "TI internal Data".
+ */
+#define DMA4_OMAP3_REV 0x00000040
+#define DMA4_OMAP4_REV 0x00010900
+
+#endif /* __TI_SDMAREG_H__ */
diff --git a/sys/arm/ti/ti_smc.S b/sys/arm/ti/ti_smc.S
new file mode 100644
index 0000000..c74f4e7
--- /dev/null
+++ b/sys/arm/ti/ti_smc.S
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard. 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.
+ */
+
+#include <machine/armreg.h>
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/* Issue a smc #0 call */
+/* r0 and r1 contains the eventual arguments, r2 contains the function ID */
+ENTRY(ti_smc0)
+ stmfd sp!, {r4-r12, lr}
+ mov r12, r2 /* the rom expects the function ID in r12 */
+ dsb
+ smc #0
+ ldmfd sp!, {r4-r12, pc}
+
diff --git a/sys/arm/ti/ti_smc.h b/sys/arm/ti/ti_smc.h
new file mode 100644
index 0000000..7fae8ab
--- /dev/null
+++ b/sys/arm/ti/ti_smc.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard. 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 TI_SMC_H_
+#define TI_SMC_H_
+uint32_t ti_smc0(uint32_t r0, uint32_t r1, uint32_t function_id);
+#endif /* TI_SMC_H_ */
diff --git a/sys/arm/ti/tivar.h b/sys/arm/ti/tivar.h
new file mode 100644
index 0000000..248ad90
--- /dev/null
+++ b/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_ */
diff --git a/sys/arm/ti/twl/twl.c b/sys/arm/ti/twl/twl.c
new file mode 100644
index 0000000..8edaf2f
--- /dev/null
+++ b/sys/arm/ti/twl/twl.c
@@ -0,0 +1,464 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management and
+ * Audio CODEC devices.
+ *
+ * This code is based on the Linux TWL multifunctional device driver, which is
+ * copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * These chips are typically used as support ICs for the OMAP range of embedded
+ * ARM processes/SOC from Texas Instruments. They are typically used to control
+ * on board voltages, however some variants have other features like audio
+ * codecs, USB OTG transceivers, RTC, PWM, etc.
+ *
+ * This driver acts as a bus for more specific companion devices.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "arm/ti/twl/twl.h"
+
+/* TWL device IDs */
+#define TWL_DEVICE_UNKNOWN 0xffff
+#define TWL_DEVICE_4030 0x4030
+#define TWL_DEVICE_6025 0x6025
+#define TWL_DEVICE_6030 0x6030
+
+/* Each TWL device typically has more than one I2C address */
+#define TWL_MAX_SUBADDRS 4
+
+/* The maxium number of bytes that can be written in one call */
+#define TWL_MAX_IIC_DATA_SIZE 63
+
+/* The TWL devices typically use 4 I2C address for the different internal
+ * register sets, plus one SmartReflex I2C address.
+ */
+#define TWL_CHIP_ID0 0x48
+#define TWL_CHIP_ID1 0x49
+#define TWL_CHIP_ID2 0x4A
+#define TWL_CHIP_ID3 0x4B
+
+#define TWL_SMARTREFLEX_CHIP_ID 0x12
+
+#define TWL_INVALID_CHIP_ID 0xff
+
+struct twl_softc {
+ device_t sc_dev;
+ struct mtx sc_mtx;
+ unsigned int sc_type;
+
+ uint8_t sc_subaddr_map[TWL_MAX_SUBADDRS];
+
+ struct intr_config_hook sc_scan_hook;
+
+ device_t sc_vreg;
+ device_t sc_clks;
+};
+
+/**
+ * Macros for driver mutex locking
+ */
+#define TWL_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define TWL_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define TWL_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "twl", MTX_DEF)
+#define TWL_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define TWL_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TWL_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+
+/**
+ * twl_is_4030 - returns true if the device is TWL4030
+ * twl_is_6025 - returns true if the device is TWL6025
+ * twl_is_6030 - returns true if the device is TWL6030
+ * @sc: device soft context
+ *
+ * Returns a non-zero value if the device matches.
+ *
+ * RETURNS:
+ * Returns a non-zero value if the device matches, otherwise zero.
+ */
+int
+twl_is_4030(device_t dev)
+{
+ struct twl_softc *sc = device_get_softc(dev);
+ return (sc->sc_type == TWL_DEVICE_4030);
+}
+
+int
+twl_is_6025(device_t dev)
+{
+ struct twl_softc *sc = device_get_softc(dev);
+ return (sc->sc_type == TWL_DEVICE_6025);
+}
+
+int
+twl_is_6030(device_t dev)
+{
+ struct twl_softc *sc = device_get_softc(dev);
+ return (sc->sc_type == TWL_DEVICE_6030);
+}
+
+
+/**
+ * twl_read - read one or more registers from the TWL device
+ * @sc: device soft context
+ * @nsub: the sub-module to read from
+ * @reg: the register offset within the module to read
+ * @buf: buffer to store the bytes in
+ * @cnt: the number of bytes to read
+ *
+ * Reads one or more registers and stores the result in the suppled buffer.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+int
+twl_read(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt)
+{
+ struct twl_softc *sc;
+ struct iic_msg msg[2];
+ uint8_t addr;
+ int rc;
+
+ sc = device_get_softc(dev);
+
+ TWL_LOCK(sc);
+ addr = sc->sc_subaddr_map[nsub];
+ TWL_UNLOCK(sc);
+
+ if (addr == TWL_INVALID_CHIP_ID)
+ return (EIO);
+
+
+ /* Set the address to read from */
+ msg[0].slave = addr;
+ msg[0].flags = IIC_M_WR | IIC_M_NOSTOP;
+ msg[0].len = 1;
+ msg[0].buf = &reg;
+ /* Read the data back */
+ msg[1].slave = addr;
+ msg[1].flags = IIC_M_RD;
+ msg[1].len = cnt;
+ msg[1].buf = buf;
+
+ rc = iicbus_transfer(dev, msg, 2);
+ if (rc != 0) {
+ device_printf(dev, "iicbus read failed (adr:0x%02x, reg:0x%02x)\n",
+ addr, reg);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+/**
+ * twl_write - writes one or more registers to the TWL device
+ * @sc: device soft context
+ * @nsub: the sub-module to read from
+ * @reg: the register offset within the module to read
+ * @buf: data to write
+ * @cnt: the number of bytes to write
+ *
+ * Writes one or more registers.
+ *
+ * RETURNS:
+ * Zero on success or a negative error code on failure.
+ */
+int
+twl_write(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt)
+{
+ struct twl_softc *sc;
+ struct iic_msg msg;
+ uint8_t addr;
+ uint8_t tmp_buf[TWL_MAX_IIC_DATA_SIZE + 1];
+ int rc;
+
+ if (cnt > TWL_MAX_IIC_DATA_SIZE)
+ return (ENOMEM);
+
+ /* Set the register address as the first byte */
+ tmp_buf[0] = reg;
+ memcpy(&tmp_buf[1], buf, cnt);
+
+ sc = device_get_softc(dev);
+
+ TWL_LOCK(sc);
+ addr = sc->sc_subaddr_map[nsub];
+ TWL_UNLOCK(sc);
+
+ if (addr == TWL_INVALID_CHIP_ID)
+ return (EIO);
+
+
+ /* Setup the transfer and execute it */
+ msg.slave = addr;
+ msg.flags = IIC_M_WR;
+ msg.len = cnt + 1;
+ msg.buf = tmp_buf;
+
+ rc = iicbus_transfer(dev, &msg, 1);
+ if (rc != 0) {
+ device_printf(sc->sc_dev, "iicbus write failed (adr:0x%02x, reg:0x%02x)\n",
+ addr, reg);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+/**
+ * twl_test_present - checks if a device with given address is present
+ * @sc: device soft context
+ * @addr: the address of the device to scan for
+ *
+ * Sends just the address byte and checks for an ACK. If no ACK then device
+ * is assumed to not be present.
+ *
+ * RETURNS:
+ * EIO if device is not present, otherwise 0 is returned.
+ */
+static int
+twl_test_present(struct twl_softc *sc, uint8_t addr)
+{
+ struct iic_msg msg;
+ uint8_t tmp;
+
+ /* Set the address to read from */
+ msg.slave = addr;
+ msg.flags = IIC_M_RD;
+ msg.len = 1;
+ msg.buf = &tmp;
+
+ if (iicbus_transfer(sc->sc_dev, &msg, 1) != 0)
+ return (EIO);
+
+ return (0);
+}
+
+/**
+ * twl_scan - scans the i2c bus for sub modules
+ * @dev: the twl device
+ *
+ * TWL devices don't just have one i2c slave address, rather they have up to
+ * 5 other addresses, each is for separate modules within the device. This
+ * function scans the bus for 4 possible sub-devices and stores the info
+ * internally.
+ *
+ */
+static void
+twl_scan(void *dev)
+{
+ struct twl_softc *sc;
+ unsigned i;
+ uint8_t devs[TWL_MAX_SUBADDRS];
+ uint8_t base = TWL_CHIP_ID0;
+
+ sc = device_get_softc((device_t)dev);
+
+ memset(devs, TWL_INVALID_CHIP_ID, TWL_MAX_SUBADDRS);
+
+ /* Try each of the addresses (0x48, 0x49, 0x4a & 0x4b) to determine which
+ * sub modules we have.
+ */
+ for (i = 0; i < TWL_MAX_SUBADDRS; i++) {
+ if (twl_test_present(sc, (base + i)) == 0) {
+ devs[i] = (base + i);
+ device_printf(sc->sc_dev, "Found (sub)device at 0x%02x\n", (base + i));
+ }
+ }
+
+ TWL_LOCK(sc);
+ memcpy(sc->sc_subaddr_map, devs, TWL_MAX_SUBADDRS);
+ TWL_UNLOCK(sc);
+
+ /* Finished with the interrupt hook */
+ config_intrhook_disestablish(&sc->sc_scan_hook);
+}
+
+/**
+ * twl_probe -
+ * @dev: the twl device
+ *
+ * Scans the FDT for a match for the device, possible compatible device
+ * strings are; "ti,twl6030", "ti,twl6025", "ti,twl4030".
+ *
+ * The FDT compat string also determines the type of device (it is currently
+ * not possible to dynamically determine the device type).
+ *
+ */
+static int
+twl_probe(device_t dev)
+{
+ phandle_t node;
+ const char *compat;
+ int len, l;
+ struct twl_softc *sc;
+
+ if ((compat = ofw_bus_get_compat(dev)) == NULL)
+ return (ENXIO);
+
+ if ((node = ofw_bus_get_node(dev)) == 0)
+ return (ENXIO);
+
+ /* Get total 'compatible' prop len */
+ if ((len = OF_getproplen(node, "compatible")) <= 0)
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ sc->sc_type = TWL_DEVICE_UNKNOWN;
+
+ while (len > 0) {
+ if (strncasecmp(compat, "ti,twl6030", 10) == 0)
+ sc->sc_type = TWL_DEVICE_6030;
+ else if (strncasecmp(compat, "ti,twl6025", 10) == 0)
+ sc->sc_type = TWL_DEVICE_6025;
+ else if (strncasecmp(compat, "ti,twl4030", 10) == 0)
+ sc->sc_type = TWL_DEVICE_4030;
+
+ if (sc->sc_type != TWL_DEVICE_UNKNOWN)
+ break;
+
+ /* Slide to the next sub-string. */
+ l = strlen(compat) + 1;
+ compat += l;
+ len -= l;
+ }
+
+ switch (sc->sc_type) {
+ case TWL_DEVICE_4030:
+ device_set_desc(dev, "TI TWL4030/TPS659x0 Companion IC");
+ break;
+ case TWL_DEVICE_6025:
+ device_set_desc(dev, "TI TWL6025 Companion IC");
+ break;
+ case TWL_DEVICE_6030:
+ device_set_desc(dev, "TI TWL6030 Companion IC");
+ break;
+ case TWL_DEVICE_UNKNOWN:
+ default:
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+twl_attach(device_t dev)
+{
+ struct twl_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ TWL_LOCK_INIT(sc);
+
+ /* We have to wait until interrupts are enabled. I2C read and write
+ * only works if the interrupts are available.
+ */
+ sc->sc_scan_hook.ich_func = twl_scan;
+ sc->sc_scan_hook.ich_arg = dev;
+
+ if (config_intrhook_establish(&sc->sc_scan_hook) != 0)
+ return (ENOMEM);
+
+ /* FIXME: should be in DTS file */
+ if ((sc->sc_vreg = device_add_child(dev, "twl_vreg", -1)) == NULL)
+ device_printf(dev, "could not allocate twl_vreg instance\n");
+ if ((sc->sc_clks = device_add_child(dev, "twl_clks", -1)) == NULL)
+ device_printf(dev, "could not allocate twl_clks instance\n");
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+twl_detach(device_t dev)
+{
+ struct twl_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_vreg)
+ device_delete_child(dev, sc->sc_vreg);
+ if (sc->sc_clks)
+ device_delete_child(dev, sc->sc_clks);
+
+
+ TWL_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t twl_methods[] = {
+ DEVMETHOD(device_probe, twl_probe),
+ DEVMETHOD(device_attach, twl_attach),
+ DEVMETHOD(device_detach, twl_detach),
+
+ {0, 0},
+};
+
+static driver_t twl_driver = {
+ "twl",
+ twl_methods,
+ sizeof(struct twl_softc),
+};
+static devclass_t twl_devclass;
+
+DRIVER_MODULE(twl, iicbus, twl_driver, twl_devclass, 0, 0);
+MODULE_VERSION(twl, 1);
diff --git a/sys/arm/ti/twl/twl.h b/sys/arm/ti/twl/twl.h
new file mode 100644
index 0000000..07f2cfd
--- /dev/null
+++ b/sys/arm/ti/twl/twl.h
@@ -0,0 +1,39 @@
+/*-
+ * 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 _TWL_H_
+#define _TWL_H_
+
+int twl_read(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt);
+int twl_write(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt);
+
+int twl_is_4030(device_t dev);
+int twl_is_6025(device_t dev);
+int twl_is_6030(device_t dev);
+
+#endif /* _TWL_H_ */
diff --git a/sys/arm/ti/twl/twl_clks.c b/sys/arm/ti/twl/twl_clks.c
new file mode 100644
index 0000000..d78a733
--- /dev/null
+++ b/sys/arm/ti/twl/twl_clks.c
@@ -0,0 +1,675 @@
+/*-
+ * Copyright (c) 2012
+ * Ben Gray <bgray@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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
+ *
+ * This driver covers the external clocks, allows for enabling &
+ * disabling their output.
+ *
+ *
+ *
+ * FLATTENED DEVICE TREE (FDT)
+ * Startup override settings can be specified in the FDT, if they are they
+ * should be under the twl parent device and take the following form:
+ *
+ * external-clocks = "name1", "state1",
+ * "name2", "state2",
+ * etc;
+ *
+ * Each override should be a pair, the first entry is the name of the clock
+ * the second is the state to set, possible strings are either "on" or "off".
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+
+#include "twl.h"
+#include "twl_clks.h"
+
+
+static int twl_clks_debug = 1;
+
+
+/*
+ * Power Groups bits for the 4030 and 6030 devices
+ */
+#define TWL4030_P3_GRP 0x80 /* Peripherals, power group */
+#define TWL4030_P2_GRP 0x40 /* Modem power group */
+#define TWL4030_P1_GRP 0x20 /* Application power group (FreeBSD control) */
+
+#define TWL6030_P3_GRP 0x04 /* Modem power group */
+#define TWL6030_P2_GRP 0x02 /* Connectivity power group */
+#define TWL6030_P1_GRP 0x01 /* Application power group (FreeBSD control) */
+
+/*
+ * Register offsets within a clk regulator register set
+ */
+#define TWL_CLKS_GRP 0x00 /* Regulator GRP register */
+#define TWL_CLKS_STATE 0x02 /* TWL6030 only */
+
+
+
+/**
+ * Support voltage regulators for the different IC's
+ */
+struct twl_clock {
+ const char *name;
+ uint8_t subdev;
+ uint8_t regbase;
+};
+
+static const struct twl_clock twl4030_clocks[] = {
+ { "32kclkout", 0, 0x8e },
+ { NULL, 0, 0x00 }
+};
+
+static const struct twl_clock twl6030_clocks[] = {
+ { "clk32kg", 0, 0xbc },
+ { "clk32kao", 0, 0xb9 },
+ { "clk32kaudio", 0, 0xbf },
+ { NULL, 0, 0x00 }
+};
+
+#define TWL_CLKS_MAX_NAMELEN 32
+
+struct twl_clk_entry {
+ LIST_ENTRY(twl_clk_entry) link;
+ struct sysctl_oid *oid;
+ char name[TWL_CLKS_MAX_NAMELEN];
+ uint8_t sub_dev; /* the sub-device number for the clock */
+ uint8_t reg_off; /* register base address of the clock */
+};
+
+struct twl_clks_softc {
+ device_t sc_dev; /* twl_clk device */
+ device_t sc_pdev; /* parent device (twl) */
+ struct sx sc_sx; /* internal locking */
+ struct intr_config_hook sc_init_hook;
+ LIST_HEAD(twl_clk_list, twl_clk_entry) sc_clks_list;
+};
+
+/**
+ * Macros for driver shared locking
+ */
+#define TWL_CLKS_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx)
+#define TWL_CLKS_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx)
+#define TWL_CLKS_SLOCK(_sc) sx_slock(&(_sc)->sc_sx)
+#define TWL_CLKS_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx)
+#define TWL_CLKS_LOCK_INIT(_sc) sx_init(&(_sc)->sc_sx, "twl_clks")
+#define TWL_CLKS_LOCK_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx);
+
+#define TWL_CLKS_ASSERT_LOCKED(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED);
+
+#define TWL_CLKS_LOCK_UPGRADE(_sc) \
+ do { \
+ while (!sx_try_upgrade(&(_sc)->sc_sx)) \
+ pause("twl_clks_ex", (hz / 100)); \
+ } while(0)
+#define TWL_CLKS_LOCK_DOWNGRADE(_sc) sx_downgrade(&(_sc)->sc_sx);
+
+
+
+
+/**
+ * twl_clks_read_1 - read single register from the TWL device
+ * twl_clks_write_1 - writes a single register in the TWL device
+ * @sc: device context
+ * @clk: the clock device we're reading from / writing to
+ * @off: offset within the clock's register set
+ * @val: the value to write or a pointer to a variable to store the result
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static inline int
+twl_clks_read_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+ uint8_t off, uint8_t *val)
+{
+ return (twl_read(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, val, 1));
+}
+
+static inline int
+twl_clks_write_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+ uint8_t off, uint8_t val)
+{
+ return (twl_write(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, &val, 1));
+}
+
+
+/**
+ * twl_clks_is_enabled - determines if a clock is enabled
+ * @dev: TWL CLK device
+ * @name: the name of the clock
+ * @enabled: upon return will contain the 'enabled' state
+ *
+ * LOCKING:
+ * Internally the function takes and releases the TWL lock.
+ *
+ * RETURNS:
+ * Zero on success or a negative error code on failure.
+ */
+int
+twl_clks_is_enabled(device_t dev, const char *name, int *enabled)
+{
+ struct twl_clks_softc *sc = device_get_softc(dev);
+ struct twl_clk_entry *clk;
+ int found = 0;
+ int err;
+ uint8_t grp, state;
+
+ TWL_CLKS_SLOCK(sc);
+
+ LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+ if (strcmp(clk->name, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ TWL_CLKS_SUNLOCK(sc);
+ return (EINVAL);
+ }
+
+
+ if (twl_is_4030(sc->sc_pdev)) {
+
+ err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+ if (!err)
+ *enabled = (grp & TWL4030_P1_GRP);
+
+ } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+ TWL_CLKS_LOCK_UPGRADE(sc);
+
+ /* Check the clock is in the application group */
+ if (twl_is_6030(sc->sc_pdev)) {
+ err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+ if (err) {
+ TWL_CLKS_LOCK_DOWNGRADE(sc);
+ goto done;
+ }
+
+ if (!(grp & TWL6030_P1_GRP)) {
+ TWL_CLKS_LOCK_DOWNGRADE(sc);
+ *enabled = 0; /* disabled */
+ goto done;
+ }
+ }
+
+ /* Read the application mode state and verify it's ON */
+ err = twl_clks_read_1(sc, clk, TWL_CLKS_STATE, &state);
+ if (!err)
+ *enabled = ((state & 0x0C) == 0x04);
+
+ TWL_CLKS_LOCK_DOWNGRADE(sc);
+
+ } else {
+ err = EINVAL;
+ }
+
+done:
+ TWL_CLKS_SUNLOCK(sc);
+ return (err);
+}
+
+
+/**
+ * twl_clks_set_state - enables/disables a clock output
+ * @sc: device context
+ * @clk: the clock entry to enable/disable
+ * @enable: non-zero the clock is enabled, zero the clock is disabled
+ *
+ * LOCKING:
+ * The TWL CLK lock must be held before this function is called.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static int
+twl_clks_set_state(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+ int enable)
+{
+ int xlocked;
+ int err;
+ uint8_t grp;
+
+ TWL_CLKS_ASSERT_LOCKED(sc);
+
+ /* Upgrade the lock to exclusive because about to perform read-mod-write */
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_CLKS_LOCK_UPGRADE(sc);
+
+ err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+ if (err)
+ goto done;
+
+ if (twl_is_4030(sc->sc_pdev)) {
+
+ /* On the TWL4030 we just need to ensure the clock is in the right
+ * power domain, don't need to turn on explicitly like TWL6030.
+ */
+ if (enable)
+ grp |= TWL4030_P1_GRP;
+ else
+ grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
+
+ err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
+
+ } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+ /* Make sure the clock belongs to at least the APP power group */
+ if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
+ grp |= TWL6030_P1_GRP;
+ err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
+ if (err)
+ goto done;
+ }
+
+ /* On TWL6030 we need to make sure we disable power for all groups */
+ if (twl_is_6030(sc->sc_pdev))
+ grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
+ else
+ grp = 0x00;
+
+ /* Set the state of the clock */
+ if (enable)
+ err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5) | 0x01);
+ else
+ err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5));
+
+ } else {
+
+ err = EINVAL;
+ }
+
+done:
+ if (!xlocked)
+ TWL_CLKS_LOCK_DOWNGRADE(sc);
+
+ if ((twl_clks_debug > 1) && !err)
+ device_printf(sc->sc_dev, "%s : %sabled\n", clk->name,
+ enable ? "en" : "dis");
+
+ return (err);
+}
+
+
+/**
+ * twl_clks_disable - disables a clock output
+ * @dev: TWL clk device
+* @name: the name of the clock
+ *
+ * LOCKING:
+ * Internally the function takes and releases the TWL lock.
+ *
+ * RETURNS:
+* Zero on success or an error code on failure.
+ */
+int
+twl_clks_disable(device_t dev, const char *name)
+{
+ struct twl_clks_softc *sc = device_get_softc(dev);
+ struct twl_clk_entry *clk;
+ int err = EINVAL;
+
+ TWL_CLKS_SLOCK(sc);
+
+ LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+ if (strcmp(clk->name, name) == 0) {
+ err = twl_clks_set_state(sc, clk, 0);
+ break;
+ }
+ }
+
+ TWL_CLKS_SUNLOCK(sc);
+ return (err);
+}
+
+/**
+ * twl_clks_enable - enables a clock output
+ * @dev: TWL clk device
+ * @name: the name of the clock
+ *
+ * LOCKING:
+ * Internally the function takes and releases the TWL CLKS lock.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+int
+twl_clks_enable(device_t dev, const char *name)
+{
+ struct twl_clks_softc *sc = device_get_softc(dev);
+ struct twl_clk_entry *clk;
+ int err = EINVAL;
+
+ TWL_CLKS_SLOCK(sc);
+
+ LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+ if (strcmp(clk->name, name) == 0) {
+ err = twl_clks_set_state(sc, clk, 1);
+ break;
+ }
+ }
+
+ TWL_CLKS_SUNLOCK(sc);
+ return (err);
+}
+
+/**
+ * twl_clks_sysctl_clock - reads the state of the clock
+ * @SYSCTL_HANDLER_ARGS: arguments for the callback
+ *
+ * Returns the clock status; disabled is zero and enabled is non-zero.
+ *
+ * LOCKING:
+ * It's expected the TWL lock is held while this function is called.
+ *
+ * RETURNS:
+ * EIO if device is not present, otherwise 0 is returned.
+ */
+static int
+twl_clks_sysctl_clock(SYSCTL_HANDLER_ARGS)
+{
+ struct twl_clks_softc *sc = (struct twl_clks_softc*)arg1;
+ int err;
+ int enabled = 0;
+
+ if ((err = twl_clks_is_enabled(sc->sc_dev, oidp->oid_name, &enabled)) != 0)
+ return err;
+
+ return sysctl_handle_int(oidp, &enabled, 0, req);
+}
+
+/**
+ * twl_clks_add_clock - adds single clock sysctls for the device
+ * @sc: device soft context
+ * @name: the name of the regulator
+ * @nsub: the number of the subdevice
+ * @regbase: the base address of the clocks registers
+ *
+ * Adds a single clock to the device and also a sysctl interface for
+ * querying it's status.
+ *
+ * LOCKING:
+ * It's expected the exclusive lock is held while this function is called.
+ *
+ * RETURNS:
+ * Pointer to the new clock entry on success, otherwise NULL on failure.
+ */
+static struct twl_clk_entry*
+twl_clks_add_clock(struct twl_clks_softc *sc, const char *name,
+ uint8_t nsub, uint8_t regbase)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ struct twl_clk_entry *new;
+
+ TWL_CLKS_ASSERT_LOCKED(sc);
+
+ new = malloc(sizeof(struct twl_clk_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (new == NULL)
+ return (NULL);
+
+
+ strncpy(new->name, name, TWL_CLKS_MAX_NAMELEN);
+ new->name[TWL_CLKS_MAX_NAMELEN - 1] = '\0';
+
+ new->sub_dev = nsub;
+ new->reg_off = regbase;
+
+
+
+ /* Add a sysctl entry for the clock */
+ new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
+ CTLTYPE_INT | CTLFLAG_RD, sc, 0,
+ twl_clks_sysctl_clock, "I", "external clock");
+
+ /* Finally add the regulator to list of supported regulators */
+ LIST_INSERT_HEAD(&sc->sc_clks_list, new, link);
+
+ return (new);
+}
+
+/**
+ * twl_clks_add_clocks - populates the internal list of clocks
+ * @sc: device soft context
+ * @chip: the name of the chip used in the hints
+ * @clks the list of clocks supported by the device
+ *
+ * Loops over the list of clocks and adds them to the device context. Also
+ * scans the FDT to determine if there are any clocks that should be
+ * enabled/disabled automatically.
+ *
+ * LOCKING:
+ * Internally takes the exclusive lock while adding the clocks to the
+ * device context.
+ *
+ * RETURNS:
+ * Always returns 0.
+ */
+static int
+twl_clks_add_clocks(struct twl_clks_softc *sc, const struct twl_clock *clks)
+{
+ int err;
+ const struct twl_clock *walker;
+ struct twl_clk_entry *entry;
+ phandle_t child;
+ char rnames[256];
+ char *name, *state;
+ int len = 0, prop_len;
+ int enable;
+
+
+ TWL_CLKS_XLOCK(sc);
+
+ /* Add the regulators from the list */
+ walker = &clks[0];
+ while (walker->name != NULL) {
+
+ /* Add the regulator to the list */
+ entry = twl_clks_add_clock(sc, walker->name, walker->subdev,
+ walker->regbase);
+ if (entry == NULL)
+ continue;
+
+ walker++;
+ }
+
+ /* Check for any FDT settings that need to be applied */
+ child = ofw_bus_get_node(sc->sc_pdev);
+ if (child) {
+
+ prop_len = OF_getprop(child, "external-clocks", rnames, sizeof(rnames));
+ while (len < prop_len) {
+ name = rnames + len;
+ len += strlen(name) + 1;
+ if ((len >= prop_len) || (name[0] == '\0'))
+ break;
+
+ state = rnames + len;
+ len += strlen(state) + 1;
+ if (state[0] == '\0')
+ break;
+
+ enable = !strncmp(state, "on", 2);
+
+ LIST_FOREACH(entry, &sc->sc_clks_list, link) {
+ if (strcmp(entry->name, name) == 0) {
+ twl_clks_set_state(sc, entry, enable);
+ break;
+ }
+ }
+ }
+ }
+
+ TWL_CLKS_XUNLOCK(sc);
+
+
+ if (twl_clks_debug) {
+ LIST_FOREACH(entry, &sc->sc_clks_list, link) {
+ err = twl_clks_is_enabled(sc->sc_dev, entry->name, &enable);
+ if (!err)
+ device_printf(sc->sc_dev, "%s : %s\n", entry->name,
+ enable ? "on" : "off");
+ }
+ }
+
+ return (0);
+}
+
+/**
+ * twl_clks_init - initialises the list of clocks
+ * @dev: the twl_clks device
+ *
+ * This function is called as an intrhook once interrupts have been enabled,
+ * this is done so that the driver has the option to enable/disable a clock
+ * based on settings providied in the FDT.
+ *
+ * LOCKING:
+ * May takes the exclusive lock in the function.
+ */
+static void
+twl_clks_init(void *dev)
+{
+ struct twl_clks_softc *sc;
+
+ sc = device_get_softc((device_t)dev);
+
+ if (twl_is_4030(sc->sc_pdev))
+ twl_clks_add_clocks(sc, twl4030_clocks);
+ else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
+ twl_clks_add_clocks(sc, twl6030_clocks);
+
+ config_intrhook_disestablish(&sc->sc_init_hook);
+}
+
+static int
+twl_clks_probe(device_t dev)
+{
+ if (twl_is_4030(device_get_parent(dev)))
+ device_set_desc(dev, "TI TWL4030 PMIC External Clocks");
+ else if (twl_is_6025(device_get_parent(dev)) ||
+ twl_is_6030(device_get_parent(dev)))
+ device_set_desc(dev, "TI TWL6025/TWL6030 PMIC External Clocks");
+ else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+twl_clks_attach(device_t dev)
+{
+ struct twl_clks_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ sc->sc_pdev = device_get_parent(dev);
+
+ TWL_CLKS_LOCK_INIT(sc);
+
+ LIST_INIT(&sc->sc_clks_list);
+
+
+ sc->sc_init_hook.ich_func = twl_clks_init;
+ sc->sc_init_hook.ich_arg = dev;
+
+ if (config_intrhook_establish(&sc->sc_init_hook) != 0)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static int
+twl_clks_detach(device_t dev)
+{
+ struct twl_clks_softc *sc;
+ struct twl_clk_entry *clk;
+ struct twl_clk_entry *tmp;
+
+ sc = device_get_softc(dev);
+
+ TWL_CLKS_XLOCK(sc);
+
+ LIST_FOREACH_SAFE(clk, &sc->sc_clks_list, link, tmp) {
+ LIST_REMOVE(clk, link);
+ sysctl_remove_oid(clk->oid, 1, 0);
+ free(clk, M_DEVBUF);
+ }
+
+ TWL_CLKS_XUNLOCK(sc);
+
+ TWL_CLKS_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t twl_clks_methods[] = {
+ DEVMETHOD(device_probe, twl_clks_probe),
+ DEVMETHOD(device_attach, twl_clks_attach),
+ DEVMETHOD(device_detach, twl_clks_detach),
+
+ {0, 0},
+};
+
+static driver_t twl_clks_driver = {
+ "twl_clks",
+ twl_clks_methods,
+ sizeof(struct twl_clks_softc),
+};
+
+static devclass_t twl_clks_devclass;
+
+DRIVER_MODULE(twl_clks, twl, twl_clks_driver, twl_clks_devclass, 0, 0);
+MODULE_VERSION(twl_clks, 1);
diff --git a/sys/arm/ti/twl/twl_clks.h b/sys/arm/ti/twl/twl_clks.h
new file mode 100644
index 0000000..c5d89f3
--- /dev/null
+++ b/sys/arm/ti/twl/twl_clks.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2012
+ * Ben Gray <bgray@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 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 _TWL_CLKS_H_
+#define _TWL_CLKS_H_
+
+
+int twl_clks_enable(device_t dev, const char *name);
+int twl_clks_disable(device_t dev, const char *name);
+int twl_clks_is_enabled(device_t dev, const char *name, int *enabled);
+
+
+#endif /* _TWL_CLKS_H_ */
diff --git a/sys/arm/ti/twl/twl_vreg.c b/sys/arm/ti/twl/twl_vreg.c
new file mode 100644
index 0000000..26c2e26
--- /dev/null
+++ b/sys/arm/ti/twl/twl_vreg.c
@@ -0,0 +1,1053 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
+ *
+ * This driver covers the voltages regulators (LDO), allows for enabling &
+ * disabling the voltage output and adjusting the voltage level.
+ *
+ * Voltage regulators can belong to different power groups, in this driver we
+ * put the regulators under our control in the "Application power group".
+ *
+ *
+ * FLATTENED DEVICE TREE (FDT)
+ * Startup override settings can be specified in the FDT, if they are they
+ * should be under the twl parent device and take the following form:
+ *
+ * voltage-regulators = "name1", "millivolts1",
+ * "name2", "millivolts2";
+ *
+ * Each override should be a pair, the first entry is the name of the regulator
+ * the second is the voltage (in millivolts) to set for the given regulator.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+
+#include "twl.h"
+#include "twl_vreg.h"
+
+static int twl_vreg_debug = 1;
+
+
+/*
+ * Power Groups bits for the 4030 and 6030 devices
+ */
+#define TWL4030_P3_GRP 0x80 /* Peripherals, power group */
+#define TWL4030_P2_GRP 0x40 /* Modem power group */
+#define TWL4030_P1_GRP 0x20 /* Application power group (FreeBSD control) */
+
+#define TWL6030_P3_GRP 0x04 /* Modem power group */
+#define TWL6030_P2_GRP 0x02 /* Connectivity power group */
+#define TWL6030_P1_GRP 0x01 /* Application power group (FreeBSD control) */
+
+/*
+ * Register offsets within a LDO regulator register set
+ */
+#define TWL_VREG_GRP 0x00 /* Regulator GRP register */
+#define TWL_VREG_STATE 0x02
+#define TWL_VREG_VSEL 0x03 /* Voltage select register */
+
+#define UNDF 0xFFFF
+
+static const uint16_t twl6030_voltages[] = {
+ 0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
+ 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
+ 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
+ 3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
+};
+
+static const uint16_t twl4030_vaux1_voltages[] = {
+ 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vaux2_voltages[] = {
+ 1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
+ 2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
+};
+static const uint16_t twl4030_vaux3_voltages[] = {
+ 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vaux4_voltages[] = {
+ 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
+ 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vmmc1_voltages[] = {
+ 1850, 2850, 3000, 3150
+};
+static const uint16_t twl4030_vmmc2_voltages[] = {
+ 1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
+ 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vpll1_voltages[] = {
+ 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vpll2_voltages[] = {
+ 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
+ 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vsim_voltages[] = {
+ 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vdac_voltages[] = {
+ 1200, 1300, 1800, 1800
+};
+static const uint16_t twl4030_vdd1_voltages[] = {
+ 800, 1450
+};
+static const uint16_t twl4030_vdd2_voltages[] = {
+ 800, 1450, 1500
+};
+static const uint16_t twl4030_vio_voltages[] = {
+ 1800, 1850
+};
+static const uint16_t twl4030_vintana2_voltages[] = {
+ 2500, 2750
+};
+
+/**
+ * Support voltage regulators for the different IC's
+ */
+struct twl_regulator {
+ const char *name;
+ uint8_t subdev;
+ uint8_t regbase;
+
+ uint16_t fixedvoltage;
+
+ const uint16_t *voltages;
+ uint32_t num_voltages;
+};
+
+#define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \
+ { name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) }
+#define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \
+ { name, subdev, reg, voltage, NULL, 0 }
+
+static const struct twl_regulator twl4030_regulators[] = {
+ TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x17, twl4030_vaux1_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x1B, twl4030_vaux2_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x1F, twl4030_vaux3_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vaux4", 0, 0x23, twl4030_vaux4_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vmmc1", 0, 0x27, twl4030_vmmc1_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vmmc2", 0, 0x2B, twl4030_vmmc2_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vpll1", 0, 0x2F, twl4030_vpll1_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vpll2", 0, 0x33, twl4030_vpll2_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vsim", 0, 0x37, twl4030_vsim_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vdac", 0, 0x3B, twl4030_vdac_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages),
+ TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500),
+ TWL_REGULATOR_FIXED("vintdig", 0, 0x47, 1500),
+ TWL_REGULATOR_FIXED("vusb1v5", 0, 0x71, 1500),
+ TWL_REGULATOR_FIXED("vusb1v8", 0, 0x74, 1800),
+ TWL_REGULATOR_FIXED("vusb3v1", 0, 0x77, 3100),
+ { NULL, 0, 0x00, 0, NULL, 0 }
+};
+
+static const struct twl_regulator twl6030_regulators[] = {
+ TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vmmc", 0, 0x98, twl6030_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vpp", 0, 0x9C, twl6030_voltages),
+ TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages),
+ TWL_REGULATOR_FIXED("vmem", 0, 0x64, 1800),
+ TWL_REGULATOR_FIXED("vusb", 0, 0xA0, 3300),
+ TWL_REGULATOR_FIXED("v1v8", 0, 0x46, 1800),
+ TWL_REGULATOR_FIXED("v2v1", 0, 0x4C, 2100),
+ TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290),
+ TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800),
+ TWL_REGULATOR_FIXED("vdac", 0, 0x94, 1800),
+ TWL_REGULATOR_FIXED("vana", 0, 0x80, 2100),
+ { NULL, 0, 0x00, 0, NULL, 0 }
+};
+
+#define TWL_VREG_MAX_NAMELEN 32
+
+struct twl_regulator_entry {
+ LIST_ENTRY(twl_regulator_entry) entries;
+ char name[TWL_VREG_MAX_NAMELEN];
+ struct sysctl_oid *oid;
+ uint8_t sub_dev; /* TWL sub-device group */
+ uint8_t reg_off; /* base register offset for the LDO */
+ uint16_t fixed_voltage; /* the (milli)voltage if LDO is fixed */
+ const uint16_t *supp_voltages; /* pointer to an array of possible voltages */
+ uint32_t num_supp_voltages; /* the number of supplied voltages */
+};
+
+struct twl_vreg_softc {
+ device_t sc_dev;
+ device_t sc_pdev;
+ struct sx sc_sx;
+
+ struct intr_config_hook sc_init_hook;
+ LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
+};
+
+
+#define TWL_VREG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx)
+#define TWL_VREG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx)
+#define TWL_VREG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx)
+#define TWL_VREG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx)
+#define TWL_VREG_LOCK_INIT(_sc) sx_init(&(_sc)->sc_sx, "twl_vreg")
+#define TWL_VREG_LOCK_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx);
+
+#define TWL_VREG_ASSERT_LOCKED(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED);
+
+#define TWL_VREG_LOCK_UPGRADE(_sc) \
+ do { \
+ while (!sx_try_upgrade(&(_sc)->sc_sx)) \
+ pause("twl_vreg_ex", (hz / 100)); \
+ } while(0)
+#define TWL_VREG_LOCK_DOWNGRADE(_sc) sx_downgrade(&(_sc)->sc_sx);
+
+
+
+
+/**
+ * twl_vreg_read_1 - read single register from the TWL device
+ * twl_vreg_write_1 - write a single register in the TWL device
+ * @sc: device context
+ * @clk: the clock device we're reading from / writing to
+ * @off: offset within the clock's register set
+ * @val: the value to write or a pointer to a variable to store the result
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static inline int
+twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
+ uint8_t off, uint8_t *val)
+{
+ return (twl_read(sc->sc_pdev, regulator->sub_dev,
+ regulator->reg_off + off, val, 1));
+}
+
+static inline int
+twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
+ uint8_t off, uint8_t val)
+{
+ return (twl_write(sc->sc_pdev, regulator->sub_dev,
+ regulator->reg_off + off, &val, 1));
+}
+
+/**
+ * twl_millivolt_to_vsel - gets the vsel bit value to write into the register
+ * for a desired voltage and regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator device
+ * @millivolts: the millivolts to find the bit value for
+ * @vsel: upon return will contain the corresponding register value
+ *
+ * Accepts a (milli)voltage value and tries to find the closest match to the
+ * actual supported voltages for the given regulator. If a match is found
+ * within 100mv of the target, @vsel is written with the match and 0 is
+ * returned. If no voltage match is found the function returns an non-zero
+ * value.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
+{
+ int delta, smallest_delta;
+ unsigned i, closest_idx;
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ if (regulator->supp_voltages == NULL)
+ return (EINVAL);
+
+ /* Loop over the support voltages and try and find the closest match */
+ closest_idx = 0;
+ smallest_delta = 0x7fffffff;
+ for (i = 0; i < regulator->num_supp_voltages; i++) {
+
+ /* Ignore undefined values */
+ if (regulator->supp_voltages[i] == UNDF)
+ continue;
+
+ /* Calculate the difference */
+ delta = millivolts - (int)regulator->supp_voltages[i];
+ if (abs(delta) < smallest_delta) {
+ smallest_delta = abs(delta);
+ closest_idx = i;
+ }
+ }
+
+ /* Check we got a voltage that was within 100mv of the actual target, this
+ * is just a value I picked out of thin air.
+ */
+ if ((smallest_delta > 100) && (closest_idx < 0x100))
+ return (EINVAL);
+
+ *vsel = closest_idx;
+ return (0);
+}
+
+/**
+ * twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator device
+ * @enabled: stores the enabled status, zero disabled, non-zero enabled
+ *
+ * LOCKING:
+ * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ * exclusive if not already but, if so, it will be downgraded again before
+ * returning.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator, int *enabled)
+{
+ int err;
+ uint8_t grp;
+ uint8_t state;
+ int xlocked;
+
+ if (enabled == NULL)
+ return (EINVAL);
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_VREG_LOCK_UPGRADE(sc);
+
+ /* The status reading is different for the different devices */
+ if (twl_is_4030(sc->sc_pdev)) {
+
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
+ if (err)
+ goto done;
+
+ *enabled = (state & TWL4030_P1_GRP);
+
+ } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+ /* Check the regulator is in the application group */
+ if (twl_is_6030(sc->sc_pdev)) {
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+ if (err)
+ goto done;
+
+ if (!(grp & TWL6030_P1_GRP)) {
+ *enabled = 0; /* disabled */
+ goto done;
+ }
+ }
+
+ /* Read the application mode state and verify it's ON */
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
+ if (err)
+ goto done;
+
+ *enabled = ((state & 0x0C) == 0x04);
+
+ } else {
+ err = EINVAL;
+ }
+
+done:
+ if (!xlocked)
+ TWL_VREG_LOCK_DOWNGRADE(sc);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_disable_regulator - disables a voltage regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator device
+ *
+ * Disables the regulator which will stop the output drivers.
+ *
+ * LOCKING:
+ * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ * exclusive if not already but, if so, it will be downgraded again before
+ * returning.
+ *
+ * RETURNS:
+ * Zero on success or a positive error code on failure.
+ */
+static int
+twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator)
+{
+ int err = 0;
+ uint8_t grp;
+ int xlocked;
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_VREG_LOCK_UPGRADE(sc);
+
+ if (twl_is_4030(sc->sc_pdev)) {
+
+ /* Read the regulator CFG_GRP register */
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+ if (err)
+ goto done;
+
+ /* On the TWL4030 we just need to remove the regulator from all the
+ * power groups.
+ */
+ grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+
+ } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+ /* On TWL6030 we need to make sure we disable power for all groups */
+ if (twl_is_6030(sc->sc_pdev))
+ grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
+ else
+ grp = 0x00;
+
+ /* Write the resource state to "OFF" */
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
+ }
+
+done:
+ if (!xlocked)
+ TWL_VREG_LOCK_DOWNGRADE(sc);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_enable_regulator - enables the voltage regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator device
+ *
+ * Enables the regulator which will enable the voltage out at the currently
+ * set voltage. Set the voltage before calling this function to avoid
+ * driving the voltage too high/low by mistake.
+ *
+ * LOCKING:
+ * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ * exclusive if not already but, if so, it will be downgraded again before
+ * returning.
+ *
+ * RETURNS:
+ * Zero on success or a positive error code on failure.
+ */
+static int
+twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator)
+{
+ int err;
+ uint8_t grp;
+ int xlocked;
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_VREG_LOCK_UPGRADE(sc);
+
+
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+ if (err)
+ goto done;
+
+ /* Enable the regulator by ensuring it's in the application power group
+ * and is in the "on" state.
+ */
+ if (twl_is_4030(sc->sc_pdev)) {
+
+ /* On the TWL4030 we just need to ensure the regulator is in the right
+ * power domain, don't need to turn on explicitly like TWL6030.
+ */
+ grp |= TWL4030_P1_GRP;
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+
+ } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+ if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
+ grp |= TWL6030_P1_GRP;
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+ if (err)
+ goto done;
+ }
+
+ /* Write the resource state to "ON" */
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
+ }
+
+done:
+ if (!xlocked)
+ TWL_VREG_LOCK_DOWNGRADE(sc);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator structure
+ * @millivolts: the voltage to set
+ *
+ * Sets the voltage output on a given regulator, if the regulator is not
+ * enabled, it will be enabled.
+ *
+ * LOCKING:
+ * On entry expects the TWL VREG lock to be held, may upgrade the lock to
+ * exclusive but if so it will be downgraded once again before returning.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator, int millivolts)
+{
+ int err;
+ uint8_t vsel;
+ int xlocked;
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ /* If millivolts is zero then we simply disable the output */
+ if (millivolts == 0)
+ return (twl_vreg_disable_regulator(sc, regulator));
+
+ /* If the regulator has a fixed voltage then check the setting matches
+ * and simply enable.
+ */
+ if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
+ if (millivolts != regulator->fixed_voltage)
+ return (EINVAL);
+
+ return (twl_vreg_enable_regulator(sc, regulator));
+ }
+
+ /* Get the VSEL value for the given voltage */
+ err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
+ if (err)
+ return (err);
+
+
+ /* Need to upgrade because writing the voltage and enabling should be atomic */
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_VREG_LOCK_UPGRADE(sc);
+
+
+ /* Set voltage and enable (atomically) */
+ err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
+ if (!err) {
+ err = twl_vreg_enable_regulator(sc, regulator);
+ }
+
+ if (!xlocked)
+ TWL_VREG_LOCK_DOWNGRADE(sc);
+
+ if ((twl_vreg_debug > 1) && !err)
+ device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
+ regulator->name, millivolts, vsel);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
+ * @sc: the device soft context
+ * @regulator: pointer to the regulator structure
+ * @millivolts: upon return will contain the voltage on the regulator
+ *
+ * LOCKING:
+ * On entry expects the TWL VREG lock to be held. It will upgrade the lock to
+ * exclusive if not already, but if so, it will be downgraded again before
+ * returning.
+ *
+ * RETURNS:
+ * Zero on success, or otherwise an error code.
+ */
+static int
+twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
+ struct twl_regulator_entry *regulator, int *millivolts)
+{
+ int err;
+ int en = 0;
+ int xlocked;
+ uint8_t vsel;
+
+ TWL_VREG_ASSERT_LOCKED(sc);
+
+ /* Need to upgrade the lock because checking enabled state and voltage
+ * should be atomic.
+ */
+ xlocked = sx_xlocked(&sc->sc_sx);
+ if (!xlocked)
+ TWL_VREG_LOCK_UPGRADE(sc);
+
+
+ /* Check if the regulator is currently enabled */
+ err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
+ if (err)
+ goto done;
+
+ *millivolts = 0;
+ if (!en)
+ goto done;
+
+
+ /* Not all voltages are adjustable */
+ if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
+ *millivolts = regulator->fixed_voltage;
+ goto done;
+ }
+
+ /* For variable voltages read the voltage register */
+ err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
+ if (err)
+ goto done;
+
+ vsel &= (regulator->num_supp_voltages - 1);
+ if (regulator->supp_voltages[vsel] == UNDF) {
+ err = EINVAL;
+ goto done;
+ }
+
+ *millivolts = regulator->supp_voltages[vsel];
+
+done:
+ if (!xlocked)
+ TWL_VREG_LOCK_DOWNGRADE(sc);
+
+ if ((twl_vreg_debug > 1) && !err)
+ device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
+ regulator->name, *millivolts, vsel);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_get_voltage - public interface to read the voltage on a regulator
+ * @dev: TWL VREG device
+ * @name: the name of the regulator to read the voltage of
+ * @millivolts: pointer to an integer that upon return will contain the mV
+ *
+ * If the regulator is disabled the function will set the @millivolts to zero.
+ *
+ * LOCKING:
+ * Internally the function takes and releases the TWL VREG lock.
+ *
+ * RETURNS:
+ * Zero on success or a negative error code on failure.
+ */
+int
+twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
+{
+ struct twl_vreg_softc *sc;
+ struct twl_regulator_entry *regulator;
+ int err = EINVAL;
+
+ if (millivolts == NULL)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ TWL_VREG_SLOCK(sc);
+
+ LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+ if (strcmp(regulator->name, name) == 0) {
+ err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
+ break;
+ }
+ }
+
+ TWL_VREG_SUNLOCK(sc);
+
+ return (err);
+}
+
+/**
+ * twl_vreg_set_voltage - public interface to write the voltage on a regulator
+ * @dev: TWL VREG device
+ * @name: the name of the regulator to read the voltage of
+ * @millivolts: the voltage to set in millivolts
+ *
+ * Sets the output voltage on a given regulator. If the regulator is a fixed
+ * voltage reg then the @millivolts value should match the fixed voltage. If
+ * a variable regulator then the @millivolt value must fit within the max/min
+ * range of the given regulator.
+ *
+ * LOCKING:
+ * Internally the function takes and releases the TWL VREG lock.
+ *
+ * RETURNS:
+ * Zero on success or a negative error code on failure.
+ */
+int
+twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
+{
+ struct twl_vreg_softc *sc;
+ struct twl_regulator_entry *regulator;
+ int err = EINVAL;
+
+ sc = device_get_softc(dev);
+
+ TWL_VREG_SLOCK(sc);
+
+ LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+ if (strcmp(regulator->name, name) == 0) {
+ err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
+ break;
+ }
+ }
+
+ TWL_VREG_SUNLOCK(sc);
+
+ return (err);
+}
+
+/**
+ * twl_sysctl_voltage - reads or writes the voltage for a regulator
+ * @SYSCTL_HANDLER_ARGS: arguments for the callback
+ *
+ * Callback for the sysctl entry for the regulator, simply used to return
+ * the voltage on a particular regulator.
+ *
+ * LOCKING:
+ * Takes the TWL_VREG shared lock internally.
+ *
+ * RETURNS:
+ * Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
+{
+ struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
+ struct twl_regulator_entry *regulator;
+ int voltage;
+ int found = 0;
+
+ TWL_VREG_SLOCK(sc);
+
+ /* Find the regulator with the matching name */
+ LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+ if (strcmp(regulator->name, oidp->oid_name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* Sanity check that we found the regulator */
+ if (!found) {
+ TWL_VREG_SUNLOCK(sc);
+ return (EINVAL);
+ }
+
+ twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
+
+ TWL_VREG_SUNLOCK(sc);
+
+ return sysctl_handle_int(oidp, &voltage, 0, req);
+}
+
+/**
+ * twl_add_regulator - adds single voltage regulator sysctls for the device
+ * @sc: device soft context
+ * @name: the name of the regulator
+ * @nsub: the number of the subdevice
+ * @regbase: the base address of the voltage regulator registers
+ * @fixed_voltage: if a fixed voltage regulator this defines it's voltage
+ * @voltages: if a variable voltage regulator, an array of possible voltages
+ * @num_voltages: the number of entries @voltages
+ *
+ * Adds a voltage regulator to the device and also a sysctl interface for the
+ * regulator.
+ *
+ * LOCKING:
+ * The TWL_VEG exclusive lock must be held while this function is called.
+ *
+ * RETURNS:
+ * Pointer to the new regulator entry on success, otherwise on failure NULL.
+ */
+static struct twl_regulator_entry*
+twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
+ uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
+ const uint16_t *voltages, uint32_t num_voltages)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ struct twl_regulator_entry *new;
+
+ new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (new == NULL)
+ return (NULL);
+
+
+ strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
+ new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
+
+ new->sub_dev = nsub;
+ new->reg_off = regbase;
+
+ new->fixed_voltage = fixed_voltage;
+
+ new->supp_voltages = voltages;
+ new->num_supp_voltages = num_voltages;
+
+
+ /* Add a sysctl entry for the voltage */
+ new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
+ CTLTYPE_INT | CTLFLAG_RD, sc, 0,
+ twl_vreg_sysctl_voltage, "I", "voltage regulator");
+
+ /* Finally add the regulator to list of supported regulators */
+ LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
+
+ return (new);
+}
+
+/**
+ * twl_vreg_add_regulators - adds any voltage regulators to the device
+ * @sc: device soft context
+ * @chip: the name of the chip used in the hints
+ * @regulators: the list of possible voltage regulators
+ *
+ * Loops over the list of regulators and matches up with the FDT values,
+ * adjusting the actual voltage based on the supplied values.
+ *
+ * LOCKING:
+ * The TWL_VEG exclusive lock must be held while this function is called.
+ *
+ * RETURNS:
+ * Always returns 0.
+ */
+static int
+twl_vreg_add_regulators(struct twl_vreg_softc *sc,
+ const struct twl_regulator *regulators)
+{
+ int err;
+ int millivolts;
+ const struct twl_regulator *walker;
+ struct twl_regulator_entry *entry;
+ phandle_t child;
+ char rnames[256];
+ char *name, *voltage;
+ int len = 0, prop_len;
+
+
+ /* Add the regulators from the list */
+ walker = &regulators[0];
+ while (walker->name != NULL) {
+
+ /* Add the regulator to the list */
+ entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
+ walker->regbase, walker->fixedvoltage,
+ walker->voltages, walker->num_voltages);
+ if (entry == NULL)
+ continue;
+
+ walker++;
+ }
+
+
+ /* Check if the FDT is telling us to set any voltages */
+ child = ofw_bus_get_node(sc->sc_pdev);
+ if (child) {
+
+ prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
+ while (len < prop_len) {
+ name = rnames + len;
+ len += strlen(name) + 1;
+ if ((len >= prop_len) || (name[0] == '\0'))
+ break;
+
+ voltage = rnames + len;
+ len += strlen(voltage) + 1;
+ if (voltage[0] == '\0')
+ break;
+
+ millivolts = strtoul(voltage, NULL, 0);
+
+ LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
+ if (strcmp(entry->name, name) == 0) {
+ twl_vreg_write_regulator_voltage(sc, entry, millivolts);
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (twl_vreg_debug) {
+ LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
+ err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
+ if (!err)
+ device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
+ }
+ }
+
+ return (0);
+}
+
+/**
+ * twl_vreg_init - initialises the list of regulators
+ * @dev: the twl_vreg device
+ *
+ * This function is called as an intrhook once interrupts have been enabled,
+ * this is done so that the driver has the option to enable/disable or set
+ * the voltage level based on settings providied in the FDT.
+ *
+ * LOCKING:
+ * Takes the exclusive lock in the function.
+ */
+static void
+twl_vreg_init(void *dev)
+{
+ struct twl_vreg_softc *sc;
+
+ sc = device_get_softc((device_t)dev);
+
+ TWL_VREG_XLOCK(sc);
+
+ if (twl_is_4030(sc->sc_pdev))
+ twl_vreg_add_regulators(sc, twl4030_regulators);
+ else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
+ twl_vreg_add_regulators(sc, twl6030_regulators);
+
+ TWL_VREG_XUNLOCK(sc);
+
+ config_intrhook_disestablish(&sc->sc_init_hook);
+}
+
+static int
+twl_vreg_probe(device_t dev)
+{
+ if (twl_is_4030(device_get_parent(dev)))
+ device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
+ else if (twl_is_6025(device_get_parent(dev)) ||
+ twl_is_6030(device_get_parent(dev)))
+ device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
+ else
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+twl_vreg_attach(device_t dev)
+{
+ struct twl_vreg_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ sc->sc_pdev = device_get_parent(dev);
+
+ TWL_VREG_LOCK_INIT(sc);
+
+ LIST_INIT(&sc->sc_vreg_list);
+
+ /* We have to wait until interrupts are enabled. I2C read and write
+ * only works if the interrupts are available.
+ */
+ sc->sc_init_hook.ich_func = twl_vreg_init;
+ sc->sc_init_hook.ich_arg = dev;
+
+ if (config_intrhook_establish(&sc->sc_init_hook) != 0)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static int
+twl_vreg_detach(device_t dev)
+{
+ struct twl_vreg_softc *sc;
+ struct twl_regulator_entry *regulator;
+ struct twl_regulator_entry *tmp;
+
+ sc = device_get_softc(dev);
+
+ /* Take the lock and free all the added regulators */
+ TWL_VREG_XLOCK(sc);
+
+ LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
+ LIST_REMOVE(regulator, entries);
+ sysctl_remove_oid(regulator->oid, 1, 0);
+ free(regulator, M_DEVBUF);
+ }
+
+ TWL_VREG_XUNLOCK(sc);
+
+ TWL_VREG_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t twl_vreg_methods[] = {
+ DEVMETHOD(device_probe, twl_vreg_probe),
+ DEVMETHOD(device_attach, twl_vreg_attach),
+ DEVMETHOD(device_detach, twl_vreg_detach),
+
+ {0, 0},
+};
+
+static driver_t twl_vreg_driver = {
+ "twl_vreg",
+ twl_vreg_methods,
+ sizeof(struct twl_vreg_softc),
+};
+
+static devclass_t twl_vreg_devclass;
+
+DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, twl_vreg_devclass, 0, 0);
+MODULE_VERSION(twl_vreg, 1);
diff --git a/sys/arm/ti/twl/twl_vreg.h b/sys/arm/ti/twl/twl_vreg.h
new file mode 100644
index 0000000..dc77dfc
--- /dev/null
+++ b/sys/arm/ti/twl/twl_vreg.h
@@ -0,0 +1,36 @@
+/*-
+ * 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 _TWL_VREG_H_
+#define _TWL_VREG_H_
+
+
+int twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts);
+int twl_vreg_set_voltage(device_t dev, const char *name, int millivolts);
+
+#endif /* _TWL_VREG_H_ */
diff --git a/sys/arm/ti/usb/omap_ehci.c b/sys/arm/ti/usb/omap_ehci.c
new file mode 100644
index 0000000..b216dfb
--- /dev/null
+++ b/sys/arm/ti/usb/omap_ehci.c
@@ -0,0 +1,1024 @@
+/*-
+ * 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.
+ */
+
+/**
+ * Driver for the High Speed USB EHCI module on the TI OMAP3530 SoC.
+ *
+ * WARNING: I've only tried this driver on a limited number of USB peripherals,
+ * it is still very raw and bound to have numerous bugs in it.
+ *
+ * This driver is based on the FreeBSD IXP4xx EHCI driver with a lot of the
+ * setup sequence coming from the Linux community and their EHCI driver for
+ * OMAP. Without these as a base I don't think I would have been able to get
+ * this driver working.
+ *
+ * The driver only contains the EHCI parts, the module also supports OHCI and
+ * USB on-the-go (OTG), currently neither are supported.
+ *
+ * CAUTION: This driver was written to run on the beaglebaord dev board, so I
+ * have made some assumptions about the type of PHY used and some of the other
+ * settings. Bare that in mind if you intend to use this driver on another
+ * platform.
+ *
+ * NOTE: This module uses a few different clocks, one being a 60Mhz clock for
+ * the TTL part of the module. This clock is derived from DPPL5 which must be
+ * configured prior to loading this driver - it is not configured by the
+ * bootloader. It took me a long time to figure this out, and caused much
+ * frustration. This PLL is now setup in the timer/clocks part of the BSP,
+ * check out the omap_prcm_setup_dpll5() function in omap_prcm.c for more info.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+
+#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/rman.h>
+#include <sys/linker_set.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 <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/gpio.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <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/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_scm.h>
+
+#include <arm/ti/usb/omap_usb.h>
+
+#include "gpio_if.h"
+
+struct omap_ehci_softc {
+ ehci_softc_t base; /* storage for EHCI code */
+
+ device_t sc_dev;
+ device_t sc_gpio_dev;
+
+ /* TLL register set */
+ struct resource* tll_mem_res;
+
+ /* UHH register set */
+ struct resource* uhh_mem_res;
+
+ /* The revision of the HS USB HOST read from UHH_REVISION */
+ uint32_t ehci_rev;
+
+ /* The following details are provided by conf hints */
+ int port_mode[3];
+ int phy_reset[3];
+ int reset_gpio_pin[3];
+};
+
+static device_attach_t omap_ehci_attach;
+static device_detach_t omap_ehci_detach;
+static device_shutdown_t omap_ehci_shutdown;
+static device_suspend_t omap_ehci_suspend;
+static device_resume_t omap_ehci_resume;
+
+/**
+ * omap_tll_read_4 - read a 32-bit value from the USBTLL registers
+ * omap_tll_write_4 - write a 32-bit value from the USBTLL registers
+ * omap_tll_readb - read an 8-bit value from the USBTLL registers
+ * omap_tll_writeb - write an 8-bit value from the USBTLL registers
+ * @sc: omap ehci device context
+ * @off: byte offset within the register set to read from
+ * @val: the value to write into the register
+ *
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_tll_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->tll_mem_res, off);
+}
+
+static inline void
+omap_tll_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->tll_mem_res, off, val);
+}
+
+static inline uint8_t
+omap_tll_readb(struct omap_ehci_softc *sc, bus_size_t off)
+{
+ return bus_read_1(sc->tll_mem_res, off);
+}
+
+static inline void
+omap_tll_writeb(struct omap_ehci_softc *sc, bus_size_t off, uint8_t val)
+{
+ bus_write_1(sc->tll_mem_res, off, val);
+}
+
+/**
+ * omap_ehci_read_4 - read a 32-bit value from the EHCI registers
+ * omap_ehci_write_4 - write a 32-bit value from the EHCI registers
+ * @sc: omap ehci device context
+ * @off: byte offset within the register set to read from
+ * @val: the value to write into the register
+ *
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_ehci_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+ return (bus_read_4(sc->base.sc_io_res, off));
+}
+static inline void
+omap_ehci_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->base.sc_io_res, off, val);
+}
+
+/**
+ * omap_uhh_read_4 - read a 32-bit value from the UHH registers
+ * omap_uhh_write_4 - write a 32-bit value from the UHH registers
+ * @sc: omap ehci device context
+ * @off: byte offset within the register set to read from
+ * @val: the value to write into the register
+ *
+ *
+ * LOCKING:
+ * None
+ *
+ * RETURNS:
+ * nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_uhh_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->uhh_mem_res, off);
+}
+static inline void
+omap_uhh_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->uhh_mem_res, off, val);
+}
+
+/**
+ * omap_ehci_utmi_init - initialises the UTMI part of the controller
+ * @isc: omap ehci device context
+ *
+ *
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+omap_ehci_utmi_init(struct omap_ehci_softc *isc, unsigned int en_mask)
+{
+ unsigned int i;
+ uint32_t reg;
+
+ /* There are 3 TLL channels, one per USB controller so set them all up the
+ * same, SDR mode, bit stuffing and no autoidle.
+ */
+ for (i=0; i<3; i++) {
+ reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));
+
+ reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE
+ | TLL_CHANNEL_CONF_ULPINOBITSTUFF
+ | TLL_CHANNEL_CONF_ULPIDDRMODE);
+
+ omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
+ }
+
+ /* Program the common TLL register */
+ reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_SHARED_CONF);
+
+ reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN
+ | TLL_SHARED_CONF_USB_DIVRATIO_MASK);
+ reg |= ( TLL_SHARED_CONF_FCLK_IS_ON
+ | TLL_SHARED_CONF_USB_DIVRATIO_2
+ | TLL_SHARED_CONF_USB_180D_SDR_EN);
+
+ omap_tll_write_4(isc, OMAP_USBTLL_TLL_SHARED_CONF, reg);
+
+ /* Enable channels now */
+ for (i = 0; i < 3; i++) {
+ reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));
+
+ /* Enable only the reg that is needed */
+ if ((en_mask & (1 << i)) == 0)
+ continue;
+
+ reg |= TLL_CHANNEL_CONF_CHANEN;
+ omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
+ }
+}
+
+/**
+ * omap_ehci_soft_phy_reset - resets the phy using the reset command
+ * @isc: omap ehci device context
+ * @port: port to send the reset over
+ *
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * nothing
+ */
+static void
+omap_ehci_soft_phy_reset(struct omap_ehci_softc *isc, unsigned int port)
+{
+ unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+ uint32_t reg;
+
+ reg = ULPI_FUNC_CTRL_RESET
+ /* FUNCTION_CTRL_SET register */
+ | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
+ /* Write */
+ | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
+ /* PORTn */
+ | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
+ /* start ULPI access*/
+ | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
+
+ omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG05_ULPI, reg);
+
+ /* Wait for ULPI access completion */
+ while ((omap_ehci_read_4(isc, OMAP_USBHOST_INSNREG05_ULPI)
+ & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
+
+ /* Sleep for a tick */
+ pause("USBPHY_RESET", 1);
+
+ if (timeout-- == 0) {
+ device_printf(isc->sc_dev, "PHY reset operation timed out\n");
+ break;
+ }
+ }
+}
+
+
+/**
+ * omap_ehci_init - initialises the USB host EHCI controller
+ * @isc: omap ehci device context
+ *
+ * This initialisation routine is quite heavily based on the work done by the
+ * OMAP Linux team (for which I thank them very much). The init sequence is
+ * almost identical, diverging only for the FreeBSD specifics.
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 on success, a negative error code on failure.
+ */
+static int
+omap_ehci_init(struct omap_ehci_softc *isc)
+{
+ unsigned long timeout;
+ int ret = 0;
+ uint8_t tll_ch_mask = 0;
+ uint32_t reg = 0;
+ int reset_performed = 0;
+ int i;
+
+ device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n");
+
+
+ /* Enable Clocks for high speed USBHOST */
+ ti_prcm_clk_enable(USBHSHOST_CLK);
+
+ /* Hold the PHY in reset while configuring */
+ for (int i = 0; i < 3; i++) {
+ if (isc->phy_reset[i]) {
+ /* Configure the GPIO to drive low (hold in reset) */
+ if ((isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) {
+ GPIO_PIN_SETFLAGS(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
+ GPIO_PIN_OUTPUT);
+ GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
+ GPIO_PIN_LOW);
+ reset_performed = 1;
+ }
+ }
+ }
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ if (reset_performed)
+ DELAY(10);
+
+ /* Read the UHH revision */
+ isc->ehci_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION);
+ device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->ehci_rev);
+
+ /* Initilise the low level interface module(s) */
+ if (isc->ehci_rev == OMAP_EHCI_REV1) {
+
+ /* Enable the USB TLL */
+ ti_prcm_clk_enable(USBTLL_CLK);
+
+ /* Perform TLL soft reset, and wait until reset is complete */
+ omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
+
+ /* Set the timeout to 100ms*/
+ timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+
+ /* Wait for TLL reset to complete */
+ while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) &
+ TLL_SYSSTATUS_RESETDONE) == 0x00) {
+
+ /* Sleep for a tick */
+ pause("USBRESET", 1);
+
+ if (timeout-- == 0) {
+ device_printf(isc->sc_dev, "TLL reset operation timed out\n");
+ ret = EINVAL;
+ goto err_sys_status;
+ }
+ }
+
+ device_printf(isc->sc_dev, "TLL RESET DONE\n");
+
+ /* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle
+ * SIDLEMODE = 2 : Smart-idle mode. Sidleack asserted after Idlereq
+ * assertion when no more activity on the USB.
+ * ENAWAKEUP = 1 : Wakeup generation enabled
+ */
+ omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP |
+ TLL_SYSCONFIG_AUTOIDLE |
+ TLL_SYSCONFIG_SIDLE_SMART_IDLE |
+ TLL_SYSCONFIG_CACTIVITY);
+
+ } else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+
+ /* For OMAP44xx devices you have to enable the per-port clocks:
+ * PHY_MODE - External ULPI clock
+ * TTL_MODE - Internal UTMI clock
+ * HSIC_MODE - Internal 480Mhz and 60Mhz clocks
+ */
+ if (isc->ehci_rev == OMAP_EHCI_REV2) {
+ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
+ ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
+ ti_prcm_clk_enable(USBP1_PHY_CLK);
+ } else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+ ti_prcm_clk_enable(USBP1_UTMI_CLK);
+ else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+ ti_prcm_clk_enable(USBP1_HSIC_CLK);
+
+ if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
+ ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
+ ti_prcm_clk_enable(USBP2_PHY_CLK);
+ } else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+ ti_prcm_clk_enable(USBP2_UTMI_CLK);
+ else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+ ti_prcm_clk_enable(USBP2_HSIC_CLK);
+ }
+ }
+
+ /* Put UHH in SmartIdle/SmartStandby mode */
+ reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG);
+ if (isc->ehci_rev == OMAP_EHCI_REV1) {
+ reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
+ UHH_SYSCONFIG_MIDLEMODE_MASK);
+ reg |= (UHH_SYSCONFIG_ENAWAKEUP |
+ UHH_SYSCONFIG_AUTOIDLE |
+ UHH_SYSCONFIG_CLOCKACTIVITY |
+ UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
+ UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
+ } else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+ reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
+ reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE;
+ reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
+ reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
+ }
+ omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg);
+ device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg);
+
+ reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG);
+
+ /* Setup ULPI bypass and burst configurations */
+ reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
+ UHH_HOSTCONFIG_ENA_INCR8 |
+ UHH_HOSTCONFIG_ENA_INCR16);
+ reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
+
+ if (isc->ehci_rev == OMAP_EHCI_REV1) {
+ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+ if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+ if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+ reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+
+ /* Bypass the TLL module for PHY mode operation */
+ if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
+ (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
+ (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
+ reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+ else
+ reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+
+ } else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+ reg |= UHH_HOSTCONFIG_APP_START_CLK;
+
+ /* Clear port mode fields for PHY mode*/
+ reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
+ reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
+
+ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+ reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
+ else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+ reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
+
+ if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+ reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
+ else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+ reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
+ }
+
+ omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
+ device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg);
+
+
+ /* I found the code and comments in the Linux EHCI driver - thanks guys :)
+ *
+ * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended
+ * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared
+ * (for example when we do ehci_bus_suspend). This breaks suspend-resume if
+ * the root-hub is allowed to suspend. Writing 1 to this undocumented
+ * register bit disables this feature and restores normal behavior."
+ */
+#if 0
+ omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG04,
+ OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND);
+#endif
+
+ /* If any of the ports are configured in TLL mode, enable them */
+ if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
+ (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
+ (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {
+
+ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+ tll_ch_mask |= 0x1;
+ if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+ tll_ch_mask |= 0x2;
+ if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
+ tll_ch_mask |= 0x4;
+
+ /* Enable UTMI mode for required TLL channels */
+ omap_ehci_utmi_init(isc, tll_ch_mask);
+ }
+
+
+ /* Release the PHY reset signal now we have configured everything */
+ if (reset_performed) {
+
+ /* Delay for 10ms */
+ DELAY(10000);
+
+ for (i = 0; i < 3; i++) {
+ /* Release reset */
+
+ if (isc->phy_reset[i] && (isc->reset_gpio_pin[i] != -1)
+ && (isc->sc_gpio_dev != NULL)) {
+ GPIO_PIN_SET(isc->sc_gpio_dev,
+ isc->reset_gpio_pin[i], GPIO_PIN_HIGH);
+ }
+ }
+ }
+
+ /* Set the interrupt threshold control, it controls the maximum rate at
+ * which the host controller issues interrupts. We set it to 1 microframe
+ * at startup - the default is 8 mircoframes (equates to 1ms).
+ */
+ reg = omap_ehci_read_4(isc, OMAP_USBHOST_USBCMD);
+ reg &= 0xff00ffff;
+ reg |= (1 << 16);
+ omap_ehci_write_4(isc, OMAP_USBHOST_USBCMD, reg);
+
+ /* Soft reset the PHY using PHY reset command over ULPI */
+ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
+ omap_ehci_soft_phy_reset(isc, 0);
+ if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
+ omap_ehci_soft_phy_reset(isc, 1);
+
+ return(0);
+
+err_sys_status:
+
+ /* Disable the TLL clocks */
+ ti_prcm_clk_disable(USBTLL_CLK);
+
+ /* Disable Clocks for USBHOST */
+ ti_prcm_clk_disable(USBHSHOST_CLK);
+
+ return(ret);
+}
+
+
+/**
+ * omap_ehci_fini - shutdown the EHCI controller
+ * @isc: omap ehci device context
+ *
+ *
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 on success, a negative error code on failure.
+ */
+static void
+omap_ehci_fini(struct omap_ehci_softc *isc)
+{
+ unsigned long timeout;
+
+ device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n");
+
+ /* Set the timeout */
+ if (hz < 10)
+ timeout = 1;
+ else
+ timeout = (100 * hz) / 1000;
+
+ /* Reset the UHH, OHCI and EHCI modules */
+ omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, 0x0002);
+ while ((omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) {
+ /* Sleep for a tick */
+ pause("USBRESET", 1);
+
+ if (timeout-- == 0) {
+ device_printf(isc->sc_dev, "operation timed out\n");
+ break;
+ }
+ }
+
+
+ /* Set the timeout */
+ if (hz < 10)
+ timeout = 1;
+ else
+ timeout = (100 * hz) / 1000;
+
+ /* Reset the TLL module */
+ omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, 0x0002);
+ while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) {
+ /* Sleep for a tick */
+ pause("USBRESET", 1);
+
+ if (timeout-- == 0) {
+ device_printf(isc->sc_dev, "operation timed out\n");
+ break;
+ }
+ }
+
+
+ /* Disable functional and interface clocks for the TLL and HOST modules */
+ ti_prcm_clk_disable(USBTLL_CLK);
+ ti_prcm_clk_disable(USBHSHOST_CLK);
+
+ device_printf(isc->sc_dev, "Clock to USB host has been disabled\n");
+
+}
+
+
+
+/**
+ * omap_ehci_suspend - suspends the bus
+ * @dev: omap ehci device
+ *
+ * Effectively boilerplate EHCI suspend code.
+ *
+ * TODO: There is a lot more we could do here - i.e. force the controller into
+ * idle mode and disable all the clocks for start.
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 on success or a positive error code
+ */
+static int
+omap_ehci_suspend(device_t dev)
+{
+ ehci_softc_t *sc = device_get_softc(dev);
+ int err;
+
+ sc = sc;
+ err = bus_generic_suspend(dev);
+ if (err)
+ return (err);
+ return (0);
+}
+
+
+/**
+ * omap_ehci_resume - resumes a suspended bus
+ * @dev: omap ehci device
+ *
+ * Effectively boilerplate EHCI resume code.
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 on success or a positive error code on failure
+ */
+static int
+omap_ehci_resume(device_t dev)
+{
+ ehci_softc_t *sc = device_get_softc(dev);
+ sc = sc;
+
+ bus_generic_resume(dev);
+
+ return (0);
+}
+
+
+/**
+ * omap_ehci_shutdown - starts the given command
+ * @dev:
+ *
+ * Effectively boilerplate EHCI shutdown code.
+ *
+ * LOCKING:
+ * none.
+ *
+ * RETURNS:
+ * 0 on success or a positive error code on failure
+ */
+static int
+omap_ehci_shutdown(device_t dev)
+{
+ ehci_softc_t *sc = device_get_softc(dev);
+ int err;
+
+ sc = sc;
+ err = bus_generic_shutdown(dev);
+ if (err)
+ return (err);
+
+ return (0);
+}
+
+
+/**
+ * omap_ehci_probe - starts the given command
+ * @dev:
+ *
+ * Effectively boilerplate EHCI resume code.
+ *
+ * LOCKING:
+ * Caller should be holding the OMAP3_MMC lock.
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+omap_ehci_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "ti,usb-ehci"))
+ return (ENXIO);
+
+ device_set_desc(dev, OMAP_EHCI_HC_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ * omap_ehci_attach - driver entry point, sets up the ECHI controller/driver
+ * @dev: the new device handle
+ *
+ * Sets up bus spaces, interrupt handles, etc for the EHCI controller. It also
+ * parses the resource hints and calls omap_ehci_init() to initialise the
+ * H/W.
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * 0 on success or a positive error code on failure.
+ */
+static int
+omap_ehci_attach(device_t dev)
+{
+ struct omap_ehci_softc *isc = device_get_softc(dev);
+ phandle_t node;
+ /* 3 ports with 3 cells per port */
+ pcell_t phyconf[3 * 3];
+ pcell_t *phyconf_ptr;
+ ehci_softc_t *sc = &isc->base;
+ int err;
+ int rid;
+ int len, tuple_size;
+ int i;
+
+ /* initialise some bus fields */
+ sc->sc_bus.parent = dev;
+ sc->sc_bus.devices = sc->sc_devices;
+ sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+
+ /* save the device */
+ isc->sc_dev = dev;
+
+ /* get all DMA memory */
+ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev),
+ &ehci_iterate_hw_softc)) {
+ return (ENOMEM);
+ }
+
+ /* When the EHCI driver is added to the tree it is expected that 3
+ * memory resources and 1 interrupt resource is assigned. The memory
+ * resources should be:
+ * 0 => EHCI register range
+ * 1 => UHH register range
+ * 2 => TLL register range
+ *
+ * The interrupt resource is just the single interupt for the controller.
+ */
+
+ /* Allocate resource for the EHCI register set */
+ rid = 0;
+ sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!sc->sc_io_res) {
+ device_printf(dev, "Error: Could not map EHCI memory\n");
+ goto error;
+ }
+ /* Request an interrupt resource */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+ if (sc->sc_irq_res == NULL) {
+ device_printf(dev, "Error: could not allocate irq\n");
+ goto error;
+ }
+
+ /* Allocate resource for the UHH register set */
+ rid = 1;
+ isc->uhh_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!isc->uhh_mem_res) {
+ device_printf(dev, "Error: Could not map UHH memory\n");
+ goto error;
+ }
+ /* Allocate resource for the TLL register set */
+ rid = 2;
+ isc->tll_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!isc->tll_mem_res) {
+ device_printf(dev, "Error: Could not map TLL memory\n");
+ goto error;
+ }
+
+ /* Add this device as a child of the USBus device */
+ sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
+ if (!sc->sc_bus.bdev) {
+ device_printf(dev, "Error: could not add USB device\n");
+ goto error;
+ }
+
+ device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+ device_set_desc(sc->sc_bus.bdev, OMAP_EHCI_HC_DEVSTR);
+
+ /* Set the vendor name */
+ sprintf(sc->sc_vendor, "Texas Instruments");
+
+ /* Get the GPIO device, we may need this if the driver needs to toggle
+ * some pins for external PHY resets.
+ */
+ isc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
+ if (isc->sc_gpio_dev == NULL) {
+ device_printf(dev, "Error: failed to get the GPIO device\n");
+ goto error;
+ }
+
+ /* Set the defaults for the hints */
+ for (i = 0; i < 3; i++) {
+ isc->phy_reset[i] = 0;
+ isc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
+ isc->reset_gpio_pin[i] = -1;
+ }
+
+ tuple_size = sizeof(pcell_t) * 3;
+ node = ofw_bus_get_node(dev);
+ len = OF_getprop(node, "phy-config", phyconf, sizeof(phyconf));
+ if (len > 0) {
+ if (len % tuple_size)
+ goto error;
+ if ((len / tuple_size) != 3)
+ goto error;
+
+ phyconf_ptr = phyconf;
+ for (i = 0; i < 3; i++) {
+ isc->port_mode[i] = fdt32_to_cpu(*phyconf_ptr);
+ isc->phy_reset[i] = fdt32_to_cpu(*(phyconf_ptr + 1));
+ isc->reset_gpio_pin[i] = fdt32_to_cpu(*(phyconf_ptr + 2));
+
+ phyconf_ptr += 3;
+ }
+ }
+
+ /* Initialise the ECHI registers */
+ err = omap_ehci_init(isc);
+ if (err) {
+ device_printf(dev, "Error: could not setup OMAP EHCI, %d\n", err);
+ goto error;
+ }
+
+
+ /* Set the tag and size of the register set in the EHCI context */
+ sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
+ sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+ sc->sc_io_size = rman_get_size(sc->sc_io_res);
+
+
+ /* Setup the interrupt */
+ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+ NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+ if (err) {
+ device_printf(dev, "Error: could not setup irq, %d\n", err);
+ sc->sc_intr_hdl = NULL;
+ goto error;
+ }
+
+
+ /* Finally we are ready to kick off the ECHI host controller */
+ err = ehci_init(sc);
+ if (err == 0) {
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
+ if (err) {
+ device_printf(dev, "Error: USB init failed err=%d\n", err);
+ goto error;
+ }
+
+ return (0);
+
+error:
+ omap_ehci_detach(dev);
+ return (ENXIO);
+}
+
+/**
+ * omap_ehci_detach - detach the device and cleanup the driver
+ * @dev: device handle
+ *
+ * Clean-up routine where everything initialised in omap_ehci_attach is
+ * freed and cleaned up. This function calls omap_ehci_fini() to shutdown
+ * the on-chip module.
+ *
+ * LOCKING:
+ * none
+ *
+ * RETURNS:
+ * Always returns 0 (success).
+ */
+static int
+omap_ehci_detach(device_t dev)
+{
+ struct omap_ehci_softc *isc = device_get_softc(dev);
+ ehci_softc_t *sc = &isc->base;
+ device_t bdev;
+ int err;
+
+ if (sc->sc_bus.bdev) {
+ bdev = sc->sc_bus.bdev;
+ device_detach(bdev);
+ device_delete_child(dev, bdev);
+ }
+
+ /* during module unload there are lots of children leftover */
+ device_delete_children(dev);
+
+ /*
+ * disable interrupts that might have been switched on in ehci_init
+ */
+ if (sc->sc_io_res) {
+ EWRITE4(sc, EHCI_USBINTR, 0);
+ }
+
+ if (sc->sc_irq_res && sc->sc_intr_hdl) {
+ /*
+ * only call ehci_detach() after ehci_init()
+ */
+ ehci_detach(sc);
+
+ err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
+ if (err)
+ device_printf(dev, "Error: could not tear down irq, %d\n", err);
+ sc->sc_intr_hdl = NULL;
+ }
+
+ /* Free the resources stored in the base EHCI handler */
+ if (sc->sc_irq_res) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ sc->sc_irq_res = NULL;
+ }
+ if (sc->sc_io_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res);
+ sc->sc_io_res = NULL;
+ }
+
+ /* Release the other register set memory maps */
+ if (isc->tll_mem_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->tll_mem_res);
+ isc->tll_mem_res = NULL;
+ }
+ if (isc->uhh_mem_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->uhh_mem_res);
+ isc->uhh_mem_res = NULL;
+ }
+
+ usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+
+ omap_ehci_fini(isc);
+
+ return (0);
+}
+
+static device_method_t ehci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, omap_ehci_probe),
+ DEVMETHOD(device_attach, omap_ehci_attach),
+ DEVMETHOD(device_detach, omap_ehci_detach),
+ DEVMETHOD(device_suspend, omap_ehci_suspend),
+ DEVMETHOD(device_resume, omap_ehci_resume),
+ DEVMETHOD(device_shutdown, omap_ehci_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0}
+};
+
+static driver_t ehci_driver = {
+ "ehci",
+ ehci_methods,
+ sizeof(struct omap_ehci_softc),
+};
+
+static devclass_t ehci_devclass;
+
+DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
diff --git a/sys/arm/ti/usb/omap_usb.h b/sys/arm/ti/usb/omap_usb.h
new file mode 100644
index 0000000..bea7957
--- /dev/null
+++ b/sys/arm/ti/usb/omap_usb.h
@@ -0,0 +1,264 @@
+/*
+ * 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 _OMAP_USB_H_
+#define _OMAP_USB_H_
+
+/*
+ * USB TTL Module
+ */
+#define OMAP_USBTLL_REVISION 0x0000
+#define OMAP_USBTLL_SYSCONFIG 0x0010
+#define OMAP_USBTLL_SYSSTATUS 0x0014
+#define OMAP_USBTLL_IRQSTATUS 0x0018
+#define OMAP_USBTLL_IRQENABLE 0x001C
+#define OMAP_USBTLL_TLL_SHARED_CONF 0x0030
+#define OMAP_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i)))
+#define OMAP_USBTLL_SAR_CNTX(i) (0x0400 + (0x04 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i)))
+#define OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i)))
+
+
+/*
+ * USB Host Module
+ */
+
+/* UHH */
+#define OMAP_USBHOST_UHH_REVISION 0x0000
+#define OMAP_USBHOST_UHH_SYSCONFIG 0x0010
+#define OMAP_USBHOST_UHH_SYSSTATUS 0x0014
+#define OMAP_USBHOST_UHH_HOSTCONFIG 0x0040
+#define OMAP_USBHOST_UHH_DEBUG_CSR 0x0044
+
+/* EHCI */
+#define OMAP_USBHOST_HCCAPBASE 0x0000
+#define OMAP_USBHOST_HCSPARAMS 0x0004
+#define OMAP_USBHOST_HCCPARAMS 0x0008
+#define OMAP_USBHOST_USBCMD 0x0010
+#define OMAP_USBHOST_USBSTS 0x0014
+#define OMAP_USBHOST_USBINTR 0x0018
+#define OMAP_USBHOST_FRINDEX 0x001C
+#define OMAP_USBHOST_CTRLDSSEGMENT 0x0020
+#define OMAP_USBHOST_PERIODICLISTBASE 0x0024
+#define OMAP_USBHOST_ASYNCLISTADDR 0x0028
+#define OMAP_USBHOST_CONFIGFLAG 0x0050
+#define OMAP_USBHOST_PORTSC(i) (0x0054 + (0x04 * (i)))
+#define OMAP_USBHOST_INSNREG00 0x0090
+#define OMAP_USBHOST_INSNREG01 0x0094
+#define OMAP_USBHOST_INSNREG02 0x0098
+#define OMAP_USBHOST_INSNREG03 0x009C
+#define OMAP_USBHOST_INSNREG04 0x00A0
+#define OMAP_USBHOST_INSNREG05_UTMI 0x00A4
+#define OMAP_USBHOST_INSNREG05_ULPI 0x00A4
+#define OMAP_USBHOST_INSNREG06 0x00A8
+#define OMAP_USBHOST_INSNREG07 0x00AC
+#define OMAP_USBHOST_INSNREG08 0x00B0
+
+#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND (1 << 5)
+
+#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT 31
+#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT 24
+#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT 22
+#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT 16
+#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8
+#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT 0
+
+
+
+
+
+/* TLL Register Set */
+#define TLL_SYSCONFIG_CACTIVITY (1UL << 8)
+#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3)
+#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3)
+#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3)
+#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2)
+#define TLL_SYSCONFIG_SOFTRESET (1UL << 1)
+#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0)
+
+#define TLL_SYSSTATUS_RESETDONE (1UL << 0)
+
+#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6)
+#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5)
+#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2)
+#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1)
+#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0)
+
+#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16)
+#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15)
+#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11)
+#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10)
+#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9)
+#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8)
+#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7)
+#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6)
+#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5)
+#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4)
+#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3)
+#define TLL_CHANNEL_CONF_CHANEN (1UL << 0)
+
+
+/* UHH Register Set */
+#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12)
+#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8)
+#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3)
+#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2)
+#define UHH_SYSCONFIG_SOFTRESET (1UL << 1)
+#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0)
+
+#define UHH_HOSTCONFIG_APP_START_CLK (1UL << 31)
+#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10)
+#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9)
+#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8)
+#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5)
+#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4)
+#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3)
+#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2)
+#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1)
+#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0)
+
+/* The following are on rev2 (OMAP44xx) of the EHCI only */
+#define UHH_SYSCONFIG_IDLEMODE_MASK (3UL << 2)
+#define UHH_SYSCONFIG_IDLEMODE_NOIDLE (1UL << 2)
+#define UHH_SYSCONFIG_STANDBYMODE_MASK (3UL << 4)
+#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY (1UL << 4)
+
+#define UHH_HOSTCONFIG_P1_MODE_MASK (3UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY (0UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY (1UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_HSIC (3UL << 16)
+#define UHH_HOSTCONFIG_P2_MODE_MASK (3UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY (0UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY (1UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_HSIC (3UL << 18)
+
+#define ULPI_FUNC_CTRL_RESET (1 << 5)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Macros for Set and Clear
+ * See ULPI 1.1 specification to find the registers with Set and Clear offsets
+ */
+#define ULPI_SET(a) (a + 1)
+#define ULPI_CLR(a) (a + 2)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Register Map
+ */
+#define ULPI_VENDOR_ID_LOW 0x00
+#define ULPI_VENDOR_ID_HIGH 0x01
+#define ULPI_PRODUCT_ID_LOW 0x02
+#define ULPI_PRODUCT_ID_HIGH 0x03
+#define ULPI_FUNC_CTRL 0x04
+#define ULPI_IFC_CTRL 0x07
+#define ULPI_OTG_CTRL 0x0a
+#define ULPI_USB_INT_EN_RISE 0x0d
+#define ULPI_USB_INT_EN_FALL 0x10
+#define ULPI_USB_INT_STS 0x13
+#define ULPI_USB_INT_LATCH 0x14
+#define ULPI_DEBUG 0x15
+#define ULPI_SCRATCH 0x16
+
+/*
+ * Values of UHH_REVISION - Note: these are not given in the TRM but taken
+ * from the linux OMAP EHCI driver (thanks guys). It has been verified on
+ * a Panda and Beagle board.
+ */
+#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */
+#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */
+
+#define EHCI_VENDORID_OMAP3 0x42fa05
+#define OMAP_EHCI_HC_DEVSTR "TI OMAP USB 2.0 controller"
+
+#define EHCI_HCD_OMAP_MODE_UNKNOWN 0
+#define EHCI_HCD_OMAP_MODE_PHY 1
+#define EHCI_HCD_OMAP_MODE_TLL 2
+#define EHCI_HCD_OMAP_MODE_HSIC 3
+
+#endif /* _OMAP_USB_H_ */
diff --git a/sys/boot/fdt/dts/beaglebone.dts b/sys/boot/fdt/dts/beaglebone.dts
new file mode 100644
index 0000000..2c68021
--- /dev/null
+++ b/sys/boot/fdt/dts/beaglebone.dts
@@ -0,0 +1,197 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/dts-v1/;
+
+/ {
+ model = "beaglebone";
+ compatible = "beaglebone", "ti,am335x";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ interrupt-parent = <&AINTC>;
+
+ aliases {
+ soc = &SOC;
+ uart0 = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = < 0x80000000 0x10000000 >; /* 256MB RAM */
+ };
+
+ SOC: am335x {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+ bus-frequency = <0>;
+
+ AINTC: interrupt-controller@48200000 {
+ compatible = "ti,aintc";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = < 0x48200000 0x1000 >;
+ };
+
+ scm@44e10000 {
+ compatible = "ti,scm";
+ reg = < 0x44e10000 0x2000 >;
+ /* Set of triplets < padname, muxname, padstate> */
+ scm-pad-config =
+ /* I2C0 */
+ "I2C0_SDA", "I2C0_SDA","i2c",
+ "I2C0_SCL", "I2C0_SCL","i2c",
+ /* Ethernet */
+ "MII1_RX_ER", "gmii1_rxerr", "input_pulldown",
+ "MII1_TX_EN", "gmii1_txen", "output",
+ "MII1_RX_DV", "gmii1_rxdv", "input_pulldown",
+ "MII1_TXD3", "gmii1_txd3", "output",
+ "MII1_TXD2", "gmii1_txd2", "output",
+ "MII1_TXD1", "gmii1_txd1", "output",
+ "MII1_TXD0", "gmii1_txd0", "output",
+ "MII1_TX_CLK", "gmii1_txclk", "input_pulldown",
+ "MII1_RX_CLK", "gmii1_rxclk", "input_pulldown",
+ "MII1_RXD3", "gmii1_rxd3", "input_pulldown",
+ "MII1_RXD2", "gmii1_rxd2", "input_pulldown",
+ "MII1_RXD1", "gmii1_rxd1", "input_pulldown",
+ "MII1_RXD0", "gmii1_rxd0", "input_pulldown",
+ "MDIO", "mdio_data", "input_pullup",
+ "MDC", "mdio_clk", "output_pullup",
+ /* MMCSD0 */
+ "MMC0_CMD", "mmc0_cmd", "input_pullup",
+ "MMC0_CLK", "mmc0_clk", "input_pullup",
+ "MMC0_DAT0", "mmc0_dat0", "input_pullup",
+ "MMC0_DAT1", "mmc0_dat1", "input_pullup",
+ "MMC0_DAT2", "mmc0_dat2", "input_pullup",
+ "MMC0_DAT3", "mmc0_dat3", "input_pullup";
+ };
+
+ prcm@44E00000 {
+ compatible = "am335x,prcm";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = < 0x44E00000 0x1300 >;
+ };
+
+ dmtimers@44E05000 {
+ compatible = "ti,am335x-dmtimer";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = < 0x44E05000 0x1000
+ 0x44E31000 0x1000
+ 0x48040000 0x1000
+ 0x48042000 0x1000
+ 0x48044000 0x1000
+ 0x48046000 0x1000
+ 0x48048000 0x1000
+ 0x4804A000 0x1000 >;
+ interrupts = < 66 67 68 69 92 93 94 95 >;
+ interrupt-parent = <&AINTC>;
+ };
+
+ GPIO: gpio {
+ #gpio-cells = <3>;
+ compatible = "ti,gpio";
+ gpio-controller;
+ reg =< 0x44E07000 0x1000
+ 0x4804C000 0x1000
+ 0x481AC000 0x1000
+ 0x481AE000 0x1000 >;
+ interrupts = < 17 19 21 23 >;
+ interrupt-parent = <&AINTC>;
+ };
+
+
+ uart0: serial@44E09000 {
+ compatible = "ns16550";
+ reg = <0x44E09000 0x1000>;
+ reg-shift = <2>;
+ interrupts = < 72 >;
+ interrupt-parent = <&AINTC>;
+ clock-frequency = < 48000000 >; /* FIXME */
+ };
+
+ edma3@49000000 {
+ compatible = "ti,edma3";
+ reg =< 0x49000000 0x100000 /* Channel Controller Regs */
+ 0x49800000 0x100000 /* Transfer Controller 0 Regs */
+ 0x49900000 0x100000 /* Transfer Controller 1 Regs */
+ 0x49a00000 0x100000 >; /* Transfer Controller 2 Regs */
+ interrupts = <12 13 14>;
+ interrupt-parent = <&AINTC>;
+ };
+
+ mmchs0@4809C000 {
+ compatible = "ti,mmchs";
+ reg =<0x48060000 0x1000 >;
+ interrupts = <64>;
+ interrupt-parent = <&AINTC>;
+ mmchs-device-id = <0>;
+ };
+
+ enet0: ethernet@4A100000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ti,cpsw";
+ reg = <0x4A100000 0x3000>;
+ interrupts = <40 41 42 43>;
+ interrupt-parent = <&AINTC>;
+ phy-handle = <&phy0>;
+ mdio@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,cpsw-mdio";
+ phy0: ethernet-phy@0 {
+ reg = <0x0>;
+ };
+ };
+ };
+
+ i2c0: i2c@44e0b000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,i2c";
+ reg =< 0x44e0b000 0x1000 >;
+ interrupts = <70>;
+ interrupt-parent = <&AINTC>;
+ i2c-device-id = <0>;
+ pmic@24 {
+ compatible = "ti,am335x-pmic";
+ reg = <0x24>;
+ };
+ };
+ };
+
+ chosen {
+ stdin = "uart0";
+ stdout = "uart0";
+ };
+};
diff --git a/sys/boot/fdt/dts/pandaboard.dts b/sys/boot/fdt/dts/pandaboard.dts
new file mode 100644
index 0000000..0f262b1
--- /dev/null
+++ b/sys/boot/fdt/dts/pandaboard.dts
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Developed by Damjan Marion <damjan.marion@gmail.com>
+ *
+ * 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$
+ */
+
+/dts-v1/;
+
+/ {
+ model = "pandaboard";
+ compatible = "pandaboard", "ti,omap4430";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ interrupt-parent = <&GIC>;
+
+ aliases {
+ soc = &SOC;
+ uart3 = &uart3;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = < 0x80000000 0x40000000 >; /* 1GB RAM at 0x0 */
+ };
+
+ SOC: omap4430 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+ bus-frequency = <0>;
+
+ GIC: interrupt-controller@48241000 {
+ compatible = "arm,gic";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = < 0x48241000 0x1000 >, /* Distributor Registers */
+ < 0x48240100 0x0100 >; /* CPU Interface Registers */
+ };
+
+ pl310@48242000 {
+ compatible = "arm,pl310";
+ reg = < 0x48242000 0x1000 >;
+ };
+ mp_tmr@48240200 {
+ compatible = "arm,mpcore-timers";
+ clock-frequency = < 504000000 >;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = < 0x48240200 0x100 >, /* Global Timer Registers */
+ < 0x48240600 0x100 >; /* Private Timer Registers */
+ interrupts = < 27 29 >;
+ interrupt-parent = < &GIC >;
+ };
+
+ uart3: serial@48020000 {
+ compatible = "ns16550";
+ reg = <0x48020000 0x1000>;
+ reg-shift = <2>;
+ interrupts = < 106 >;
+ interrupt-parent = <&GIC>;
+ clock-frequency = < 48000000 >; /* 48Mhz clock for all uarts */
+ /* (techref 17.3.1.1) */
+ };
+
+ scm@4a100000 {
+ compatible = "ti,scm";
+ reg = < 0x4a100000 0x1000 >;
+ /* Set of triplets < padname, muxname, padstate> */
+ scm-pad-config =
+ "ag19", "usbb1_ulpiphy_stp", "output",
+ "ae18", "usbb1_ulpiphy_clk", "input_pulldown",
+ "af19", "usbb1_ulpiphy_dir", "input_pulldown",
+ "ae19", "usbb1_ulpiphy_nxt", "input_pulldown",
+ "af18", "usbb1_ulpiphy_dat0", "input_pulldown",
+ "ag18", "usbb1_ulpiphy_dat1", "input_pulldown",
+ "ae17", "usbb1_ulpiphy_dat2", "input_pulldown",
+ "af17", "usbb1_ulpiphy_dat3", "input_pulldown",
+ "ah17", "usbb1_ulpiphy_dat4", "input_pulldown",
+ "ae16", "usbb1_ulpiphy_dat5", "input_pulldown",
+ "af16", "usbb1_ulpiphy_dat6", "input_pulldown",
+ "ag16", "usbb1_ulpiphy_dat7", "input_pulldown";
+ };
+
+ omap4_prcm@4a306000 {
+ compatible = "ti,omap4_prcm";
+ reg =< 0x4a306000 0x2000
+ 0x4a004000 0x1000
+ 0x4a008000 0x8000>;
+ };
+
+ GPIO: gpio {
+ #gpio-cells = <3>;
+ compatible = "ti,gpio";
+ gpio-controller;
+ reg =< 0x4a310000 0x1000
+ 0x48055000 0x1000
+ 0x48057000 0x1000
+ 0x48059000 0x1000
+ 0x4805b000 0x1000
+ 0x4805d000 0x1000>;
+ interrupts = <61 62 63 64 65 66>;
+ interrupt-parent = <&GIC>;
+ };
+
+ ehci {
+ compatible = "ti,usb-ehci", "usb-ehci";
+ /*
+ * USB port PHY configuration is a tuple: <mode, reset, gpio_pin>
+ * mode is one of the following values:
+ * 0 - unknown
+ * 1 - PHY
+ * 2 - TLL
+ * 3 - HSIC
+ *
+ * reset indicates (if non-zero) if port reset is required
+ * gpio_pin - GPIO pin that is used to perform reset
+ */
+ phy-config = < 1 0 0
+ 0 0 0
+ 0 0 0>;
+ reg = < 0x4a064c00 0x100 /* EHCI regs */
+ 0x4a064000 0x700 /* UHH regs */
+ 0x4a062000 0x1000>; /* TLL regs */
+ interrupts = <109>;
+ interrupt-parent = <&GIC>;
+ };
+
+ I2C1: i2c@x48070000 {
+ compatible = "ti,i2c";
+ reg =< 0x48070000 0x100 >;
+ interrupts = <88>;
+ interrupt-parent = <&GIC>;
+ i2c-device-id = <1>;
+ };
+
+ sdma@x48070000 {
+ compatible = "ti,sdma";
+ reg =< 0x4A056000 0x1000 >;
+ interrupts = <44 45 46 47>;
+ interrupt-parent = <&GIC>;
+ };
+
+ mmc@x4809C000 {
+ compatible = "ti,mmchs";
+ reg =<0x4809C000 0x1000 >;
+ interrupts = <115>;
+ interrupt-parent = <&GIC>;
+ mmchs-device-id = <1>;
+ };
+
+ };
+
+ chosen {
+ stdin = "uart3";
+ stdout = "uart3";
+ };
+};
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index 77be79a..a63d501 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -1730,5 +1730,6 @@ static driver_t mmc_driver = {
};
static devclass_t mmc_devclass;
+DRIVER_MODULE(mmc, ti_mmchs, mmc_driver, mmc_devclass, NULL, NULL);
DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL);
DRIVER_MODULE(mmc, sdhci, mmc_driver, mmc_devclass, NULL, NULL);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 9922d62..ee13588 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -72,6 +72,7 @@ SUBDIR= \
${_coff} \
${_coretemp} \
${_cp} \
+ ${_cpsw} \
${_cpuctl} \
${_cpufreq} \
${_crypto} \
@@ -735,6 +736,7 @@ _zfs= zfs
.if ${MACHINE_CPUARCH} == "arm"
_cfi= cfi
+_cpsw= cpsw
.endif
.if ${MACHINE_CPUARCH} == "ia64"
diff --git a/sys/modules/cpsw/Makefile b/sys/modules/cpsw/Makefile
new file mode 100644
index 0000000..508fb03
--- /dev/null
+++ b/sys/modules/cpsw/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../arm/ti/cpsw
+
+KMOD= if_cpsw
+SRCS= if_cpsw.c device_if.h bus_if.h ofw_bus_if.h miibus_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud