[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/omap3/cpu_early_init.S b/src/bsp/lk/platform/omap3/cpu_early_init.S
new file mode 100644
index 0000000..ca026bc
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/cpu_early_init.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+.text
+.globl __cpu_early_init
+
+__cpu_early_init:
+	/* do an omap3 specific setup of the L2 */	
+	mov		r12, #1
+	.word	0xe1600070
+	bx		lr
\ No newline at end of file
diff --git a/src/bsp/lk/platform/omap3/debug.c b/src/bsp/lk/platform/omap3/debug.c
new file mode 100644
index 0000000..0ba711d
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/debug.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdarg.h>
+#include <reg.h>
+#include <debug.h>
+#include <stdio.h>
+#include <kernel/thread.h>
+#include <platform/debug.h>
+#include <arch/ops.h>
+#include <dev/uart.h>
+#include <target/debugconfig.h>
+
+void platform_dputc(char c)
+{
+	if (c == '\n')
+		uart_putc(DEBUG_UART, '\r');
+	uart_putc(DEBUG_UART, c);
+}
+
+int platform_dgetc(char *c, bool wait)
+{
+	int _c;
+
+	if ((_c = uart_getc(DEBUG_UART, false)) < 0)
+		return -1;
+
+	*c = _c;
+	return 0;
+}
+
diff --git a/src/bsp/lk/platform/omap3/i2c.c b/src/bsp/lk/platform/omap3/i2c.c
new file mode 100644
index 0000000..2a30979
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/i2c.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <trace.h>
+#include <err.h>
+#include <reg.h>
+#include <string.h>
+#include <dev/i2c.h>
+#include <platform.h>
+#include <platform/omap3.h>
+
+#define LOCAL_TRACE 0
+
+#define I2C_TIMEOUT 200
+
+static const addr_t i2c_reg_base[] = {
+	I2C1_BASE,
+	I2C2_BASE,
+	I2C3_BASE,
+};
+
+#define I2C_REG_ADDR(bus, reg) (i2c_reg_base[bus] + (reg))
+#define I2C_REG(bus, reg) (*REG16(I2C_REG_ADDR(bus, reg)))
+#define I2C_RMW_REG(bus, reg, startbit, width, val) RMWREG16(I2C_REG_ADDR(bus, reg), startbit, width, val)
+
+static void i2c_dump_bus(int bus)
+{
+	hexdump((void *)i2c_reg_base[bus], 128);
+}
+
+static void i2c_reset_bus(int bus)
+{
+	I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled
+
+	/* reset the bus */
+	I2C_REG(bus, I2C_SYSC) = (1<<1);
+	I2C_REG(bus, I2C_CON) = (1<<15); // enable the bus
+	while ((I2C_REG(bus, I2C_SYSS) & 1) == 0)
+		;
+
+	/* disable the bus again and set up some internals */
+	I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled
+
+	/* set up the clock */
+	I2C_REG(bus, I2C_PSC) = 23; // 96Mhz / 23 == 4Mhz
+	I2C_REG(bus, I2C_SCLL) = 13;
+	I2C_REG(bus, I2C_SCLH) = 15; // 4Mhz / combined divider of 40 (13+7 + 15+5) == 100khz
+
+	/* slave address */
+	I2C_REG(bus, I2C_OA0) = 1; // XXX made this up
+
+	/* fifo is set to 1 byte trigger */
+	I2C_REG(bus, I2C_BUF) = 0;
+
+	/* disable all interrupts */
+	I2C_REG(bus, I2C_IE) = 0;
+
+	/* enable the bus */
+	I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9); // enable, master, transmitter mode
+}
+
+static void i2c_wait_for_bb(int bus)
+{
+	I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
+	while (I2C_REG(bus, I2C_STAT) & (1<<12)) {
+		I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
+	}
+	I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
+}
+
+status_t i2c_transmit(int bus, uint8_t address, const void *buf, size_t count)
+{
+	status_t err;
+
+	LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count);
+
+	i2c_wait_for_bb(bus);
+
+	I2C_REG(bus, I2C_SA) = address;
+	I2C_REG(bus, I2C_CNT) = count;
+	I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9)|(1<<1)|(1<<0); // enable, master, transmit, STP, STT
+
+	lk_time_t t = current_time();
+
+	const uint8_t *ptr = (const uint8_t *)buf;
+	for (;;) {
+		uint16_t stat = I2C_REG(bus, I2C_STAT);
+		if (stat & (1<<1)) {
+			// NACK
+//			printf("NACK\n");
+			err = ERR_GENERIC;
+			goto out;
+		}
+		if (stat & (1<<0)) {
+			// AL (arbitration lost)
+//			printf("arbitration lost!\n");
+			err = ERR_GENERIC;
+			goto out;
+		}
+		if (stat & (1<<2)) {
+			// ARDY
+//			printf("ARDY, completed\n");
+			break;
+		}
+		if (stat & (1<<4)) {
+			// RRDY
+//			printf("XRDY\n");
+
+			// transmit a byte
+			*REG8(I2C_REG_ADDR(bus, I2C_DATA)) = *ptr;
+			ptr++;
+		}
+		I2C_REG(bus, I2C_STAT) = stat;
+
+		if (current_time() - t > I2C_TIMEOUT) {
+//			printf("i2c timeout\n");
+			err = ERR_TIMED_OUT;
+			goto out;
+		}
+	}
+
+	err = NO_ERROR;
+
+out:
+	I2C_REG(bus, I2C_STAT) = 0xffff;
+	I2C_REG(bus, I2C_CNT) = 0;
+
+	return err;
+}
+
+status_t i2c_receive(int bus, uint8_t address, void *buf, size_t count)
+{
+	status_t err;
+
+	LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count);
+
+	i2c_wait_for_bb(bus);
+
+	I2C_REG(bus, I2C_SA) = address;
+	I2C_REG(bus, I2C_CNT) = count;
+	I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<1)|(1<<0); // enable, master, STP, STT
+
+	lk_time_t t = current_time();
+
+	uint8_t *ptr = (uint8_t *)buf;
+	for (;;) {
+		uint16_t stat = I2C_REG(bus, I2C_STAT);
+		if (stat & (1<<1)) {
+			// NACK
+//			printf("NACK\n");
+			err = ERR_GENERIC;
+			goto out;
+		}
+		if (stat & (1<<0)) {
+			// AL (arbitration lost)
+//			printf("arbitration lost!\n");
+			err = ERR_GENERIC;
+			goto out;
+		}
+		if (stat & (1<<2)) {
+			// ARDY
+//			printf("ARDY, completed\n");
+			break;
+		}
+		if (stat & (1<<3)) {
+			// RRDY
+//			printf("RRDY\n");
+
+			// read a byte, since our fifo threshold is set to 1 byte
+			*ptr = *REG8(I2C_REG_ADDR(bus, I2C_DATA));
+			ptr++;
+		}
+		I2C_REG(bus, I2C_STAT) = stat;
+
+		if (current_time() - t > I2C_TIMEOUT) {
+//			printf("i2c timeout\n");
+			err = ERR_TIMED_OUT;
+			goto out;
+		}
+	}
+
+	err = NO_ERROR;
+
+out:
+	I2C_REG(bus, I2C_STAT) = 0xffff;
+	I2C_REG(bus, I2C_CNT) = 0;
+
+	return err;
+}
+
+status_t i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t* val, size_t cnt)
+{
+	uint8_t buf[16];
+
+	if (cnt > (sizeof(buf) - 1))
+		return ERR_TOO_BIG;
+
+	buf[0] = reg;
+	memcpy(buf + 1, val, cnt);
+
+	return i2c_transmit(bus, address, buf, cnt + 1);
+}
+
+status_t i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *val, size_t cnt)
+{
+	int err = i2c_transmit(bus, address, &reg, 1);
+	if (err < 0)
+		return err;
+
+	return i2c_receive(bus, address, val, cnt);
+}
+
+
+void i2c_init_early(void)
+{
+	LTRACE_ENTRY;
+
+	/* enable clocks on i2c 0-2 */
+	RMWREG32(CM_FCLKEN1_CORE, 15, 3, 0x7),
+	RMWREG32(CM_ICLKEN1_CORE, 15, 3, 0x7),
+
+	i2c_reset_bus(0);
+	i2c_reset_bus(1);
+	i2c_reset_bus(2);
+
+#if 0
+	// write something into a reg
+	char buf[2];
+	i2c_write_reg(0, 0x4b, 0x14, 0x99);
+	i2c_write_reg(0, 0x4b, 0x15, 0x98);
+
+	i2c_read_reg(0, 0x4b, 0x15, buf);
+	printf("0x%hhx\n", buf[0]);
+	i2c_read_reg(0, 0x4b, 0x14, buf);
+	printf("0x%hhx\n", buf[0]);
+
+	int i;
+	for (i=0; i < 255; i++) {
+		char buf[1];
+		buf[0] = i;
+		i2c_transmit(0, 0x4b, buf, 1);
+		i2c_receive(0, 0x4b, buf, sizeof(buf));
+		printf("0x%hhx\n", buf[0]);
+	}
+#endif
+
+	LTRACE_EXIT;
+}
+
+void i2c_init(void)
+{
+}
+
+#if WITH_LIB_CONSOLE
+
+#include <lib/console.h>
+
+static int cmd_i2c(int argc, const cmd_args *argv);
+
+STATIC_COMMAND_START
+STATIC_COMMAND("i2c", "i2c read/write commands", &cmd_i2c)
+STATIC_COMMAND_END(i2c);
+
+static int cmd_i2c(int argc, const cmd_args *argv)
+{
+	int err;
+
+	if (argc < 5) {
+		printf("not enough arguments\n");
+usage:
+		printf("%s read_reg <bus> <i2c address> <register>\n", argv[0].str);
+		printf("%s write_reg <bus> <i2c address> <register> <val>\n", argv[0].str);
+		return -1;
+	}
+
+	int bus = argv[2].u;
+	uint8_t i2c_address = argv[3].u;
+
+	if (!strcmp(argv[1].str, "read_reg")) {
+		uint8_t reg = argv[4].u;
+		uint8_t val;
+
+		err = i2c_read_reg(bus, i2c_address, reg, &val);
+		printf("i2c_read_reg err %d, val 0x%hhx\n", err, val);
+	} else if (!strcmp(argv[1].str, "write_reg")) {
+		uint8_t reg = argv[4].u;
+		uint8_t val = argv[5].u;
+		err = i2c_write_reg(bus, i2c_address, reg, val);
+		printf("i2c_write_reg err %d\n", err);
+	} else {
+		printf("unrecognized subcommand\n");
+		goto usage;
+	}
+
+	return 0;
+}
+
+#endif // WITH_APP_CONSOLE
+
+
diff --git a/src/bsp/lk/platform/omap3/include/platform/omap3.h b/src/bsp/lk/platform/omap3/include/platform/omap3.h
new file mode 100644
index 0000000..bc87664
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/include/platform/omap3.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_OMAP3_H
+#define __PLATFORM_OMAP3_H
+
+#define SDRAM_BASE 0x80000000
+
+#define L4_BASE     0x48000000
+#define L4_WKUP_BASE    0x48300000
+#define L4_PER_BASE 0x49000000
+#define L4_EMU_BASE 0x54000000
+#define GFX_BASE    0x50000000
+#define L3_BASE     0x68000000
+#define SMS_BASE    0x6C000000
+#define SDRC_BASE   0x6D000000
+#define GPMC_BASE   0x6E000000
+#define SCM_BASE    0x48002000
+
+/* clocks */
+#define CM_CLKSEL_PER       (L4_BASE + 0x5040)
+
+/* PRCM */
+#define CM_FCLKEN_IVA2      (L4_BASE + 0x4000)
+#define CM_CLKEN_PLL_IVA2   (L4_BASE + 0x4004)
+#define CM_IDLEST_PLL_IVA2  (L4_BASE + 0x4024)
+#define CM_CLKSEL1_PLL_IVA2 (L4_BASE + 0x4040)
+#define CM_CLKSEL2_PLL_IVA2 (L4_BASE + 0x4044)
+#define CM_CLKEN_PLL_MPU    (L4_BASE + 0x4904)
+#define CM_IDLEST_PLL_MPU   (L4_BASE + 0x4924)
+#define CM_CLKSEL1_PLL_MPU  (L4_BASE + 0x4940)
+#define CM_CLKSEL2_PLL_MPU  (L4_BASE + 0x4944)
+#define CM_FCLKEN1_CORE     (L4_BASE + 0x4a00)
+#define CM_ICLKEN1_CORE     (L4_BASE + 0x4a10)
+#define CM_ICLKEN2_CORE     (L4_BASE + 0x4a14)
+#define CM_CLKSEL_CORE      (L4_BASE + 0x4a40)
+#define CM_FCLKEN_GFX       (L4_BASE + 0x4b00)
+#define CM_ICLKEN_GFX       (L4_BASE + 0x4b10)
+#define CM_CLKSEL_GFX       (L4_BASE + 0x4b40)
+#define CM_FCLKEN_WKUP      (L4_BASE + 0x4c00)
+#define CM_ICLKEN_WKUP      (L4_BASE + 0x4c10)
+#define CM_CLKSEL_WKUP      (L4_BASE + 0x4c40)
+#define CM_IDLEST_WKUP      (L4_BASE + 0x4c20)
+#define CM_CLKEN_PLL        (L4_BASE + 0x4d00)
+#define CM_IDLEST_CKGEN     (L4_BASE + 0x4d20)
+#define CM_CLKSEL1_PLL      (L4_BASE + 0x4d40)
+#define CM_CLKSEL2_PLL      (L4_BASE + 0x4d44)
+#define CM_CLKSEL3_PLL      (L4_BASE + 0x4d48)
+#define CM_FCLKEN_DSS       (L4_BASE + 0x4e00)
+#define CM_ICLKEN_DSS       (L4_BASE + 0x4e10)
+#define CM_CLKSEL_DSS       (L4_BASE + 0x4e40)
+#define CM_FCLKEN_CAM       (L4_BASE + 0x4f00)
+#define CM_ICLKEN_CAM       (L4_BASE + 0x4f10)
+#define CM_CLKSEL_CAM       (L4_BASE + 0x4F40)
+#define CM_FCLKEN_PER       (L4_BASE + 0x5000)
+#define CM_ICLKEN_PER       (L4_BASE + 0x5010)
+#define CM_CLKSEL_PER       (L4_BASE + 0x5040)
+#define CM_CLKSEL1_EMU      (L4_BASE + 0x5140)
+
+#define PRM_CLKSEL          (L4_BASE + 0x306d40)
+#define PRM_RSTCTRL         (L4_BASE + 0x307250)
+#define PRM_CLKSRC_CTRL     (L4_BASE + 0x307270)
+
+/* General Purpose Timers */
+#define OMAP34XX_GPT1           (L4_BASE + 0x318000)
+#define OMAP34XX_GPT2           (L4_BASE + 0x1032000)
+#define OMAP34XX_GPT3           (L4_BASE + 0x1034000)
+#define OMAP34XX_GPT4           (L4_BASE + 0x1036000)
+#define OMAP34XX_GPT5           (L4_BASE + 0x1038000)
+#define OMAP34XX_GPT6           (L4_BASE + 0x103A000)
+#define OMAP34XX_GPT7           (L4_BASE + 0x103C000)
+#define OMAP34XX_GPT8           (L4_BASE + 0x103E000)
+#define OMAP34XX_GPT9           (L4_BASE + 0x1040000)
+#define OMAP34XX_GPT10          (L4_BASE + 0x86000)
+#define OMAP34XX_GPT11          (L4_BASE + 0x88000)
+#define OMAP34XX_GPT12          (L4_BASE + 0x304000)
+
+#define TIDR                0x00
+#define TIOCP_CFG           0x10
+#define TISTAT              0x14
+#define TISR                0x18
+#define TIER                0x1C
+#define TWER                0x20
+#define TCLR                0x24
+#define TCRR                0x28
+#define TLDR                0x2C
+#define TTGR                0x30
+#define TWPS                0x34
+#define TMAR                0x38
+#define TCAR1               0x3C
+#define TSICR               0x40
+#define TCAR2               0x44
+#define TPIR                0x48
+#define TNIR                0x4C
+#define TCVR                0x50
+#define TOCR                0x54
+#define TOWR                0x58
+
+/* WatchDog Timers (1 secure, 3 GP) */
+#define WD1_BASE            (0x4830C000)
+#define WD2_BASE            (0x48314000)
+#define WD3_BASE            (0x49030000)
+
+#define WIDR        0x00
+#define WD_SYSCONFIG    0x10
+#define WD_SYSSTATUS    0x14
+#define WISR        0x18
+#define WIER        0x1C
+#define WCLR        0x24
+#define WCRR        0x28
+#define WLDR        0x2C
+#define WTGR        0x30
+#define WWPS        0x34
+#define WSPR        0x48
+
+#define W_PEND_WCLR (1<<0)
+#define W_PEND_WCRR (1<<1)
+#define W_PEND_WLDR (1<<2)
+#define W_PEND_WTGR (1<<3)
+#define W_PEND_WSPR (1<<4)
+
+#define WD_UNLOCK1      0xAAAA
+#define WD_UNLOCK2      0x5555
+
+/* 32KTIMER */
+#define TIMER32K_BASE       (L4_BASE + 0x320000)
+#define TIMER32K_REV        (TIMER32K_BASE + 0x00)
+#define TIMER32K_CR         (TIMER32K_BASE + 0x10)
+
+/* UART */
+#define OMAP_UART1_BASE     (L4_BASE + 0x6a000)
+#define OMAP_UART2_BASE     (L4_BASE + 0x6c000)
+#define OMAP_UART3_BASE     (L4_BASE + 0x01020000)
+
+#define UART_RHR    0
+#define UART_THR    0
+#define UART_DLL    0
+#define UART_IER    1
+#define UART_DLH    1
+#define UART_IIR    2
+#define UART_FCR    2
+#define UART_EFR    2
+#define UART_LCR    3
+#define UART_MCR    4
+#define UART_LSR    5
+#define UART_MSR    6
+#define UART_TCR    6
+#define UART_SPR    7
+#define UART_TLR    7
+#define UART_MDR1   8
+#define UART_MDR2   9
+#define UART_SFLSR  10
+#define UART_RESUME 11
+#define UART_TXFLL  10
+#define UART_TXFLH  11
+#define UART_SFREGL 12
+#define UART_SFREGH 13
+#define UART_RXFLL  12
+#define UART_RXFLH  13
+#define UART_BLR    14
+#define UART_UASR   14
+#define UART_ACREG  15
+#define UART_SCR    16
+#define UART_SSR    17
+#define UART_EBLR   18
+#define UART_MVR    19
+#define UART_SYSC   20
+
+/* MPU INTC */
+#define INTC_BASE           (L4_BASE + 0x200000)
+#define INTC_REVISION       (INTC_BASE + 0x000)
+#define INTC_SYSCONFIG      (INTC_BASE + 0x010)
+#define INTC_SYSSTATUS      (INTC_BASE + 0x014)
+#define INTC_SIR_IRQ        (INTC_BASE + 0x040)
+#define INTC_SIR_FIQ        (INTC_BASE + 0x044)
+#define INTC_CONTROL        (INTC_BASE + 0x048)
+#define INTC_PROTECTION     (INTC_BASE + 0x04C)
+#define INTC_IDLE           (INTC_BASE + 0x050)
+#define INTC_IRQ_PRIORITY   (INTC_BASE + 0x060)
+#define INTC_FIQ_PRIORITY   (INTC_BASE + 0x064)
+#define INTC_THRESHOLD      (INTC_BASE + 0x068)
+#define INTC_ITR(n)         (INTC_BASE + 0x080 + (n) * 0x20)
+#define INTC_MIR(n)         (INTC_BASE + 0x084 + (n) * 0x20)
+#define INTC_MIR_CLEAR(n)   (INTC_BASE + 0x088 + (n) * 0x20)
+#define INTC_MIR_SET(n)     (INTC_BASE + 0x08C + (n) * 0x20)
+#define INTC_ISR_SET(n)     (INTC_BASE + 0x090 + (n) * 0x20)
+#define INTC_ISR_CLEAR(n)   (INTC_BASE + 0x094 + (n) * 0x20)
+#define INTC_PENDING_IRQ(n) (INTC_BASE + 0x098 + (n) * 0x20)
+#define INTC_PENDING_FIQ(n) (INTC_BASE + 0x09C + (n) * 0x20)
+#define INTC_ILR(n)         (INTC_BASE + 0x100 + (n) * 4)
+
+/* interrupts */
+#define INT_VECTORS         96
+#define GPT2_IRQ            38
+
+/* HS USB */
+#define USB_HS_BASE         (L4_BASE + 0xab000)
+
+/* USB OTG */
+#define OTG_BASE            (L4_BASE + 0xab400)
+
+#define OTG_REVISION        (OTG_BASE + 0x00)
+#define OTG_SYSCONFIG       (OTG_BASE + 0x04)
+#define OTG_SYSSTATUS       (OTG_BASE + 0x08)
+#define OTG_INTERFSEL       (OTG_BASE + 0x0C)
+#define OTG_SIMENABLE       (OTG_BASE + 0x10)
+#define OTG_FORCESTDBY      (OTG_BASE + 0x14)
+
+/* I2C */
+#define I2C1_BASE       (L4_BASE + 0x70000)
+#define I2C2_BASE       (L4_BASE + 0x72000)
+#define I2C3_BASE       (L4_BASE + 0x60000)
+
+#define I2C_REV             (0x00)
+#define I2C_IE              (0x04)
+#define I2C_STAT            (0x08)
+#define I2C_WE              (0x0C)
+#define I2C_SYSS            (0x10)
+#define I2C_BUF             (0x14)
+#define I2C_CNT             (0x18)
+#define I2C_DATA            (0x1C)
+#define I2C_SYSC            (0x20)
+#define I2C_CON             (0x24)
+#define I2C_OA0             (0x28)
+#define I2C_SA              (0x2C)
+#define I2C_PSC             (0x30)
+#define I2C_SCLL            (0x34)
+#define I2C_SCLH            (0x38)
+#define I2C_SYSTEST         (0x3C)
+#define I2C_BUFSTAT         (0x40)
+#define I2C_OA1             (0x44)
+#define I2C_OA2             (0x48)
+#define I2C_OA3             (0x4C)
+#define I2C_ACTOA           (0x50)
+#define I2C_SBLOCK          (0x54)
+
+#endif
+
diff --git a/src/bsp/lk/platform/omap3/interrupts.c b/src/bsp/lk/platform/omap3/interrupts.c
new file mode 100644
index 0000000..44e5d4d
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/interrupts.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <debug.h>
+#include <trace.h>
+#include <err.h>
+#include <reg.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+#include <arch/ops.h>
+#include <arch/arm.h>
+#include "platform_p.h"
+#include <platform/omap3.h>
+
+struct int_handler_struct {
+	int_handler handler;
+	void *arg;
+};
+
+static struct int_handler_struct int_handler_table[INT_VECTORS];
+
+#define vectorToController(vector) ((vector) / 32)
+
+void platform_init_interrupts(void)
+{
+	unsigned int i;
+
+	// reset the controller
+	*REG32(INTC_SYSCONFIG) = 0x2; // start a reset
+	while ((*REG32(INTC_SYSSTATUS) & 0x1) == 0)
+		;
+
+	// mask all interrupts
+	*REG32(INTC_MIR(0)) = 0xffffffff;
+	*REG32(INTC_MIR(1)) = 0xffffffff;
+	*REG32(INTC_MIR(2)) = 0xffffffff;
+
+	// set up each of the interrupts
+	for (i = 0; i < INT_VECTORS; i++) {
+		// set each vector up as high priority IRQ
+		*REG32(INTC_ILR(i)) = 0;
+		//*ICReg(i / 32, INTCON_ILR_BASE + 4*(i%32)) = ((level_trigger[i/32] & (1<<(i%32))) ? (1<<1) : (0<<1)) | 0;
+	}
+
+	// disable the priority threshold
+	*REG32(INTC_THRESHOLD) = 0xff;
+
+	// clear any pending sw interrupts
+	*REG32(INTC_ISR_CLEAR(0)) = 0xffffffff;
+	*REG32(INTC_ISR_CLEAR(1)) = 0xffffffff;
+	*REG32(INTC_ISR_CLEAR(2)) = 0xffffffff;
+
+	// globally unmask interrupts
+	*REG32(INTC_CONTROL) = 3; // reset and enable the controller
+}
+
+status_t mask_interrupt(unsigned int vector)
+{
+	if (vector >= INT_VECTORS)
+		return ERR_INVALID_ARGS;
+
+//	dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+	*REG32(INTC_MIR_SET(vectorToController(vector))) = 1 << (vector % 32);
+
+	return NO_ERROR;
+}
+
+
+void platform_mask_irqs(void)
+{
+	int i;
+	for (i=0; i<INT_VECTORS; i++)
+		mask_interrupt(i);
+}
+
+status_t unmask_interrupt(unsigned int vector)
+{
+	if (vector >= INT_VECTORS)
+		return ERR_INVALID_ARGS;
+
+//	dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+	*REG32(INTC_MIR_CLEAR(vectorToController(vector))) = 1 << (vector % 32);
+
+	return NO_ERROR;
+}
+
+enum handler_return platform_irq(struct arm_iframe *frame)
+{
+	// get the current vector
+	unsigned int vector;
+
+	// read the currently active IRQ
+	vector = *REG32(INTC_SIR_IRQ) & 0x7f;
+
+//	TRACEF("spsr 0x%x, pc 0x%x, currthread %p, vector %d, handler %p\n", frame->spsr, frame->pc, current_thread, vector, int_handler_table[vector].handler);
+
+	THREAD_STATS_INC(interrupts);
+
+	// deliver the interrupt
+	enum handler_return ret;
+
+	ret = INT_NO_RESCHEDULE;
+	if (int_handler_table[vector].handler)
+		ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
+
+	// ack the interrupt
+	*REG32(INTC_CONTROL) = 0x1;
+
+	return ret;
+}
+
+void platform_fiq(struct arm_iframe *frame)
+{
+	PANIC_UNIMPLEMENTED;
+}
+
+void register_int_handler(unsigned int vector, int_handler handler, void *arg)
+{
+	if (vector >= INT_VECTORS)
+		panic("register_int_handler: vector out of range %d\n", vector);
+
+	spin_lock_saved_state_t statep;
+	arch_interrupt_save(&statep, SPIN_LOCK_FLAG_IRQ);
+
+	int_handler_table[vector].arg = arg;
+	int_handler_table[vector].handler = handler;
+
+	arch_interrupt_restore(statep, SPIN_LOCK_FLAG_IRQ);
+}
+
+
diff --git a/src/bsp/lk/platform/omap3/platform.c b/src/bsp/lk/platform/omap3/platform.c
new file mode 100644
index 0000000..ec8dc58
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/platform.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <debug.h>
+#include <arch/arm/mmu.h>
+#include <platform.h>
+#include "platform_p.h"
+#include <platform/omap3.h>
+#include <dev/i2c.h>
+#include <dev/uart.h>
+#include <dev/usbc.h>
+#include <kernel/vm.h>
+
+#warning Add proper memory map
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+	// XXX needs to be filled in
+
+	/* null entry to terminate the list */
+	{ 0 }
+};
+
+#if 0
+void platform_init_mmu_mappings(void)
+{
+	/* do some memory map initialization */
+	addr_t addr;
+	arm_mmu_map_section(SDRAM_BASE, 0,
+			MMU_MEMORY_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE |
+			MMU_MEMORY_L1_AP_P_NA_U_NA);
+
+	for (addr = SDRAM_BASE; addr < SDRAM_BASE + SDRAM_SIZE; addr += (1024*1024)) {
+		arm_mmu_map_section(addr, addr,
+				MMU_MEMORY_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE |
+				MMU_MEMORY_L1_AP_P_RW_U_NA);
+	}
+}
+#endif
+
+void platform_early_init(void)
+{
+	/* initialize the interrupt controller */
+	platform_init_interrupts();
+
+	/* initialize the timer block */
+	platform_init_timer();
+
+	/* initialize the uart */
+	uart_init_early();
+
+	i2c_init_early();
+}
+
+void platform_init(void)
+{
+	i2c_init();
+
+	uart_init();
+
+//	usbc_init();
+}
+
diff --git a/src/bsp/lk/platform/omap3/platform_p.h b/src/bsp/lk/platform/omap3/platform_p.h
new file mode 100644
index 0000000..872ea2b
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/platform_p.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_P_H
+#define __PLATFORM_P_H
+
+void platform_init_interrupts(void);
+void platform_init_timer(void);
+
+#endif
+
diff --git a/src/bsp/lk/platform/omap3/rules.mk b/src/bsp/lk/platform/omap3/rules.mk
new file mode 100644
index 0000000..a091a92
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/rules.mk
@@ -0,0 +1,32 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+ARCH := arm
+ARM_CPU := cortex-a8
+CPU := generic
+
+# provides a few devices
+GLOBAL_DEFINES += \
+	WITH_DEV_UART=1
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/cpu_early_init.S \
+	$(LOCAL_DIR)/debug.c \
+	$(LOCAL_DIR)/i2c.c \
+	$(LOCAL_DIR)/interrupts.c \
+	$(LOCAL_DIR)/platform.c \
+	$(LOCAL_DIR)/timer.c \
+	$(LOCAL_DIR)/uart.c \
+
+#	$(LOCAL_DIR)/usbc.c
+
+MEMBASE := 0x80000000
+
+GLOBAL_DEFINES += \
+	WITH_CPU_EARLY_INIT=1
+
+LINKER_SCRIPT += \
+	$(BUILDDIR)/system-onesegment.ld
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/omap3/timer.c b/src/bsp/lk/platform/omap3/timer.c
new file mode 100644
index 0000000..37cac3a
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/timer.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/timer.h>
+#include <platform/omap3.h>
+#include "platform_p.h"
+
+static lk_time_t tick_interval;
+static platform_timer_callback t_callback;
+static void *callback_arg;
+
+/* timer 2 */
+static const ulong timer_base = OMAP34XX_GPT2;
+
+#define TIMER_TICK_RATE 32768
+
+#define TIMER_REG(reg) *REG32(timer_base + (reg))
+
+status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval)
+{
+	spin_lock_saved_state_t statep;
+	arch_interrupt_save(&statep, SPIN_LOCK_FLAG_IRQ);
+
+	t_callback = callback;
+	callback_arg = arg;
+	tick_interval = interval;
+	uint32_t ticks_per_interval = (uint64_t)interval * TIMER_TICK_RATE / 1000; // interval is in ms
+
+	TIMER_REG(TCLR) = 0; // stop the timer
+	TIMER_REG(TLDR) = -ticks_per_interval;
+	TIMER_REG(TTGR) = 1;
+	TIMER_REG(TIER) = 0x2;
+	TIMER_REG(TCLR) = 0x3; // autoreload, start
+
+	unmask_interrupt(GPT2_IRQ);
+
+	arch_interrupt_restore(statep, SPIN_LOCK_FLAG_IRQ);
+
+	return NO_ERROR;
+}
+
+lk_time_t current_time(void)
+{
+	uint32_t delta_ticks;
+	uint32_t delta_ticks2;
+
+retry:
+	delta_ticks = *REG32(TIMER32K_CR);
+	delta_ticks2 = *REG32(TIMER32K_CR);
+	if (delta_ticks2 != delta_ticks)
+		goto retry;
+
+	uint64_t longtime = delta_ticks * 1000ULL / 32768ULL;
+
+	return (lk_time_t)longtime;
+}
+
+lk_bigtime_t current_time_hires(void)
+{
+	uint32_t delta_ticks;
+	uint32_t delta_ticks2;
+
+retry:
+	delta_ticks = *REG32(TIMER32K_CR);
+	delta_ticks2 = *REG32(TIMER32K_CR);
+	if (delta_ticks2 != delta_ticks)
+		goto retry;
+
+	uint64_t longtime = delta_ticks * 1000000ULL / 32768ULL;
+
+	return (lk_bigtime_t)longtime;
+}
+static enum handler_return os_timer_tick(void *arg)
+{
+	TIMER_REG(TISR) = TIMER_REG(TISR);
+
+	return t_callback(callback_arg, current_time());
+}
+
+void platform_init_timer(void)
+{
+	/* GPT2 */
+	RMWREG32(CM_CLKSEL_PER, 0, 1, 1);
+	RMWREG32(CM_ICLKEN_PER, 3, 1, 1);
+	RMWREG32(CM_FCLKEN_PER, 3, 1, 1);
+
+	// reset the GP timer
+	TIMER_REG(TIOCP_CFG) = 0x2;
+	while ((TIMER_REG(TISTAT) & 1) == 0)
+		;
+
+	// set GPT2-9 clock inputs over to 32k
+	*REG32(CM_CLKSEL_PER) = 0;
+
+	// disable ints
+	TIMER_REG(TIER) = 0;
+	TIMER_REG(TISR) = 0x7; // clear any pending bits
+
+	// XXX make sure 32K timer is running
+
+	register_int_handler(GPT2_IRQ, &os_timer_tick, NULL);
+}
+
+void platform_halt_timers(void)
+{
+	TIMER_REG(TCLR) = 0;
+}
+
diff --git a/src/bsp/lk/platform/omap3/uart.c b/src/bsp/lk/platform/omap3/uart.c
new file mode 100644
index 0000000..900a321
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/uart.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <reg.h>
+#include <dev/uart.h>
+#include <platform/omap3.h>
+#include <target/debugconfig.h>
+
+struct uart_stat {
+	addr_t base;
+	uint shift;
+};
+
+static struct uart_stat uart[3] = {
+	{ OMAP_UART1_BASE, 2 },
+	{ OMAP_UART2_BASE, 2 },
+	{ OMAP_UART3_BASE, 2 },
+};
+
+static inline void write_uart_reg(int port, uint reg, unsigned char data)
+{
+	*(volatile unsigned char *)(uart[port].base + (reg << uart[port].shift)) = data;
+}
+
+static inline unsigned char read_uart_reg(int port, uint reg)
+{
+	return *(volatile unsigned char *)(uart[port].base + (reg << uart[port].shift));
+}
+
+#define LCR_8N1     0x03
+
+#define FCR_FIFO_EN     0x01        /* Fifo enable */
+#define FCR_RXSR        0x02        /* Receiver soft reset */
+#define FCR_TXSR        0x04        /* Transmitter soft reset */
+
+#define MCR_DTR         0x01
+#define MCR_RTS         0x02
+#define MCR_DMA_EN      0x04
+#define MCR_TX_DFR      0x08
+
+#define LCR_WLS_MSK 0x03        /* character length select mask */
+#define LCR_WLS_5   0x00        /* 5 bit character length */
+#define LCR_WLS_6   0x01        /* 6 bit character length */
+#define LCR_WLS_7   0x02        /* 7 bit character length */
+#define LCR_WLS_8   0x03        /* 8 bit character length */
+#define LCR_STB     0x04        /* Number of stop Bits, off = 1, on = 1.5 or 2) */
+#define LCR_PEN     0x08        /* Parity eneble */
+#define LCR_EPS     0x10        /* Even Parity Select */
+#define LCR_STKP    0x20        /* Stick Parity */
+#define LCR_SBRK    0x40        /* Set Break */
+#define LCR_BKSE    0x80        /* Bank select enable */
+
+#define LSR_DR      0x01        /* Data ready */
+#define LSR_OE      0x02        /* Overrun */
+#define LSR_PE      0x04        /* Parity error */
+#define LSR_FE      0x08        /* Framing error */
+#define LSR_BI      0x10        /* Break */
+#define LSR_THRE    0x20        /* Xmit holding register empty */
+#define LSR_TEMT    0x40        /* Xmitter empty */
+#define LSR_ERR     0x80        /* Error */
+
+#define LCRVAL LCR_8N1                  /* 8 data, 1 stop, no parity */
+#define MCRVAL (MCR_DTR | MCR_RTS)          /* RTS/DTR */
+#define FCRVAL (FCR_FIFO_EN | FCR_RXSR | FCR_TXSR)  /* Clear & enable FIFOs */
+
+#define V_NS16550_CLK            (48000000)  /* 48MHz (APLL96/2) */
+
+void uart_init_port(int port, uint baud)
+{
+	/* clear the tx & rx fifo and disable */
+	uint16_t baud_divisor = (V_NS16550_CLK / 16 / baud);
+
+	write_uart_reg(port, UART_IER, 0);
+	write_uart_reg(port, UART_LCR, LCR_BKSE | LCRVAL); // config mode A
+	write_uart_reg(port, UART_DLL, baud_divisor & 0xff);
+	write_uart_reg(port, UART_DLH, (baud_divisor >> 8) & 0xff);
+	write_uart_reg(port, UART_LCR, LCRVAL); // operational mode
+	write_uart_reg(port, UART_MCR, MCRVAL);
+	write_uart_reg(port, UART_FCR, FCRVAL);
+	write_uart_reg(port, UART_MDR1, 0); // UART 16x mode
+
+//	write_uart_reg(port, UART_LCR, 0xBF); // config mode B
+//	write_uart_reg(port, UART_EFR, (1<<7)|(1<<6)); // hw flow control
+//	write_uart_reg(port, UART_LCR, LCRVAL); // operational mode
+}
+
+void uart_init_early(void)
+{
+	/* UART1 */
+	RMWREG32(CM_FCLKEN1_CORE, 13, 1, 1),
+	RMWREG32(CM_ICLKEN1_CORE, 13, 1, 1),
+
+	/* UART2 */
+	RMWREG32(CM_FCLKEN1_CORE, 14, 1, 1),
+	RMWREG32(CM_ICLKEN1_CORE, 14, 1, 1),
+
+	/* UART3 */
+	RMWREG32(CM_FCLKEN_PER, 11, 1, 1),
+	RMWREG32(CM_ICLKEN_PER, 11, 1, 1),
+
+	uart_init_port(DEBUG_UART, 115200);
+}
+
+void uart_init(void)
+{
+}
+
+int uart_putc(int port, char c )
+{
+	while (!(read_uart_reg(port, UART_LSR) & (1<<6))) // wait for the last char to get out
+		;
+	write_uart_reg(port, UART_THR, c);
+	return 0;
+}
+
+int uart_getc(int port, bool wait)  /* returns -1 if no data available */
+{
+	if (wait) {
+		while (!(read_uart_reg(port, UART_LSR) & (1<<0))) // wait for data to show up in the rx fifo
+			;
+	} else {
+		if (!(read_uart_reg(port, UART_LSR) & (1<<0)))
+			return -1;
+	}
+	return read_uart_reg(port, UART_RHR);
+}
+
+void uart_flush_tx(int port)
+{
+	while (!(read_uart_reg(port, UART_LSR) & (1<<6))) // wait for the last char to get out
+		;
+}
+
+void uart_flush_rx(int port)
+{
+	// empty the rx fifo
+	while (read_uart_reg(port, UART_LSR) & (1<<0)) {
+		volatile char c = read_uart_reg(port, UART_RHR);
+		(void)c;
+	}
+}
+
+
diff --git a/src/bsp/lk/platform/omap3/usbc.c b/src/bsp/lk/platform/omap3/usbc.c
new file mode 100644
index 0000000..c0d6483
--- /dev/null
+++ b/src/bsp/lk/platform/omap3/usbc.c
@@ -0,0 +1,884 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <trace.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <kernel/thread.h>
+#include <dev/usbc.h>
+#include <dev/twl4030.h>
+#include <reg.h>
+#include <platform/omap3.h>
+#include <platform/interrupts.h>
+#include <hw/usb.h>
+
+#define LOCAL_TRACE 0
+
+#define hsusb_reg8(reg) *REG8(USB_HS_BASE + (reg))
+#define hsusb_reg16(reg) *REG16(USB_HS_BASE + (reg))
+#define hsusb_reg32(reg) *REG32(USB_HS_BASE + (reg))
+
+/* registers */
+#define FADDR   0x0
+#define POWER   0x1
+#define INTRTX  0x2
+#define INTRRX  0x4
+#define INTRTXE 0x6
+#define INTRRXE 0x8
+#define INTRUSB 0xa
+#define INTRUSBE 0xb
+#define FRAME   0xc
+#define INDEX   0xe
+#define TESTMODE 0xf
+
+// indexed endpoint regs
+#define IDX_TXMAXP  0x10
+#define IDX_TXCSR   0x12
+#define IDX_TXCSRL  0x12
+#define IDX_TXCSRH  0x13
+#define IDX_RXMAXP  0x14
+#define IDX_RXCSR   0x16
+#define IDX_RXCSRL  0x16
+#define IDX_RXCSRH  0x17
+#define IDX_RXCOUNT 0x18
+#define IDX_FIFOSIZE    0x1f
+
+// if endpoint 0 is selected
+#define IDX_CSR0    0x12
+#define IDX_CONFIGDATA  0x1f
+
+// endpoint FIFOs
+#define FIFOBASE    0x20
+
+#define DEVCTL  0x60
+#define TXFIFOSZ    0x62
+#define RXFIFOSZ    0x63
+#define TXFIFOADD   0x64
+#define RXFIFOADD   0x66
+#define HWVERS  0x6c
+#define EPINFO  0x78
+#define RAMINFO 0x79
+#define LINKINFO    0x7a
+
+static void setup_dynamic_fifos(void);
+
+enum usb_state {
+	USB_DEFAULT = 0,
+	USB_ADDRESS,
+	USB_CONFIGURED
+};
+
+struct usbc_ep {
+	bool active;
+	uint width;
+	uint blocksize;
+
+	/* current data buffer */
+	usbc_transfer *transfer;
+
+	/* callback when tx or rx happens on the endpoint */
+	int (*callback)(ep_t endpoint, usbc_callback_op_t op, usbc_transfer *transfer);
+};
+
+struct usbc_stat {
+	bool active;
+	enum usb_state state;
+	uint8_t active_config;
+
+	// callback for device events
+	usb_callback callback;
+
+	// ep0 pending tx
+	const void *ep0_tx_buf;
+	size_t ep0_tx_len;
+	uint ep0_tx_pos;
+
+	struct usbc_ep inep[16];  // IN endpoints (device to host)
+	struct usbc_ep outep[16]; // OUT endpoint (host to device)
+};
+
+static struct usbc_stat *usbc;
+
+struct usbc_callback {
+	struct list_node node;
+	usb_callback callback;
+};
+
+static struct list_node usbc_callback_list;
+
+static void call_all_callbacks(usbc_callback_op_t op, const union usb_callback_args *arg)
+{
+	struct usbc_callback *cb;
+
+	list_for_every_entry(&usbc_callback_list, cb, struct usbc_callback, node) {
+		LTRACEF("calling %p, op %d, arg %p\n", cb->callback, op, arg);
+		cb->callback(op, arg);
+	}
+}
+
+static void print_usb_setup(const struct usb_setup *setup)
+{
+	printf("usb_setup:\n");
+	printf("\ttype 0x%hhx\n", setup->request_type);
+	printf("\trequest 0x%hhx\n", setup->request);
+	printf("\tvalue 0x%hx\n", setup->value);
+	printf("\tindex 0x%hx\n", setup->index);
+	printf("\tlength 0x%hx\n", setup->length);
+}
+
+static void select_ep(uint ep)
+{
+	DEBUG_ASSERT(ep < 16);
+	hsusb_reg8(INDEX) = ep;
+}
+
+static void dump_ep_regs(uint ep)
+{
+#if 0
+	select_ep(ep);
+
+	LTRACEF("%d txmaxp 0x%hx\n", ep, hsusb_reg16(IDX_TXMAXP));
+	LTRACEF("%d rxmaxp 0x%hx\n", ep, hsusb_reg16(IDX_RXMAXP));
+	LTRACEF("%d txfifosz 0x%hhx\n", ep, hsusb_reg8(TXFIFOSZ));
+	LTRACEF("%d rxfifosz 0x%hhx\n", ep, hsusb_reg8(RXFIFOSZ));
+	LTRACEF("%d txfifoadd 0x%hx\n", ep, hsusb_reg16(TXFIFOADD));
+	LTRACEF("%d rxfifoadd 0x%hx\n", ep, hsusb_reg16(RXFIFOADD));
+#endif
+}
+
+#define MULOF4(val) (((uint32_t)(val) & 0x3) == 0)
+
+static int read_ep_fifo(uint ep, void *_buf, size_t maxlen)
+{
+	char *buf = (void *)_buf;
+
+	select_ep(ep);
+
+	uint8_t fifo_reg = FIFOBASE + ep * 4;
+	size_t rxcount = hsusb_reg16(IDX_RXCOUNT);
+
+	if (rxcount > maxlen)
+		rxcount = maxlen;
+
+	if (MULOF4(buf) && MULOF4(rxcount)) {
+		uint i;
+		uint32_t *buf32 = (uint32_t *)_buf;
+		for (i=0; i < rxcount / 4; i++) {
+			buf32[i] = hsusb_reg32(fifo_reg);
+		}
+	} else {
+		/* slow path */
+		uint i;
+		for (i=0; i < rxcount; i++) {
+			buf[i] = hsusb_reg8(fifo_reg);
+		}
+	}
+
+	return rxcount;
+}
+
+static int write_ep_fifo(uint ep, const void *_buf, size_t len)
+{
+	char *buf = (void *)_buf;
+
+	select_ep(ep);
+
+	uint8_t fifo_reg = FIFOBASE + ep * 4;
+
+	if (MULOF4(buf) && MULOF4(len)) {
+		uint i;
+		uint32_t *buf32 = (uint32_t *)_buf;
+		for (i=0; i < len / 4; i++) {
+			hsusb_reg32(fifo_reg) = buf32[i];
+		}
+	} else {
+		/* slow path */
+		uint i;
+		for (i=0; i < len; i++) {
+			hsusb_reg8(fifo_reg) = buf[i];
+		}
+	}
+
+	return len;
+}
+
+#undef MULOF4
+
+void usbc_ep0_send(const void *buf, size_t len, size_t maxlen)
+{
+	LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen);
+
+	// trim the transfer
+	len = MIN(len, maxlen);
+
+	size_t transfer_len = MIN(64, len);
+
+	// write the first 64 bytes
+	write_ep_fifo(0, buf, transfer_len);
+
+	// set txpktready
+	select_ep(0);
+	if (len > 64) {
+		// we have more data to send, don't mark data end
+		hsusb_reg16(IDX_CSR0) |= (1<<1); // TxPktRdy
+
+		// save our position so we can continue
+		usbc->ep0_tx_buf = buf;
+		usbc->ep0_tx_pos = 64;
+		usbc->ep0_tx_len = len;
+	} else {
+		hsusb_reg16(IDX_CSR0) |= (1<<3) | (1<<1); // DataEnd, TxPktRdy
+		usbc->ep0_tx_buf = NULL;
+	}
+}
+
+static void ep0_control_send_resume(void)
+{
+	DEBUG_ASSERT(usbc->ep0_tx_buf != NULL);
+	DEBUG_ASSERT(usbc->ep0_tx_len > usbc->ep0_tx_pos);
+
+	LTRACEF("buf %p pos %d len %d\n", usbc->ep0_tx_buf, usbc->ep0_tx_pos, usbc->ep0_tx_len);
+
+	size_t transfer_len = MIN(64, usbc->ep0_tx_len - usbc->ep0_tx_pos);
+
+	write_ep_fifo(0, (const uint8_t *)usbc->ep0_tx_buf + usbc->ep0_tx_pos, transfer_len);
+
+	usbc->ep0_tx_pos += transfer_len;
+
+	if (usbc->ep0_tx_pos >= usbc->ep0_tx_len) {
+		// completes the transfer
+		hsusb_reg16(IDX_CSR0) |= (1<<3) | (1<<1); // DataEnd, TxPktRdy
+		usbc->ep0_tx_buf = NULL;
+	} else {
+		hsusb_reg16(IDX_CSR0) |= (1<<1); // TxPktRdy
+	}
+}
+
+void usbc_ep0_ack(void)
+{
+	hsusb_reg16(IDX_CSR0) |= (1<<6)|(1<<3); // servicedrxpktrdy & dataend
+}
+
+void usbc_ep0_stall(void)
+{
+	printf("USB STALL\n");
+}
+
+static void usb_shutdown_endpoints(void)
+{
+	// iterate through all the endpoints, cancelling any pending io and shut down the endpoint
+	ep_t i;
+	for (i=1; i < 16; i++) {
+		if (usbc->inep[i].active && usbc->inep[i].transfer) {
+			// pool's closed
+			usbc_transfer *t = usbc->inep[i].transfer;
+			usbc->inep[i].transfer = NULL;
+			t->result = USB_TRANSFER_RESULT_CANCELLED;
+			usbc->inep[i].callback(i, CB_EP_TRANSFER_CANCELLED, t);
+		}
+		if (usbc->outep[i].active && usbc->outep[i].transfer) {
+			// pool's closed
+			usbc_transfer *t = usbc->outep[i].transfer;
+			usbc->outep[i].transfer = NULL;
+			t->result = USB_TRANSFER_RESULT_CANCELLED;
+			usbc->outep[i].callback(i, CB_EP_TRANSFER_CANCELLED, t);
+		}
+	}
+
+	// clear pending ep0 data
+	usbc->ep0_tx_buf = 0;
+}
+
+static void usb_enable_endpoints(void)
+{
+	setup_dynamic_fifos();
+}
+
+static void usb_disconnect(void)
+{
+	// we've been disconnected
+	usbc->state = USB_DEFAULT;
+	usbc->active_config = 0;
+
+	usb_shutdown_endpoints();
+}
+
+static void usb_reset(void)
+{
+	// this wipes out our endpoint interrupt disables
+	hsusb_reg16(INTRTXE) = (1<<0);
+	hsusb_reg16(INTRRXE) = 0;
+
+	usb_shutdown_endpoints();
+}
+
+static int handle_ep_rx(int ep)
+{
+	struct usbc_ep *e = &usbc->outep[ep];
+
+	DEBUG_ASSERT(e->active);
+
+	DEBUG_ASSERT(e->transfer); // can't rx to no transfer
+	usbc_transfer *t = e->transfer;
+
+	uint rxcount = hsusb_reg16(IDX_RXCOUNT);
+	uint readcount = MIN(rxcount, t->buflen - t->bufpos);
+	readcount = MIN(readcount, e->blocksize);
+
+	int len = read_ep_fifo(ep, (uint8_t *)t->buf + t->bufpos, readcount);
+	LTRACEF("read %d bytes from the fifo\n", len);
+
+	// no more packet ready
+	hsusb_reg16(IDX_RXCSRL) &= ~(1<<0); // clear rxpktrdy
+
+	t->bufpos += len;
+
+	if (rxcount < e->blocksize || t->bufpos >= t->buflen) {
+		// we're done with this transfer, clear it and disable the endpoint
+		e->transfer = NULL;
+		hsusb_reg16(INTRRXE) &= ~(1<<ep);
+
+		t->result = USB_TRANSFER_RESULT_OK;
+
+		DEBUG_ASSERT(e->callback);
+		e->callback(ep, CB_EP_RXCOMPLETE, t);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+bool usbc_is_highspeed(void)
+{
+	return (hsusb_reg8(POWER) & (1<<4)) ? true : false;
+}
+
+static enum handler_return hsusb_interrupt(void *arg)
+{
+	uint16_t intrtx = hsusb_reg16(INTRTX);
+	uint16_t intrrx = hsusb_reg16(INTRRX);
+	uint8_t intrusb = hsusb_reg8(INTRUSB);
+	enum handler_return ret = INT_NO_RESCHEDULE;
+
+	LTRACEF("intrtx 0x%hx (0x%x), intrrx 0x%hx (0x%x), intrusb 0x%hhx, intrusbe 0x%hhx\n",
+	        intrtx, hsusb_reg16(INTRTXE), intrrx, hsusb_reg16(INTRRXE), intrusb, hsusb_reg8(INTRUSBE));
+
+	dump_ep_regs(2);
+
+	// look for global usb interrupts
+	intrusb &= hsusb_reg8(INTRUSBE);
+	if (intrusb) {
+		if (intrusb & (1<<0)) {
+			// suspend
+			TRACEF("suspend\n");
+			call_all_callbacks(CB_SUSPEND, 0);
+			ret = INT_RESCHEDULE;
+		}
+		if (intrusb & (1<<1)) {
+			// resume
+			TRACEF("resume\n");
+			call_all_callbacks(CB_RESUME, 0);
+			ret = INT_RESCHEDULE;
+		}
+		if (intrusb & (1<<2)) {
+			// reset
+			TRACEF("reset\n");
+			TRACEF("high speed %d\n", hsusb_reg8(POWER) & (1<<4) ? 1 : 0);
+			call_all_callbacks(CB_RESET, 0);
+			usb_reset();
+			ret = INT_RESCHEDULE;
+		}
+		if (intrusb & (1<<3)) {
+			// SOF
+			TRACEF("sof\n");
+		}
+		if (intrusb & (1<<4)) {
+			// connect (host only)
+			TRACEF("connect\n");
+		}
+		if (intrusb & (1<<5)) {
+			// disconnect
+			TRACEF("disconnect\n");
+			call_all_callbacks(CB_DISCONNECT, 0);
+			usb_disconnect();
+			ret = INT_RESCHEDULE;
+		}
+		if (intrusb & (1<<6)) {
+			// session request (A device only)
+			TRACEF("session request\n");
+		}
+		if (intrusb & (1<<7)) {
+			// vbus error (A device only)
+			TRACEF("vbus error\n");
+		}
+	}
+
+	// look for endpoint 0 interrupt
+	if (intrtx & 1) {
+		select_ep(0);
+		uint16_t csr = hsusb_reg16(IDX_CSR0);
+		LTRACEF("ep0 csr 0x%hhx\n", csr);
+
+		// clear the stall bit
+		if (csr & (1<<2))
+			hsusb_reg16(IDX_CSR0) &= ~(1<<2);
+
+		// do we have any pending tx data?
+		if (usbc->ep0_tx_buf != NULL) {
+			if (csr & (1<<4)) { // setup end
+				// we got an abort on the data transfer
+				usbc->ep0_tx_buf = NULL;
+			} else {
+				// send more data
+				ep0_control_send_resume();
+			}
+		}
+
+		// clear the setup end bit
+		if (csr & (1<<4)) {
+			hsusb_reg16(IDX_CSR0) |= (1<<7); // servicedsetupend
+		}
+
+		if (csr & 0x1) {
+			// rxpktrdy
+			LTRACEF("ep0: rxpktrdy, count %d\n", hsusb_reg16(IDX_RXCOUNT));
+
+			struct usb_setup setup;
+			read_ep_fifo(0, (void *)&setup, sizeof(setup));
+//			print_usb_setup(&setup);
+
+			hsusb_reg16(IDX_CSR0) |= (1<<6); // servicedrxpktrdy
+
+			union usb_callback_args args;
+			args.setup = &setup;
+			call_all_callbacks(CB_SETUP_MSG, &args);
+
+			switch (setup.request) {
+				case SET_ADDRESS: {
+					LTRACEF("got SET_ADDRESS: value %d\n", setup.value);
+					dprintf(INFO, "usb: got assigned address %d\n", setup.value);
+					usbc_ep0_ack();
+
+					hsusb_reg8(FADDR) = setup.value;
+					if (setup.value == 0)
+						usbc->state = USB_DEFAULT;
+					else
+						usbc->state = USB_ADDRESS;
+
+					break;
+				}
+				case SET_CONFIGURATION:
+					LTRACEF("got SET_CONFIGURATION, config %d\n", setup.value);
+
+					if (setup.value == 0) {
+						if (usbc->state == USB_CONFIGURED)
+							usbc->state = USB_ADDRESS;
+						call_all_callbacks(CB_OFFLINE, 0);
+					} else {
+						usbc->state = USB_CONFIGURED;
+						call_all_callbacks(CB_ONLINE, 0);
+					}
+					usbc->active_config = setup.value;
+					ret = INT_RESCHEDULE;
+
+					// set up all of the endpoints
+					usb_enable_endpoints();
+					break;
+			}
+		}
+	}
+
+	// handle endpoint interrupts
+
+	// mask out ones we don't want to play with
+	intrtx &= hsusb_reg16(INTRTXE);
+	intrrx &= hsusb_reg16(INTRRXE);
+
+	int i;
+	for (i=1; i < 16; i++) {
+		if (intrtx & (1<<i)) {
+			select_ep(i);
+
+			LTRACEF("txcsr %i: 0x%hx\n", i, hsusb_reg16(IDX_TXCSR));
+
+			// data was sent, see if we have more to send
+			struct usbc_ep *e = &usbc->inep[i];
+
+			DEBUG_ASSERT(e->transfer); // interrupts shouldn't be enabled if there isn't a transfer queued
+			usbc_transfer *t = e->transfer;
+
+			if (t->bufpos < t->buflen) {
+				// cram more stuff in the buffer
+				uint queuelen = MIN(e->blocksize, t->buflen - t->bufpos);
+				LTRACEF("writing more tx data into fifo: len %u, remaining %zu\n", queuelen, t->buflen - t->bufpos);
+				write_ep_fifo(i, (uint8_t *)t->buf + t->bufpos, queuelen);
+				t->bufpos += queuelen;
+
+				// start the transfer
+				hsusb_reg16(IDX_TXCSR) |= (1<<0); // txpktrdy
+			} else {
+				// we're done, callback
+				e->transfer = NULL;
+				hsusb_reg16(INTRTXE) &= ~(1<<i);
+
+				t->result = USB_TRANSFER_RESULT_OK;
+
+				DEBUG_ASSERT(e->callback);
+				e->callback(i, CB_EP_TXCOMPLETE, t);
+				ret = INT_RESCHEDULE;
+			}
+		}
+		if (intrrx & (1<<i)) {
+			select_ep(i);
+
+			uint16_t csr = hsusb_reg16(IDX_RXCSR);
+			LTRACEF("rxcsr %i: 0x%hx\n", i, csr);
+
+			if (csr & 0x1) { // rxpktrdy
+				// see if the endpoint is ready
+				struct usbc_ep *e = &usbc->outep[i];
+				if (!e->active) {
+					// stall it
+					hsusb_reg16(IDX_RXCSR) |= (1<<6); // stall
+					hsusb_reg16(IDX_RXCSR) |= (1<<4); // flush fifo
+					panic("rx on inactive endpoint\n");
+					continue;
+				}
+
+				if (handle_ep_rx(i) > 0)
+					ret = INT_RESCHEDULE;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static enum handler_return hsusb_dma_interrupt(void *arg)
+{
+	LTRACE;
+
+	return INT_NO_RESCHEDULE;
+}
+
+void usbc_setup_endpoint(ep_t ep, ep_dir_t dir, bool active, ep_callback callback, uint width, uint blocksize)
+{
+	DEBUG_ASSERT(ep != 0);
+	DEBUG_ASSERT(ep < 16);
+	DEBUG_ASSERT(dir == IN || dir == OUT);
+
+	struct usbc_ep *e;
+	if (dir == IN)
+		e = &usbc->inep[ep];
+	else
+		e = &usbc->outep[ep];
+
+	// for now we can only make active
+	e->active = active;
+	e->callback = callback;
+	e->width = width;
+	e->blocksize = blocksize;
+}
+
+int usbc_queue_rx(ep_t ep, usbc_transfer *transfer)
+{
+	LTRACE;
+	struct usbc_ep *e = &usbc->outep[ep];
+
+	DEBUG_ASSERT(ep != 0);
+	DEBUG_ASSERT(ep < 16);
+	DEBUG_ASSERT(e->active);
+
+	DEBUG_ASSERT(transfer);
+	DEBUG_ASSERT(transfer->buf);
+
+	DEBUG_ASSERT(e->transfer == NULL);
+
+	// can only queue up multiples of the endpoint blocksize
+	DEBUG_ASSERT(transfer->buflen >= e->blocksize && (transfer->buflen % e->blocksize) == 0);
+
+	enter_critical_section();
+
+	if (usbc->state != USB_CONFIGURED) {
+		// can't transfer now
+		exit_critical_section();
+		return -1;
+	}
+
+	e->transfer = transfer;
+
+	// make sure the ep is set up right
+//	select_ep(ep);
+//	hsusb_reg8(IDX_RXCSRH) = 0;
+	dump_ep_regs(ep);
+
+	select_ep(ep);
+	if (hsusb_reg16(IDX_RXCSR) & (1<<0)) {
+		// packet already ready
+		LTRACEF("****packet already ready (%d)\n", hsusb_reg16(IDX_RXCOUNT));
+
+		int rc = handle_ep_rx(ep);
+		if (rc > 0) {
+			// the transfer was completed
+			goto done;
+		}
+	}
+
+	// unmask irqs for this endpoint
+	hsusb_reg16(INTRRXE) |= (1<<ep);
+
+done:
+	exit_critical_section();
+
+	return 0;
+}
+
+int usbc_queue_tx(ep_t ep, usbc_transfer *transfer)
+{
+	LTRACEF("ep %u, transfer %p (buf %p, len %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
+	struct usbc_ep *e = &usbc->inep[ep];
+
+	DEBUG_ASSERT(ep != 0);
+	DEBUG_ASSERT(ep < 16);
+	DEBUG_ASSERT(e->active);
+
+	DEBUG_ASSERT(e->transfer == NULL);
+
+	enter_critical_section();
+
+	if (usbc->state != USB_CONFIGURED) {
+		// can't transfer now
+		exit_critical_section();
+		return -1;
+	}
+
+	e->transfer = transfer;
+
+	select_ep(ep);
+
+	// set this endpoint in tx mode
+//	hsusb_reg8(IDX_TXCSRH) = (1<<7)|(1<<5); // autoset, tx direction
+	dump_ep_regs(ep);
+
+	// unmask irqs for this endpoint
+	hsusb_reg16(INTRTXE) |= (1<<ep);
+
+	// if the fifo is empty, start the transfer
+	if ((hsusb_reg16(IDX_TXCSR) & (1<<1)) == 0) {
+		// dump the start of the transfer in the fifo
+		uint queuelen = MIN(e->blocksize, transfer->buflen);
+		write_ep_fifo(ep, transfer->buf, queuelen);
+		transfer->bufpos = queuelen;
+
+		// start the transfer
+		hsusb_reg16(IDX_TXCSR) |= (1<<0); // txpktrdy
+	}
+
+	exit_critical_section();
+
+	return 0;
+}
+
+int usbc_set_callback(usb_callback callback)
+{
+	DEBUG_ASSERT(callback != NULL);
+
+	struct usbc_callback *cb = malloc(sizeof(struct usbc_callback));
+
+	enter_critical_section();
+
+	cb->callback = callback;
+	list_add_head(&usbc_callback_list, &cb->node);
+
+	exit_critical_section();
+	return 0;
+}
+
+int usbc_set_active(bool active)
+{
+	LTRACEF("active %d\n", active);
+	if (active) {
+		DEBUG_ASSERT(!usbc->active);
+
+		hsusb_reg8(POWER) |= (1<<6); // soft conn
+		twl4030_set_usb_pullup(true);
+		usbc->active = true;
+	} else {
+		hsusb_reg8(POWER) &= ~(1<<6); // soft conn
+		twl4030_set_usb_pullup(false);
+		usbc->active = false;
+	}
+
+	return 0;
+}
+
+static void setup_dynamic_fifos(void)
+{
+//	LTRACE;
+
+#if LOCAL_TRACE
+	uint8_t raminfo = hsusb_reg8(RAMINFO);
+	size_t ramsize = (1 << ((raminfo & 0xf) + 2));
+	LTRACEF("%zd bytes of onboard ram\n", ramsize);
+#endif
+
+	uint32_t offset = 128;
+
+	int highspeed = hsusb_reg8(POWER) & (1<<4);
+
+	int i;
+	for (i=1; i < 16; i++) {
+		select_ep(i);
+		if (usbc->inep[i].active) {
+			hsusb_reg8(TXFIFOSZ) = (1<<4)|(0x6); // 512 byte, double buffered
+			hsusb_reg8(RXFIFOSZ) = 0;
+			hsusb_reg16(TXFIFOADD) = offset / 8;
+			hsusb_reg16(RXFIFOADD) = 0;
+			if (highspeed) {
+				hsusb_reg16(IDX_TXMAXP) = usbc->inep[i].width;
+			} else {
+				hsusb_reg16(IDX_TXMAXP) = (((usbc->inep[i].blocksize / 64) - 1) << 11) | 64;
+//				hsusb_reg16(IDX_TXMAXP) = 64;
+//				usbc->inep[i].blocksize = 64;
+			}
+
+			hsusb_reg16(IDX_RXMAXP) = 0;
+			LTRACEF("%d: txmaxp 0x%hx\n", i, hsusb_reg16(IDX_TXMAXP));
+			hsusb_reg8(IDX_TXCSRH) = (1<<5)|(1<<3);
+			hsusb_reg8(IDX_TXCSRL) = (1<<3);
+			hsusb_reg8(IDX_TXCSRL) = (1<<3);
+			offset += 512*2;
+		} else {
+			hsusb_reg8(TXFIFOSZ) = 0;
+			hsusb_reg16(TXFIFOADD) = 0;
+			hsusb_reg16(IDX_TXMAXP) = 0;
+		}
+		if (usbc->outep[i].active) {
+			hsusb_reg8(TXFIFOSZ) = 0;
+			hsusb_reg8(RXFIFOSZ) = (0<<4)|(0x6); // 512 byte, single buffered
+			hsusb_reg16(TXFIFOADD) = 0;
+			hsusb_reg16(RXFIFOADD) = offset / 8;
+			hsusb_reg16(IDX_TXMAXP) = 0;
+			if (highspeed) {
+				hsusb_reg16(IDX_RXMAXP) = usbc->inep[i].width;
+			} else {
+				hsusb_reg16(IDX_RXMAXP) = (((usbc->outep[i].blocksize / 64) - 1) << 11) | 64;
+//				hsusb_reg16(IDX_RXMAXP) = 64;
+//				usbc->outep[i].blocksize = 64;
+			}
+			LTRACEF("%d: rxmaxp 0x%hx\n", i, hsusb_reg16(IDX_RXMAXP));
+			offset += 512;
+			hsusb_reg8(IDX_RXCSRH) = (1<<7);
+			hsusb_reg8(IDX_RXCSRL) = (1<<7);
+
+//			LTRACEF("rxcsr 0x%hx\n", hsusb_reg16(IDX_RXCSR));
+		} else {
+			hsusb_reg8(RXFIFOSZ) = 0;
+			hsusb_reg16(RXFIFOADD) = 0;
+			hsusb_reg16(IDX_RXMAXP) = 0;
+		}
+//		LTRACEF("%d txfifosz 0x%hhx\n", i, hsusb_reg8(TXFIFOSZ));
+//		LTRACEF("%d rxfifosz 0x%hhx\n", i, hsusb_reg8(RXFIFOSZ));
+//		LTRACEF("%d txfifoadd 0x%hx\n", i, hsusb_reg16(TXFIFOADD));
+//		LTRACEF("%d rxfifoadd 0x%hx\n", i, hsusb_reg16(RXFIFOADD));
+	}
+}
+
+static void otg_reset(void)
+{
+	/* reset the chip */
+	*REG32(OTG_SYSCONFIG) |= (1<<1);
+	while ((*REG32(OTG_SYSSTATUS) & 1) == 0)
+		;
+
+	/* power up the controller */
+	*REG32(OTG_FORCESTDBY) = 0; // disable forced standby
+	*REG32(OTG_SYSCONFIG) &= ~(1<<1); // autoidle off
+	*REG32(OTG_SYSCONFIG) = (2<<12) | (2<<3) | (0<<0); // master in smart-standby, periph in smart-idle, autoidle off
+
+	*REG32(OTG_SYSCONFIG) |= 1; // autoidle on
+
+	*REG32(OTG_INTERFSEL) = 1; // 8 bit ULPI
+}
+
+static void hsusb_init(void)
+{
+	LTRACE_ENTRY;
+
+	// select endpoint 0
+	dprintf(SPEW, "hwvers 0x%hx\n", hsusb_reg16(HWVERS));
+	dprintf(SPEW, "epinfo 0x%hhx\n", hsusb_reg8(EPINFO));
+	dprintf(SPEW, "raminfo 0x%hhx\n", hsusb_reg8(RAMINFO));
+	hsusb_reg8(INDEX) = 0;
+	dprintf(SPEW, "config 0x%hhx\n", hsusb_reg8(IDX_CONFIGDATA));
+
+	// assert that we have dynamic fifo sizing
+	DEBUG_ASSERT(hsusb_reg8(IDX_CONFIGDATA) & (1<<2));
+
+	// mask all the interrupts for the endpoints (except 0)
+	hsusb_reg16(INTRTXE) = (1<<0);
+	hsusb_reg16(INTRRXE) = 0;
+
+	twl4030_usb_reset();
+	twl4030_init_hs();
+
+	hsusb_reg8(DEVCTL) = 0; // peripheral mode
+//	hsusb_reg8(POWER) &= (1<<5); // disable high speed
+	hsusb_reg8(POWER) |= (1<<5); // enable high speed
+
+	hsusb_reg8(INTRUSBE) = (1<<5)|(1<<2)|(1<<1)|(1<<0); // disconnect, reset, resume, suspend
+
+	LTRACE_EXIT;
+}
+
+void usbc_init(void)
+{
+	LTRACE_ENTRY;
+
+	// enable the clock
+	RMWREG32(CM_ICLKEN1_CORE, 4, 1, 1);
+
+	// allocate some ram for the usb struct
+	usbc = malloc(sizeof(struct usbc_stat));
+	memset(usbc, 0, sizeof(struct usbc_stat));
+
+	usbc->state = USB_DEFAULT;
+
+	// initialize the callback list
+	list_initialize(&usbc_callback_list);
+
+	// register the interrupt handlers
+	register_int_handler(92, hsusb_interrupt, NULL);
+//	register_int_handler(93, hsusb_dma_interrupt, NULL);
+
+	otg_reset();
+	hsusb_init();
+
+	unmask_interrupt(92);
+//	unmask_interrupt(93);
+
+	LTRACE_EXIT;
+}
+