[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/lpc43xx/debug.c b/src/bsp/lk/platform/lpc43xx/debug.c
new file mode 100644
index 0000000..b4d8094
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/debug.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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 <kernel/thread.h>
+#include <lib/cbuf.h>
+
+#include <arch/arm/cm.h>
+#include <platform/lpc43xx-uart.h>
+#include <platform/lpc43xx-clocks.h>
+
+static cbuf_t console_rx_buf;
+
+#ifndef TARGET_DEBUG_BAUDRATE
+#define TARGET_DEBUG_BAUDRATE 115200
+#endif
+
+#if TARGET_DEBUG_UART == 1
+#define UART_BASE UART0_BASE
+#define UART_IRQ lpc43xx_USART0_IRQ
+#define UART_IRQn USART0_IRQn
+#elif TARGET_DEBUG_UART == 2
+#define UART_BASE UART1_BASE
+#define UART_IRQ lpc43xx_UART1_IRQ
+#define UART_IRQn UART1_IRQn
+#elif TARGET_DEBUG_UART == 3
+#define UART_BASE UART2_BASE
+#define UART_IRQ lpc43xx_USART2_IRQ
+#define UART_IRQn USART2_IRQn
+#elif TARGET_DEBUG_UART == 4
+#define UART_BASE UART3_BASE
+#define UART_IRQ lpc43xx_USART3_IRQ
+#define UART_IRQn USART3_IRQn
+#else
+#warning TARGET_DEBUG_UART unspecified
+#endif
+
+static u32 base_uart_clk[4] = {
+	BASE_UART0_CLK,
+	BASE_UART1_CLK,
+	BASE_UART2_CLK,
+	BASE_UART3_CLK
+};
+
+extern uint8_t __lpc43xx_main_clock_sel;
+extern uint32_t __lpc43xx_main_clock_mhz;
+
+#define ITM_STIM0	0xE0000000
+#define ITM_TER		0xE0000E00
+#define ITM_TCR		0xE0000E80
+#define ITM_LAR		0xE0000FB0
+
+#define TPI_ACPR	0xE0040010
+#define TPI_SPPR	0xE00400F0
+#define TPI_FFCR	0xE0040304
+
+#define DEMCR		0xE000EDFC
+#define DEMCR_TRCENA	(1 << 24)
+
+void lpc43xx_debug_early_init(void)
+{
+	// ensure ITM and DWT are enabled
+	writel(readl(DEMCR) | DEMCR_TRCENA, DEMCR);
+
+	writel((1 << 9) | (1 << 16) | (2 << 10), DWT_CTRL);
+
+	// configure TPIU for one-wire, nrz, 6mbps
+	writel((__lpc43xx_main_clock_mhz / 6000000) - 1, TPI_ACPR);
+	writel(2, TPI_SPPR);
+	writel(0x100, TPI_FFCR);
+
+	// configure ITM
+	writel(0xC5ACCE55, ITM_LAR); // unlock regs
+	writel(0x0001000D, ITM_TCR); // ID=1, enable ITM, SYNC, DWT events
+	writel(0xFFFFFFFF, ITM_TER); // enable all trace ports
+
+#ifdef UART_BASE
+#if TARGET_DEBUG_BAUDRATE == 115200
+	// config for 115200-n-8-1 from 12MHz clock
+	writel(BASE_CLK_SEL(CLK_IRC), base_uart_clk[TARGET_DEBUG_UART - 1]);
+	writel(LCR_DLAB, UART_BASE + REG_LCR);
+	writel(4, UART_BASE + REG_DLL);
+	writel(0, UART_BASE + REG_DLM);
+	writel(FDR_DIVADDVAL(5) | FDR_MULVAL(8), UART_BASE + REG_FDR);
+#else
+	uint32_t div = __lpc43xx_main_clock_mhz / 16 / TARGET_DEBUG_BAUDRATE;
+	writel(BASE_CLK_SEL(__lpc43xx_main_clock_sel),
+		base_uart_clk[TARGET_DEBUG_UART - 1]);
+	writel(LCR_DLAB, UART_BASE + REG_LCR);
+	writel(div & 0xFF, UART_BASE + REG_DLL);
+	writel((div >> 8) & 0xFF, UART_BASE + REG_DLM);
+#endif
+	writel(LCR_WLS_8 | LCR_SBS_1, UART_BASE + REG_LCR);
+	writel(FCR_FIFOEN | FCR_RX_TRIG_1, UART_BASE + REG_FCR);
+	writel(IER_RBRIE, UART_BASE + REG_IER);
+	NVIC_EnableIRQ(UART_IRQn);
+#endif
+}
+
+void lpc43xx_debug_init(void)
+{
+	cbuf_initialize(&console_rx_buf, 64);
+}
+
+#ifdef UART_BASE
+void UART_IRQ (void) {
+	arm_cm_irq_entry();
+	while (readl(UART_BASE + REG_LSR) & LSR_RDR) {
+		unsigned c = readl(UART_BASE + REG_RBR);
+		if (cbuf_space_avail(&console_rx_buf)) {
+			cbuf_write_char(&console_rx_buf, c, false);
+		}
+	}
+	arm_cm_irq_exit(1);
+}
+#endif
+
+void platform_dputc(char c)
+{
+	// if ITM is enabled, send character to STIM0
+	if (readl(ITM_TCR) & 1) {
+		while (!readl(ITM_STIM0)) ;
+		writeb(c, ITM_STIM0);
+	}
+#ifdef UART_BASE
+	while (!(readl(UART_BASE + REG_LSR) & LSR_THRE)) ;
+	writel(c, UART_BASE + REG_THR);
+#endif
+}
+
+int platform_dgetc(char *c, bool wait)
+{
+	if (cbuf_read_char(&console_rx_buf, c, wait) == 0)
+		return -1;
+	return 0;
+}
+
+#define DCRDR 0xE000EDF8
+
+void _debugmonitor(void) {
+	u32 n;
+	arm_cm_irq_entry();
+	n = readl(DCRDR);
+	if (n & 0x80000000) {
+		switch (n >> 24) {
+		case 0x80: // write to console
+			if (cbuf_space_avail(&console_rx_buf)) {
+				cbuf_write_char(&console_rx_buf, n & 0xFF, false);
+			}
+			n = 0;
+			break;
+		default:
+			n = 0x01000000;
+		}
+		writel(n, DCRDR);
+	}
+	arm_cm_irq_exit(1);
+}
diff --git a/src/bsp/lk/platform/lpc43xx/gpio.c b/src/bsp/lk/platform/lpc43xx/gpio.c
new file mode 100644
index 0000000..04b99bc
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/gpio.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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 <reg.h>
+#include <platform/lpc43xx-gpio.h>
+
+inline int gpio_config(unsigned nr, unsigned flags) {
+	unsigned m = _GPIOm(nr);
+	unsigned n = _GPIOn(nr);
+	if (flags & GPIO_INPUT) {
+		writel(readl(GPIO_DIR(m)) & (~(1 << n)), GPIO_DIR(m));
+	} else {
+		writel(readl(GPIO_DIR(m)) | (1 << n), GPIO_DIR(m));
+	}
+	return 0;
+}
+
+inline void gpio_set(unsigned nr, unsigned on) {
+	writel(on, GPIO_WORD(nr));
+}
+
+inline int gpio_get(unsigned nr) {
+	return readl(GPIO_WORD(nr)) & 1;
+}
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/defirq.h b/src/bsp/lk/platform/lpc43xx/include/platform/defirq.h
new file mode 100644
index 0000000..112466f
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/defirq.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+DEFIRQ(DAC)
+DEFIRQ(M0APP)
+DEFIRQ(DMA)
+DEFIRQ(RESERVED03)
+DEFIRQ(FLASHEEPROM)
+DEFIRQ(ETHERNET)
+DEFIRQ(SDIO)
+DEFIRQ(LCD)
+DEFIRQ(USB0)
+DEFIRQ(USB1)
+DEFIRQ(SCT)
+DEFIRQ(RITIMER)
+DEFIRQ(TIMER0)
+DEFIRQ(TIMER1)
+DEFIRQ(TIMER2)
+DEFIRQ(TIMER3)
+DEFIRQ(MCPWM)
+DEFIRQ(ADC0)
+DEFIRQ(I2C0)
+DEFIRQ(I2C1)
+DEFIRQ(SPI_INT)
+DEFIRQ(ADC1)
+DEFIRQ(SSP0)
+DEFIRQ(SSP1)
+DEFIRQ(USART0)
+DEFIRQ(UART1)
+DEFIRQ(USART2)
+DEFIRQ(USART3)
+DEFIRQ(I2S0)
+DEFIRQ(I2S1)
+DEFIRQ(SPIFI)
+DEFIRQ(SGPIO_INT)
+DEFIRQ(PIN_INT0)
+DEFIRQ(PIN_INT1)
+DEFIRQ(PIN_INT2)
+DEFIRQ(PIN_INT3)
+DEFIRQ(PIN_INT4)
+DEFIRQ(PIN_INT5)
+DEFIRQ(PIN_INT6)
+DEFIRQ(PIN_INT7)
+DEFIRQ(GINT0)
+DEFIRQ(GINT1)
+DEFIRQ(EVENTROUTER)
+DEFIRQ(C_CAN1)
+DEFIRQ(RESERVED44)
+DEFIRQ(ADCHS)
+DEFIRQ(ATIMER)
+DEFIRQ(RTC)
+DEFIRQ(RESERVED48)
+DEFIRQ(WWDT)
+DEFIRQ(M0SUB)
+DEFIRQ(C_CAN0)
+DEFIRQ(QEI)
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-clocks.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-clocks.h
new file mode 100644
index 0000000..5b760af
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-clocks.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define FREQ_MON		0x40050014
+#define XTAL_OSC_CTRL		0x40050018
+
+#define PLL0USB_STAT		0x4005001C
+#define PLL0USB_CTRL		0x40050020
+#define PLL0USB_MDIV		0x40050024
+#define PLL0USB_NP_DIV		0x40050028
+
+#define PLL0AUDIO_STAT		0x4005002C
+#define PLL0AUDIO_CTRL		0x40050030
+#define PLL0AUDIO_MDIV		0x40050034
+#define PLL0AUDIO_NP_DIV	0x40050038
+#define PLL0AUDIO_FRAC		0x4005003C
+
+#define PLL1_STAT		0x40050040
+#define PLL1_CTRL		0x40050044
+
+#define IDIVA_CTRL		0x40050048 // /(1..4)   IRC, CLKIN, XTAL, PLLs
+#define IDIVB_CTRL		0x4005004C // /(1..16)  IRC, CLKIN, XTAL, PLL0AUDIO, PLL1, IDIVA
+#define IDIVC_CTRL		0x40050050 // /(1..16)  "
+#define IDIVD_CTRL		0x40050054 // /(1..16)  "
+#define IDIVE_CTRL		0x40050058 // /(1..256) IRC, CLKIN, XTAL, PLL0AUDIO, PLL1, IDIVA
+
+#define BASE_SAFE_CLK		0x4005005C // only CLK_IRC allowed
+#define BASE_USB0_CLK		0x40050060 // only CLK_PLL0USB allowed
+#define BASE_PERIPH_CLK		0x40050064
+#define BASE_USB1_CLK		0x40050068
+#define BASE_M4_CLK		0x4005006C
+#define BASE_SPIFI_CLK		0x40050070
+#define BASE_SPI_CLK		0x40050074
+#define BASE_PHY_RX_CLK		0x40050078
+#define BASE_PHY_TX_CLK		0x4005008C
+#define BASE_APB1_CLK		0x40050080
+#define BASE_APB3_CLK		0x40050084
+#define BASE_LCD_CLK		0x40050088
+#define BASE_ADCHS_CLK		0x4005008C
+#define BASE_SDIO_CLK		0x40050090
+#define BASE_SSP0_CLK		0x40050094
+#define BASE_SSP1_CLK		0x40050098
+#define BASE_UART0_CLK		0x4005009C
+#define BASE_UART1_CLK		0x400500A0
+#define BASE_UART2_CLK		0x400500A4
+#define BASE_UART3_CLK		0x400500A8
+#define BASE_OUT_CLK		0x400500AC
+#define BASE_AUDIO_CLK		0x400500C0
+#define BASE_CGU_OUT0_CLK	0x400500C4
+#define BASE_CGU_OUT1_CLK	0x400500C8
+
+#define BASE_PD			(1 << 0) // power-down
+#define BASE_AUTOBLOCK		(1 << 11)
+#define BASE_CLK_SEL(n)		((n) << 24)
+
+#define PLL0_STAT_LOCK		(1 << 0)
+#define PLL0_STAT_FR		(1 << 1)
+
+#define PLL0_CTRL_PD		(1 << 0) // power down
+#define PLL0_CTRL_BYPASS	(1 << 1) // input sent to post-div
+#define PLL0_CTRL_DIRECTI	(1 << 2)
+#define PLL0_CTRL_DIRECTO	(1 << 3)
+#define PLL0_CTRL_CLKEN		(1 << 4)
+#define PLL0_CTRL_FRM		(1 << 6) // free running mode
+#define PLL0_CTRL_AUTOBLOCK	(1 << 11)
+#define PLL0_CTRL_CLK_SEL(n)	((n) << 24) // input clock select
+// PLL0AUDIO only:
+#define PLL0_CTRL_PLLFRACT_REQ	(1 << 12)
+#define PLL0_CTRL_SEL_EXT	(1 << 13)
+#define PLL0_CTRL_MOD_PD	(1 << 14)
+
+#define PLL1_STAT_LOCK		(1 << 0)
+
+#define PLL1_CTRL_PD		(1 << 0)
+#define PLL1_CTRL_BYPASS	(1 << 1)
+#define PLL1_CTRL_FBSEL		(1 << 6)
+#define PLL1_CTRL_DIRECT	(1 << 7)
+#define PLL1_CTRL_PSEL_1	(0 << 8)
+#define PLL1_CTRL_PSEL_2	(1 << 8)
+#define PLL1_CTRL_PSEL_4	(2 << 8)
+#define PLL1_CTRL_PSEL_8	(3 << 8)
+#define PLL1_CTRL_AUTOBLOCK	(1 << 11)
+#define PLL1_CTRL_NSEL_1	(0 << 12)
+#define PLL1_CTRL_NSEL_2	(1 << 12)
+#define PLL1_CTRL_NSEL_3	(2 << 12)
+#define PLL1_CTRL_NSEL_4	(3 << 12)
+#define PLL1_CTRL_MSEL(m)	(((m) - 1) << 16)
+#define PLL1_CTRL_CLK_SEL(c)	((c) << 24)
+
+#define IDIV_PD			(1 << 0)
+#define IDIV_N(n)		(((n) - 1) << 2)
+#define IDIV_AUTOBLOCK		(1 << 11)
+#define IDIV_CLK_SEL(c)		((c) << 24)
+
+#define CLK_32K			0x00
+#define CLK_IRC			0x01 // 12MHz internal RC OSC
+#define CLK_ENET_RX		0x02
+#define CLK_ENET_TX		0x03
+#define CLK_GP_CLKIN		0x04
+#define CLK_XTAL		0x06 // crystal oscillator
+#define CLK_PLL0USB		0x07 // only for BASE_{USB0,USB1,OUT}_CLK
+#define CLK_PLL0AUDIO		0x08
+#define CLK_PLL1		0x09
+#define CLK_IDIVA		0x0C
+#define CLK_IDIVB		0x0D
+#define CLK_IDIVC		0x0E
+#define CLK_IDIVD		0x0F
+#define CLK_IDIVE		0x10
+
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpdma.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpdma.h
new file mode 100644
index 0000000..949b90b
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpdma.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+// these are bitmasks of ch0..ch7 in bit0..bit7
+#define DMA_INTSTAT		0x40002000 // ro: INTTCSTAT | INTERRSTAT
+#define DMA_INTTCSTAT		0x40002004
+#define DMA_INTTCCLR		0x40002008 // wtc
+#define DMA_INTERRSTAT		0x4000200C
+#define DMA_INTERRCLR		0x40002010 // wtc
+#define DMA_INTTCRAW		0x40002014 // not masked
+#define DMA_INTERRRAW		0x40002018 // not masked
+#define DMA_ENABLED		0x4000201C
+
+#define DMA_CONFIG		0x40002030
+#define DMA_CONFIG_EN		(1 << 0) // enable controller
+#define DMA_CONFIG_M0_BE	(1 << 1) // master0 big-endian mode
+#define DMA_CONFIG_M1_BE	(1 << 2) // master1 big-endian mode
+
+#define DMA_SRC(n)		(0x40002100 + ((n) * 0x20))
+#define DMA_DST(n)		(0x40002104 + ((n) * 0x20))
+#define DMA_LLI(n)		(0x40002108 + ((n) * 0x20))
+#define DMA_CTL(n)		(0x4000210C + ((n) * 0x20))
+#define DMA_CFG(n)		(0x40002110 + ((n) * 0x20))
+
+// DMA_CTL bits
+#define BURST_1			0
+#define BURST_4			1
+#define BURST_8			2
+#define BURST_16		3
+#define BURST_32		4
+#define BURST_64		5
+#define BURST_128		6
+#define BURST_256		7
+
+#define DMA_XFER_SIZE(n)	((n) & 0xFFF)
+#define DMA_SRC_BURST(sz)	(((sz) & 7) << 12)
+#define DMA_DST_BURST(sz)	(((sz) & 7) << 15)
+#define DMA_SRC_BYTE		(0 << 18)
+#define DMA_SRC_HALF		(1 << 18)
+#define DMA_SRC_WORD		(2 << 18)
+#define DMA_DST_BYTE		(0 << 21)
+#define DMA_DST_HALF		(1 << 21)
+#define DMA_DST_WORD		(2 << 21)
+#define DMA_SRC_MASTER0		(0 << 24)
+#define DMA_SRC_MASTER1		(1 << 24)
+#define DMA_DST_MASTER0		(0 << 25) // memory only
+#define DMA_DST_MASTER1		(1 << 25)
+#define DMA_SRC_INCR		(1 << 26)
+#define DMA_DST_INCR		(1 << 27)
+#define DMA_PROT1		(1 << 28) // Privileged
+#define DMA_PROT2		(1 << 29) // Bufferable
+#define DMA_PROT3		(1 << 30) // Cacheable
+#define DMA_TC_IE		(1 << 31) // enable irq on terminal count
+
+// DMA_CFG bits
+#define DMA_ENABLE		(1 << 0)
+#define DMA_SRC_PERIPH(n)	(((n) & 15) << 1)
+#define DMA_DST_PERIPH(n)	(((n) & 15) << 6)
+#define DMA_FLOW_M2M_DMAc	(0 << 11) // dma ctl
+#define DMA_FLOW_M2P_DMAc	(1 << 11) // dma ctl
+#define DMA_FLOW_P2M_DMAc	(2 << 11) // dma ctl
+#define DMA_FLOW_P2P_DMAc	(3 << 11) // dma ctl
+#define DMA_FLOW_P2P_DPc	(4 << 11) // dst per ctl
+#define DMA_FLOW_M2P_DPc	(5 << 11) // dst per ctl
+#define DMA_FLOW_P2M_SPc	(6 << 11) // src per ctl
+#define DMA_FLOW_P2P_SPc	(7 << 11) // src per ctl
+#define DMA_ERR_IRQ_EN		(1 << 14)
+#define DMA_TC_IRQ_EN		(1 << 15)
+#define DMA_LOCK_XFER		(1 << 16)
+#define DMA_ACTIVE		(1 << 17) // ro: data in fifo
+#define DMA_HALT		(1 << 18) // ignore source dreqs, drain fifo
+
+
+#define DMAMUX_REG	0x4004311C
+
+#define DMAMUX_P(n,v)	(((v) & 3) << (((n) & 15) << 1))
+#define DMAMUX_M(n)	(~DMAMUX_P(n,3))
+
+#define P0_SPIFI	0
+#define P0_SCT_OUT2	1
+#define P0_SGPIO14	2
+#define P0_TIMER3_M1	3
+
+#define P1_TIMER0_M0	0
+#define P1_USART0_TX	1
+#define P1_AES_IN	3
+
+#define P2_TIMER0_M1	0
+#define P2_USART0_RX	1
+#define P2_AES_OUT	3
+
+#define P3_TIMER1_M0	0
+#define P3_UART1_TX	1
+#define P3_I2S1_DMA1	2
+#define P3_SSP1_TX	3
+
+#define P4_TIMER1_M1	0
+#define P4_UART1_RX	1
+#define P4_I2S1_DMA2	2
+#define P4_SSP1_RX	3
+
+#define P5_TIMER2_M0	0
+#define P5_USART2_TX	1
+#define P5_SSP1_TX	2
+#define P5_SGPIO15	3
+
+#define P6_TIMER2_M1	0
+#define P6_USART2_RX	1
+#define P6_SSP1_RX	2
+#define P6_SGPIO14	3
+
+#define P7_TIMER3_M0	0
+#define P7_USART3_TX	1
+#define P7_SCT_DMA0	2
+#define P7_ADCHS_WR	3
+
+#define P8_TIMER3_M1	0
+#define P8_USART3_RX	1
+#define P8_SCT_DMA1	2
+#define P8_ADCHS_RD	3
+
+#define P9_SSP0_RX	0
+#define P9_I2S0_DMA1	1
+#define P9_SCT_DMA1	2
+
+#define P10_SSP0_RX	0
+#define P10_I2S0_DMA2	1
+#define P10_SCT_DMA0	2
+
+#define P11_SSP1_RX	0
+#define P11_SGPIO14	1
+#define P11_USART0_TX	2
+
+#define P12_SSP1_RX	0
+#define P12_SGPIO15	1
+#define P12_USART0_RX	2
+
+#define P13_ADC0	0
+#define P13_AES_IN	1
+#define P13_SSP1_RX	2
+#define P13_USART3_RX	3
+
+#define P14_ADC1	0
+#define P14_AES_OUT	1
+#define P14_SSP1_TX	2
+#define P14_USART3_TX	3
+
+#define P15_DAC		0
+#define P15_SCT_OUT3	1
+#define P15_SGPIO15	2
+#define P15_TIMER3_M0	3
+
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpio.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpio.h
new file mode 100644
index 0000000..a53b358
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-gpio.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <dev/gpio.h>
+
+// pinmux
+#define PIN(m,n)	((((m) & 0xFF) << 8) | ((n) & 0xFF))
+#define _PINm(nr)	(((nr) >> 8) & 0xFF)
+#define _PINn(nr)	((nr) & 0xFF)
+
+#define _PIN_CFG(m,n)	(0x40086000 + ((m) * 0x80) + ((n) * 4))
+#define PIN_CFG(nr)	_PIN_CFG(_PINm(nr),_PINn(nr))
+
+#define PIN_MODE(n)	((n) & 7)
+#define PIN_PULLUP	(0 << 3) // pull-up, no pull-down
+#define PIN_REPEATER	(1 << 3) // repeater mode
+#define PIN_PLAIN	(2 << 3) // no pull-up, no pull-down
+#define PIN_PULLDOWN	(3 << 3) // pull-down, no pull-up
+#define PIN_SLOW	(0 << 5) // slow slew rate (low noise, medium speed)
+#define PIN_FAST	(1 << 5) // fast slew rate (medium noise, fast speed)
+#define PIN_INPUT	(1 << 6) // enable input buffer, required for inputs
+#define PIN_FILTER	(1 << 7) // enable glitch filter, not for >30MHz signals
+
+static inline void pin_config(unsigned nr, unsigned flags) {
+	writel(flags, PIN_CFG(nr));
+}
+
+// gpio
+#define GPIO(m,n) ((((m) & 0xFF) << 8) | ((n) & 0xFF))
+#define _GPIOm(nr)	(((nr) >> 8) & 0xFF)
+#define _GPIOn(nr)	((nr) & 0xFF)
+
+// each GPIO as a single byte or word register
+// write zero to clear
+// write non-zero to set
+// reads as zero if input is low
+// reads as FF (byte) or FFFFFFFF (word) if input is high
+#define _GPIO_BYTE(m,n)	(0x400F4000 + ((m) * 0x20) + (n))
+#define _GPIO_WORD(m,n)	(0x400F5000 + ((m) * 0x80) + ((n) * 4))
+#define GPIO_BYTE(nr)	_GPIO_BYTE(_GPIOm(nr),_GPIOn(nr))
+#define GPIO_WORD(nr)	_GPIO_WORD(_GPIOm(nr),_GPIOn(nr))
+
+// GPIOs grouped by port, with one bit per pin
+#define GPIO_DIR(m)	(0x400F6000 + ((m) * 4)) // 1 = output, 0 = input
+#define GPIO_MASK(m)	(0x400F6080 + ((m) * 4)) // 1s disable MPIN() bits
+#define GPIO_PIN(m)	(0x400F6100 + ((m) * 4)) // r/w value at pins
+#define GPIO_MPIN(m)	(0x400F6180 + ((m) * 4)) // r value at pins & ~MASK
+						 // w only MASK bits
+#define GPIO_SET(m)	(0x400F6200 + ((m) * 4)) // write 1s to set
+#define GPIO_CLR(m)	(0x400F6280 + ((m) * 4)) // write 1s to clear
+#define GPIO_NOT(m)	(0x400F6300 + ((m) * 4)) // write 1s to invert
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-sgpio.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-sgpio.h
new file mode 100644
index 0000000..cac3e83
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-sgpio.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define SGPIO_OUT_CFG(n)	(0x40101000 + ((n) * 4))
+#define CFG_OUT_M1		0x00
+#define CFG_OUT_M2A		0x01
+#define CFG_OUT_M2B		0x02
+#define CFG_OUT_M2C		0x03
+#define CFG_OUT_GPIO		0x04
+#define CFG_OUT_M4A		0x05
+#define CFG_OUT_M4B		0x06
+#define CFG_OUT_M4C		0x07
+#define CFG_OUT_CLK		0x08
+#define CFG_OUT_M8A		0x09
+#define CFG_OUT_M8B		0x0A
+#define CFG_OUT_M8C		0x0B
+#define CFG_OE_GPIO		0x00
+#define CFG_OE_M1		0x40
+#define CFG_OE_M2		0x50
+#define CFG_OE_M4		0x60
+#define CFG_OE_M8		0x70
+
+#define SLICE_CFG1(n) 		(0x40101040 + ((n) * 4))
+#define CLK_USE_SLICE		(0 << 0)
+#define CLK_USE_PIN		(1 << 0)
+#define CLK_PIN_SGPIO8		(0 << 1)
+#define CLK_PIN_SGPIO9		(1 << 1)
+#define CLK_PIN_SGPIO10		(2 << 1)
+#define CLK_PIN_SGPIO11		(3 << 1)
+#define CLK_SLICE_D		(0 << 3)
+#define CLK_SLICE_H		(1 << 3)
+#define CLK_SLICE_O		(2 << 3)
+#define CLK_SLICE_P		(3 << 3)
+#define QUAL_ENABLE		(0 << 5)
+#define QUAL_DISABLE		(1 << 5)
+#define QUAL_USE_SLICE		(2 << 5)
+#define QUAL_USE_PIN		(3 << 5)
+#define QUAL_PIN_SGPIO8		(0 << 7)
+#define QUAL_PIN_SGPIO9		(1 << 7)
+#define QUAL_PIN_SGPIO10	(2 << 7)
+#define QUAL_PIN_SGPIO11	(3 << 7)
+#define QUAL_SLICE_A		(0 << 9) // D for SLICE A
+#define QUAL_SLICE_H		(1 << 9) // O for SLICE H
+#define QUAL_SLICE_I		(2 << 9) // D for SLICE I
+#define QUAL_SLICE_P		(3 << 9) // O for SLICE P
+#define CONCAT_PIN		(0 << 11)
+#define CONCAT_SLICE		(1 << 11)
+#define CONCAT_LOOP		(0 << 12)
+#define CONCAT_2_SLICE		(1 << 12)
+#define CONCAT_4_SLICE		(2 << 12)
+#define CONCAT_8_SLICE		(3 << 12)
+
+#define SLICE_CFG2(n)		(0x40101080 + ((n) * 4))
+#define MATCH_MODE		(1 << 0)
+#define CLK_GEN_INTERNAL	(0 << 2) // from COUNTER
+#define CLK_GEN_EXTERNAL	(1 << 2) // from PIN or SLICE
+#define INV_CLK_OUT		(1 << 3)
+#define SHIFT_1BPC		(0 << 6)
+#define SHIFT_2BPC		(1 << 6)
+#define SHIFT_4BPC		(2 << 6)
+#define SHIFT_8BPC		(3 << 6)
+#define INVERT_QUALIFIER	(1 << 8)
+
+#define SLICE_REG(n)		(0x401010C0 + ((n) * 4)) // main shift reg
+#define SLICE_SHADOW(n)		(0x40101100 + ((n) * 4)) // swapped @ POS underflow
+#define SLICE_PRESET(n)		(0x40101140 + ((n) * 4)) // 12bit -> COUNT @ 0
+#define SLICE_COUNT(n)		(0x40101180 + ((n) * 4)) // 12 bit downcount
+#define SLICE_POS(n)		(0x401011C0 + ((n) * 4))
+#define POS_POS(n)		((n) << 0) // value at start
+#define POS_RESET(n)		((n) << 8) // load at underflow
+
+#define SGPIO_IN		(0x40101210)
+#define SGPIO_OUT		(0x40101214)
+#define SGPIO_OEN		(0x40101218)
+#define SLICE_CTRL_ENABLE	(0x4010121C)
+#define SLICE_CTRL_DISABLE	(0x40101220)
+#define SLICE_XHG_STS		(0x40101F2C)
+#define SLICE_XHG_STS_CLR	(0x40101F30)
+#define SLICE_XHG_STS_SET	(0x40101F34)
+
+#define SLC_A			0
+#define SLC_B			1
+#define SLC_C			2
+#define SLC_D			3
+#define SLC_E			4
+#define SLC_F			5
+#define SLC_G			6
+#define SLC_H			7
+#define SLC_I			8
+#define SLC_J			9
+#define SLC_K			10
+#define SLC_L			11
+#define SLC_M			12
+#define SLC_N			13
+#define SLC_O			14
+#define SLC_P			15
+
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-spifi.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-spifi.h
new file mode 100644
index 0000000..6902ab4
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-spifi.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define SPIFI_CTRL		0x40003000 // Control
+#define SPIFI_CMD		0x40003004 // Command
+#define SPIFI_ADDR		0x40003008 // Address
+#define SPIFI_IDATA		0x4000300C // Intermediate Data
+#define SPIFI_CLIMIT		0x40003010 // Cache Limit
+#define SPIFI_DATA		0x40003014 // Data
+#define SPIFI_MCMD		0x40003018 // Memory Command
+#define SPIFI_STAT		0x4000301C // Status
+
+#define CTRL_TIMEOUT(n)		((n) & 0xFFFF)
+#define CTRL_CSHIGH(n)		(((n) & 0xF) << 16) // Minimum /CS high time (serclks - 1)
+#define CTRL_D_PRFTCH_DIS	(1 << 21) // Disable Prefetch of Data
+#define CTRL_INTEN		(1 << 22) // Enable IRQ on end of command
+#define CTRL_MODE3		(1 << 23) // 0=SCK low after +edge of last bit, 1=high
+#define CTRL_PRFTCH_DIS		(1 << 27) // Disable Prefetch
+#define CTRL_DUAL		(1 << 28) // 0=Quad 1=Dual (bits in "wide" ops)
+#define CTRL_QUAD		(0 << 28)
+#define CTRL_RFCLK		(1 << 29) // 1=sample read data on -edge clock
+#define CTRL_FBCLK		(1 << 30) // use feedback clock from SCK pin for sampling
+#define CTRL_DMAEN		(1 << 31) // enable DMA request output
+
+#define CMD_DATALEN(n)		((n) & 0x3FFF)
+#define CMD_POLL		(1 << 14) // if set, read byte repeatedly until condition
+#define CMD_POLLBIT(n)		((n) & 7) // which bit# to check
+#define CMD_POLLSET		(1 << 3)  // condition is bit# set
+#define CMD_POLLCLR		(0 << 3)  // condition is bit# clear
+#define CMD_DOUT		(1 << 15) // 1=data phase output, 0=data phase input
+#define CMD_DIN			(0 << 15)
+#define CMD_INTLEN(n)		(((n) & 7) << 16) // count of intermediate bytes
+#define CMD_FF_SERIAL		(0 << 19) // all command fields serial
+#define CMD_FF_WIDE_DATA	(1 << 19) // data is wide, all other fields serial
+#define CMD_FF_SERIAL_OPCODE	(2 << 19) // opcode is serial, all other fields wide
+#define CMD_FF_WIDE		(3 << 19) // all command fields wide
+#define CMD_FR_OP		(1 << 21) // frame format: opcode only
+#define CMD_FR_OP_1B		(2 << 21) // opcode, lsb addr
+#define CMD_FR_OP_2B		(3 << 21) // opcode, 2 lsb addr
+#define CMD_FR_OP_3B		(4 << 21) // opcode, 3 lsb addr
+#define CMD_FR_OP_4B		(5 << 21) // opcode, 4b address
+#define CMD_FR_3B		(6 << 21) // 3 lsb addr
+#define CMD_FR_4B		(7 << 21) // 4 lsb addr
+#define CMD_OPCODE(n)		((n) << 24)
+
+// MCMD register defines CMD for automatic reads
+// Similar to CMD, but
+// DATALEN, POLL, DOUT must be 0
+
+#define STAT_MCINIT		(1 << 0) // set on sw write to MCMD, clear on RST, wr(0)
+#define STAT_CMD		(1 << 1) // set when CMD written, clear on CS, RST
+#define STAT_RESET		(1 << 4) // write 1 to abort current txn or memory mode
+#define STAT_INTRQ		(1 << 5) // read IRQ status, wr(1) to clear
+
+// 1. Write ADDR
+// 2. Write CMD
+// 3. Read/Write DATA necessary number of times to transfer DATALEN bytes
+//    (byte/half/word ops move 1/2/4 bytes at a time)
+
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-uart.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-uart.h
new file mode 100644
index 0000000..26a7ea1
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-uart.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define UART0_BASE	0x40081000
+#define UART1_BASE	0x40082000
+#define UART2_BASE	0x400C1000
+#define UART3_BASE	0x400C2000
+
+#define REG_RBR		0x00 // RO Recv Buffer       (DLAB==0)
+#define REG_THR		0x00 // WO Xmit Holding      (DLAB==0)
+#define REG_IER		0x04 // RW Interrupt Enable  (DLAB==0)
+#define REG_DLL		0x00 // RW Divisor Latch LSB (DLAB==1)
+#define REG_DLM		0x04 // RW Divisor Latch MSB (DLAB==1)
+#define REG_IIR		0x08 // RO Interrupt ID
+#define REG_FCR		0x08 // WO Fifo Control
+#define REG_LCR		0x0C // RW Line Control
+#define REG_MCR		0x10 // RW Modem Control (UART1 only)
+#define REG_LSR		0x14 // RO Line Status
+#define REG_MSR		0x18 // RO Modem Status (UART1 only)
+#define REG_SCR		0x1C // RW Scratcpad (no hw use)
+#define REG_ACR		0x20 // RW Auto-baud Control
+#define REG_ICR		0x24 // RW IrDA Control
+#define REG_FDR		0x28 // RW Fractional Divider
+#define REG_OSR		0x2C // RW Oversampling (REG0/2/3 only)
+
+#define IER_RBRIE	(1 << 0) // enable receive data avail
+#define IER_THREIE	(1 << 1) // enable THRE irq
+#define IER_RXIE	(1 << 2) // enable RX Line Status IRQs
+
+#define IIR_INTSTATUS	(1 << 0) // 0=IRQ Pending
+#define IIR_INTID_MASK	(3 << 1)
+#define IIR_INTID_RLS	(3 << 1) // Receive Line Status
+				 // Cleared on LSR Read
+#define IIR_INTID_RDA	(2 << 1) // Receive Data Available
+				 // Cleared when FIFO < trigger level
+#define IIR_INTID_CTI	(6 << 1) // Character Timeout
+				 // data in FIFO, and 3.5-4.5 char times idle
+#define IIR_INTID_THRE	(1 << 1) // Transmit Holding Register Empty
+#define IIR_INTID_NONE	(0 << 1)
+
+#define FCR_FIFOEN	(1 << 0) // enable FIFO
+#define FCR_RXFIFORES	(1 << 1) // RX FIFO reset
+#define FCR_TXFIFORES	(1 << 2) // TX FIFO reset
+#define FCR_DMAMODE	(1 << 3) // select DMA mode
+#define FCR_RX_TRIG_1	(0 << 6) // RX Trigger at 1 byte
+#define FCR_RX_TRIG_4	(1 << 6) // RX Trigger at 4 bytes
+#define FCR_RX_TRIG_8	(2 << 6) // RX Trigger at 8 bytes
+#define FCR_RX_TRIG_14	(3 << 6) // RX Trigger at 14 bytes
+
+#define LCR_WLS_5	(0 << 0) // 5bit character
+#define LCR_WLS_6	(1 << 0) // 6bit character
+#define LCR_WLS_7	(2 << 0) // 7bit character
+#define LCR_WLS_8	(3 << 0) // 8bit character
+#define LCR_SBS_1	(0 << 2) // 1 stop bit
+#define LCR_SBS_2	(1 << 2) // 2 stop bits
+#define LCR_PE		(1 << 3) // parity enable
+#define LCR_PS_ODD	(0 << 4) // odd parity
+#define LCR_PS_EVEN	(1 << 4) // even parity
+#define LCR_PS_HIGH	(2 << 4) // always-1 parity
+#define LCR_PS_LOW	(3 << 4) // always-0 parity
+#define LCR_BC		(1 << 6) // enable break transmission
+#define LCR_DLAB	(1 << 7) // enable access to divisor latches
+
+#define LSR_RDR		(1 << 0) // receiver data ready
+#define LSR_OE		(1 << 1) // overrun error (fifo was full, character lost)
+#define LSR_PE		(1 << 2) // parity error (top of fifo)
+#define LSR_FE		(1 << 3) // framing error (top of fifo)
+#define LSR_BI		(1 << 4) // break interrupt
+#define LSR_THRE	(1 << 5) // transmit holding register empty
+#define LSR_TEMT	(1 << 6) // transmitter empty
+#define LSR_RXFE	(1 << 7) // error in RX FIFO
+#define LSR_TXERR	(1 << 8) // NACK received in smart card mode
+
+#define FDR_DIVADDVAL(n) ((n) & 0xF)
+#define FDR_MULVAL(n) (((n) & 0xF) << 4)
+
+// baud rate selection:
+//
+// PCLK / ( 16 * ( 256 * DLM + DLL ) * ( 1 + ( DivAddVal / MulVal ) )
+//
+// 1 <= MulVal <= 15            DivAddVal == 0  -> Disables Frac Divider
+// 0 <= DivAddVal <= 14
+// DivAddVal < MulVal
+
+
+#define OSR_OSFRAC(n)	(((n) & 0x3) << 1) // fractional part
+#define OSR_OSINT(n)	(((n) & 0xF) << 4) // integer part - 1
+
+// oversampling rate = OsInt + 1 + ( 1/8 * OsFrac)   (default is 16)
+
+
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-usb.h b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-usb.h
new file mode 100644
index 0000000..d8cb0ac
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/lpc43xx-usb.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define USB0_BASE		0x40006000
+
+#define USB_CMD			0x140
+#define USB_STS			0x144
+#define USB_INTR		0x148
+#define USB_FRINDEX		0x14C
+#define USB_DEVICEADDR		0x154
+#define USB_ENDPOINTLISTADDR 	0x158
+#define USB_BURSTSIZE		0x160
+#define USB_ENDPTNAK		0x178
+#define USB_ENDPTNAKEN		0x17C
+#define USB_PORTSC1		0x184
+#define USB_OTGSC		0x1A4
+#define USB_MODE		0x1A8
+#define USB_ENDPTSETUPSTAT	0x1AC
+#define USB_ENDPTPRIME		0x1B0
+#define USB_ENDPTFLUSH		0x1B4
+#define USB_ENDPTSTAT		0x1B8
+#define USB_ENDPTCOMPLETE	0x1BC
+#define USB_ENDPTCTRL(n)	(0x1C0 + (n) * 4)
+
+
+#define CMD_RUN			(1 << 0) // initiate attach
+#define CMD_STOP		(0 << 0) // detach
+#define CMD_RST			(1 << 1) // reset controller, raz when done
+#define CMD_SUTW		(1 << 13) // SetUp TripWire
+#define CMD_ATDTW		(1 << 14) // Add TD TripWire
+#define CMD_ITC_0		(0 << 16) // IRQ Threshold Immediate
+#define CMD_ITC_1		(1 << 16) // 1 microframe
+#define CMD_ITC_2		(2 << 16) // 2 microframes
+#define CMD_ITC_8		(8 << 16) // 8 microframes
+#define CMD_ITC_16		(16 << 16) // 16 microframes
+#define CMD_ITC_32		(32 << 16) // 32 microframes
+#define CMD_ITC_64		(64 << 16) // 64 microframes
+
+#define STS_UI			(1 << 0) // USB Interrupt (WtC)
+#define STS_UEI			(1 << 1) // USB Error IRQ (WtC)
+#define STS_PCI			(1 << 2) // Port Change Detect (WtC)
+#define STS_SEI			(1 << 4) // System Error (fatal, reset)
+#define STS_URI			(1 << 6) // USB Reset (WtC)
+#define STS_SRI			(1 << 7) // SOF Received (WtC)
+#define STS_SLI			(1 << 8) // DC Suspend (WtC)
+#define STS_NAKI		(1 << 16) // 1 when EPT NAK bits set
+
+#define INTR_UE			(1 << 0) // USB Interrupt Enable
+#define INTR_UEE		(1 << 1) // USB Error IRQ Enable
+#define INTR_PCE		(1 << 2) // Port Change Detect IRQ Enable
+#define INTR_SEE		(1 << 4) // System Error IRQ Enable
+#define INTR_URE		(1 << 6) // USB Reset IRQ Enable
+#define INTR_SRE		(1 << 7) // SOF Received IRQ Enable
+#define INTR_SLE		(1 << 8) // DC Suspend IRQ Enable
+#define INTR_NAKE		(1 << 16) // NAK IRQ Enable
+
+#define PORTSC1_CCS		(1 << 0) // device is attached
+#define PORTSC1_PE		(1 << 2) // port enable (always 1)
+#define PORTSC1_PEC		(1 << 3) // always 0
+#define PORTSC1_FPR		(1 << 6) // force port resume
+#define PORTSC1_SUSP		(1 << 7) // ro: 1 = port suspended
+#define PORTSC1_RC		(1 << 8) // ro: 1 = port in reset
+#define PORTSC1_HSP		(1 << 9) // ro: 1 = port in high-speed
+#define PORTSC1_PFSC		(1 << 24) // 1 = force full-speed only
+
+#define OTG_VD			(1 << 0)  // vbus discharge
+#define OTG_VC			(1 << 1)  // vbus charge
+#define OTG_HAAR		(1 << 2)  // hardware assist auto-reset
+#define OTG_OT			(1 << 3)  // OTG termination
+#define OTG_DP			(1 << 4)  // data pulsing
+#define OTG_IDPU		(1 << 5)  // ID pull-up
+#define OTG_HADP		(1 << 6)  // hardware assist data pulse
+#define OTG_HABA		(1 << 7)  // hardware assist B-dis to A-con
+#define OTG_ID			(1 << 8)  // 0 = A-device, 1 = B-device
+#define OTG_AVV			(1 << 9)  // A-VBUS Valid
+#define OTG_ASV			(1 << 10) // A-Session Valid
+#define OTG_BSV			(1 << 11) // B-Session Valid
+#define OTG_BSE			(1 << 12) // B-Session End
+#define OTG_MS1T		(1 << 13) // 1ms Timer Toggle
+#define OTG_DPS			(1 << 14) // 1 = data pulsing detected
+#define OTG_IDIS		(1 << 16) // irq status bits (r/wc)
+#define OTG_AVVIS		(1 << 17)
+#define OTG_ASVIS		(1 << 18)
+#define OTG_BSVIS		(1 << 19)
+#define OTG_BSEIS		(1 << 20)
+#define OTG_MS1S		(1 << 21)
+#define OTG_DPIS		(1 << 22)
+#define OTG_IDIE		(1 << 24) // irq enable bits (rw)
+#define OTG_AVVIE		(1 << 25)
+#define OTG_ASVIE		(1 << 26)
+#define OTG_BSVIE		(1 << 27)
+#define OTG_BSEIE		(1 << 28)
+#define OTG_MS1E		(1 << 29)
+#define OTG_DPIE		(1 << 30)
+
+//#define MODE_MASK		3
+#define MODE_IDLE		0 // write once to enter device/host mode
+#define MODE_DEVICE		2 // must reset to idle to change mode
+#define MODE_HOST		3 // nust reset to idle to change mode
+#define MODE_ES			(1 << 2) // select big endian
+#define MODE_SLOM		(1 << 3) // enable setup lockout mode
+#define MODE_SDIS		(1 << 4) // enable stream disable mode
+
+// bits for ENDPTCTRL(n)
+#define EPCTRL_RXS		(1 << 0) // rx ept stall
+#define EPCTRL_RX_CTRL		(0 << 2)
+#define EPCTRL_RX_ISOC		(1 << 2)
+#define EPCTRL_RX_BULK		(2 << 2)
+#define EPCTRL_RX_INTR		(3 << 2)
+#define EPCTRL_RXR		(1 << 6) // tx data toggle reset
+#define EPCTRL_RXE		(1 << 7) // rx ept enable
+#define EPCTRL_TXS		(1 << 16) // tx ept stall
+#define EPCTRL_TX_CTRL		(0 << 18)
+#define EPCTRL_TX_ISOC		(1 << 18)
+#define EPCTRL_TX_BULK		(2 << 18)
+#define EPCTRL_TX_INTR		(3 << 18)
+#define EPCTRL_TXR		(1 << 22) // tx data toggle reset
+#define EPCTRL_TXE		(1 << 23) // rx ept enable
+// Do not leave unconfigured endpoints as CTRL when enabling
+// their sibling, or data PID tracking will be undefined
+
+// bits for all other ENDPT* registers
+#define EP0_RX			(1 << 0)
+#define EP1_RX			(1 << 1)
+#define EP2_RX			(1 << 2)
+#define EP3_RX			(1 << 3)
+#define EP4_RX			(1 << 4)
+#define EP5_RX			(1 << 5)
+#define EP0_TX			(1 << 16)
+#define EP1_TX			(1 << 17)
+#define EP2_TX			(1 << 18)
+#define EP3_TX			(1 << 19)
+#define EP4_TX			(1 << 20)
+#define EP5_TX			(1 << 21)
+
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+#define DQH_MULT0		(0 << 30) // non-iscoh
+#define DQH_MULT1		(1 << 30) // 1 txn per td
+#define DQH_MULT2		(2 << 30) // 2 txn per td
+#define DQH_MULT3		(3 << 30) // 3 txn per td
+#define DQH_CFG_ZLT		(1 << 29) // disable zero-length terminate
+#define DQH_CFG_MAXPKT(n)	((n) << 16) // <= 1024
+#define DQH_CFG_IOS		(1 << 15) // IRQ on SETUP
+
+#define DTD_LEN(n)		((n) << 16)
+#define DTD_IOC			(1 << 15) // interrupt on complete
+#define DTD_MULT0		(0 << 10)
+#define DTD_MULT1		(1 << 10)
+#define DTD_MULT2		(2 << 10)
+#define DTD_MULT3		(3 << 10)
+#define DTD_STS_MASK		0xE8
+#define DTD_ACTIVE		0x80
+#define DTD_HALTED		0x40
+#define DTD_BUF_ERR		0x20
+#define DTD_TXN_ERR		0x08
+
+typedef struct usb_dtd {
+	u32 next_dtd;
+	u32 config;
+	u32 bptr0;
+	u32 bptr1;
+	u32 bptr2;
+	u32 bptr3;
+	u32 bptr4;
+	struct usb_dtd *next;
+} usb_dtd_t;
+
+typedef struct usb_dqh {
+	u32 config;
+	u32 current_dtd;
+	u32 next_dtd;
+	u32 dtd_config;
+	u32 dtd_bptr0;
+	u32 dtd_bptr1;
+	u32 dtd_bptr2;
+	u32 dtd_bptr3;
+	u32 dtd_bptr4;
+	u32 dtd_rsvd0;
+	u32 setup0;
+	u32 setup1;
+	u32 rsvd1;
+	u32 rsvd2;
+	u32 rsvd3;
+	u32 rsvd4;
+} usb_dqh_t;
diff --git a/src/bsp/lk/platform/lpc43xx/include/platform/platform_cm.h b/src/bsp/lk/platform/lpc43xx/include/platform/platform_cm.h
new file mode 100644
index 0000000..8e92b78
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/include/platform/platform_cm.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define __CM4_REV		1
+#define __MPU_PRESENT		1
+#define __NVIC_PRIO_BITS	3
+#define __Vendor_SysTickConfig	0
+#define __FPU_PRESENT		1
+
+#define DEFIRQ(x) x##_IRQn,
+typedef enum {
+	Reset_IRQn = -15,
+	NonMaskableInt_IRQn = -14,
+	HardFault_IRQn = -13,
+	MemoryManagement_IRQn = -12,
+	BusFault_IRQn = -11,
+	UsageFault_IRQn = -10,
+	SVCall_IRQn = -5,
+	DebugMonitor_IRQn = -4,
+	PendSV_IRQn = -2,
+	SysTick_IRQn = -1,
+#include <platform/defirq.h>
+} IRQn_Type;
+#undef DEFIRQ
+
diff --git a/src/bsp/lk/platform/lpc43xx/init.c b/src/bsp/lk/platform/lpc43xx/init.c
new file mode 100644
index 0000000..56639aa
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/init.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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 <arch/arm/cm.h>
+#include <kernel/thread.h>
+#include <platform.h>
+
+#include <platform/lpc43xx-clocks.h>
+
+void lpc43xx_debug_early_init(void);
+void lpc43xx_debug_init(void);
+
+uint8_t __lpc43xx_main_clock_sel;
+uint32_t __lpc43xx_main_clock_mhz;
+
+void platform_early_init(void)
+{
+#ifndef WITH_NO_CLOCK_INIT
+	unsigned cfg;
+	// Different boot modes will enable different sets of clocks.
+	// To keep it simple, we drop back to the 12MHz internal osc,
+	// power down the other clocks, and bring things back up in an
+	// orderly fashion.  This costs a few hundred microseconds.
+
+	// switch CPU clock to 12MHz internal osc
+	writel(readl(BASE_M4_CLK) | BASE_AUTOBLOCK, BASE_M4_CLK);
+	writel(BASE_CLK_SEL(CLK_IRC) | BASE_AUTOBLOCK, BASE_M4_CLK);
+
+	// Disable PLL1, if it was already running
+	writel(PLL1_CTRL_PD, PLL1_CTRL);
+
+	// Disable PLL0USB, if it was already running
+	writel(PLL0_CTRL_PD, PLL0USB_CTRL);
+
+	// Disable XTAL osc if it was already running
+	writel(readl(XTAL_OSC_CTRL) | 1, XTAL_OSC_CTRL);
+	// Disable BYPASS or HF modes:
+	writel(1, XTAL_OSC_CTRL);
+	// Enable, HF=0 BYPASS=0
+	writel(0, XTAL_OSC_CTRL);
+	// Wait
+	spin_cycles(3000); // 250uS @ 12MHz
+
+	// PLL1: 12MHz -> N=(/2) -> M=(x32) -> P=(/2)   96MHz
+	cfg = PLL1_CTRL_NSEL_2 | PLL1_CTRL_PSEL_1 | PLL1_CTRL_MSEL(32) |
+		PLL1_CTRL_CLK_SEL(CLK_XTAL) | PLL1_CTRL_AUTOBLOCK;
+	writel(cfg, PLL1_CTRL);
+	while (!(readl(PLL1_STAT) & PLL1_STAT_LOCK)) ;
+
+	writel(BASE_CLK_SEL(CLK_PLL1) | BASE_AUTOBLOCK, BASE_M4_CLK);
+
+	// when moving from < 90 MHz to > 110MHz, must spend 50uS
+	// at 90-110MHz before shifting to high speeds
+	spin_cycles(4800); // 50uS @ 96MHz
+
+	// disable P divider  192MHz
+	writel(cfg | PLL1_CTRL_DIRECT, PLL1_CTRL);
+
+	// 12MHz -> 480MHz settings, per boot rom
+	writel(0x01967FFA, PLL0USB_MDIV);
+	writel(0x00302062, PLL0USB_NP_DIV);
+	// Enable PLL, wait for lock
+	cfg = PLL0_CTRL_CLK_SEL(CLK_XTAL) | PLL0_CTRL_DIRECTO | PLL0_CTRL_AUTOBLOCK;
+	writel(cfg, PLL0USB_CTRL);
+	while (!(readl(PLL0USB_STAT) & PLL0_STAT_LOCK)) ;
+	// Enable clock output
+	writel(cfg | PLL0_CTRL_CLKEN, PLL0USB_CTRL);
+
+#if 0
+	// route PLL1 / 2 to CLK0 pin for verification
+	writel(0x11, 0x40086C00); // CLK0 = CLK_OUT, no PU/PD
+	writel(IDIV_CLK_SEL(CLK_PLL1) | IDIV_N(2), IDIVE_CTRL);
+	writel(BASE_CLK_SEL(CLK_IDIVE), BASE_OUT_CLK);
+#endif
+#if 0
+	// route PLL0USB / 4 to CLK0 pin for verification
+	writel(0x11, 0x40086C00); // CLK0 = CLK_OUT, no PU/PD
+	writel(IDIV_CLK_SEL(CLK_PLL0USB) | IDIV_N(4), IDIVA_CTRL);
+	writel(BASE_CLK_SEL(CLK_IDIVA), BASE_OUT_CLK);
+#endif
+	__lpc43xx_main_clock_mhz = 192000000;
+	__lpc43xx_main_clock_sel = CLK_PLL1;
+#else
+	__lpc43xx_main_clock_mhz = 96000000;
+	__lpc43xx_main_clock_sel = CLK_IDIVC;
+#endif
+	arm_cm_systick_init(__lpc43xx_main_clock_mhz);
+	lpc43xx_debug_early_init();
+}
+
+void lpc43xx_usb_init(u32 dmabase, size_t dmasize);
+
+void platform_init(void)
+{
+	lpc43xx_debug_init();
+	lpc43xx_usb_init(0x20000000, 4096);
+}
+
+void platform_halt(platform_halt_action suggested_action,
+			platform_halt_reason reason)
+{
+	arch_disable_ints();
+	if (suggested_action == HALT_ACTION_REBOOT) {
+		// CORE reset
+		writel(1, 0x40053100);
+	} else {
+		dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason);
+	}
+	for(;;);
+}
diff --git a/src/bsp/lk/platform/lpc43xx/rules.mk b/src/bsp/lk/platform/lpc43xx/rules.mk
new file mode 100644
index 0000000..d5d5c4e
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/rules.mk
@@ -0,0 +1,42 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+ROMBASE ?= 0x10000000
+MEMBASE ?= 0x10080000
+MEMSIZE ?= 40960
+
+ARCH := arm
+ARM_CPU := cortex-m4
+
+GLOBAL_DEFINES += \
+	MEMSIZE=$(MEMSIZE)
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/init.c \
+	$(LOCAL_DIR)/gpio.c \
+	$(LOCAL_DIR)/vectab.c \
+	$(LOCAL_DIR)/debug.c \
+	$(LOCAL_DIR)/udc.c \
+	$(LOCAL_DIR)/udc-common.c
+
+LINKER_SCRIPT += \
+	$(BUILDDIR)/system-twosegment.ld
+
+MODULE_DEPS += \
+	arch/arm/arm-m/systick \
+	lib/cbuf
+
+LPCSIGNEDBIN := $(OUTBIN).sign
+LPCCHECK := $(LKROOT)/platform/lpc15xx/lpccheck.py
+EXTRA_BUILDDEPS += $(LPCSIGNEDBIN)
+GENERATED += $(LPCSIGNEDBIN)
+
+$(LPCSIGNEDBIN): $(OUTBIN) $(LPCCHECK)
+	@$(MKDIR)
+	$(NOECHO)echo generating $@; \
+	cp $< $@.tmp; \
+	$(LPCCHECK) $@.tmp; \
+	mv $@.tmp $@
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/lpc43xx/udc-common.c b/src/bsp/lk/platform/lpc43xx/udc-common.c
new file mode 100644
index 0000000..a22106c
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/udc-common.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ * Copyright (c) 2008 Google, Inc.
+ *
+ * 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 <malloc.h>
+#include <printf.h>
+#include <string.h>
+#include <dev/udc.h>
+
+#include "udc-common.h"
+
+static udc_descriptor_t *udc_descriptor_alloc(unsigned type, unsigned num, unsigned len)
+{
+	struct udc_descriptor *desc;
+	if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
+		return 0;
+
+	if(!(desc = malloc(sizeof(struct udc_descriptor) + len)))
+		return 0;
+
+	desc->next = 0;
+	desc->tag = (type << 8) | num;
+	desc->len = len;
+	desc->data[0] = len;
+	desc->data[1] = type;
+
+	return desc;
+}
+
+static udc_descriptor_t langid_list = {
+	.tag = 0x0300,
+	.len = 4,
+	.data = { 0x04, TYPE_STRING, 0x09, 0x04 }, // EN_US
+};
+
+static struct udc_descriptor *desc_list = &langid_list;
+static unsigned next_string_id = 1;
+
+udc_descriptor_t *udc_descriptor_find(unsigned tag)
+{
+	udc_descriptor_t *desc = desc_list;
+	while (desc != NULL) {
+		if (desc->tag == tag) {
+			return desc;
+		}
+		desc = desc->next;
+	}
+	printf("cant find %08x\n", tag);
+	return NULL;
+}
+
+static void udc_descriptor_register(struct udc_descriptor *desc)
+{
+	desc->next = desc_list;
+	desc_list = desc;
+}
+
+static unsigned udc_string_desc_alloc(const char *str)
+{
+	unsigned len;
+	struct udc_descriptor *desc;
+	unsigned char *data;
+
+	if (next_string_id > 255)
+		return 0;
+
+	if (!str)
+		return 0;
+
+	len = strlen(str);
+	desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
+	if (!desc)
+		return 0;
+	next_string_id++;
+
+	/* expand ascii string to utf16 */
+	data = desc->data + 2;
+	while (len-- > 0) {
+		*data++ = *str++;
+		*data++ = 0;
+	}
+
+	udc_descriptor_register(desc);
+	return desc->tag & 0xff;
+}
+
+
+static unsigned udc_ifc_desc_size(udc_gadget_t *g)
+{
+	return 9 + g->ifc_endpoints * 7;
+}
+
+static void udc_ifc_desc_fill(udc_gadget_t *g, unsigned ifcn, unsigned char *data)
+{
+	unsigned n;
+
+	data[0] = 0x09;
+	data[1] = TYPE_INTERFACE;
+	data[2] = ifcn; // ifc number
+	data[3] = 0x00; // alt number
+	data[4] = g->ifc_endpoints;
+	data[5] = g->ifc_class;
+	data[6] = g->ifc_subclass;
+	data[7] = g->ifc_protocol;
+	data[8] = udc_string_desc_alloc(g->ifc_string);
+
+	data += 9;
+	for (n = 0; n < g->ifc_endpoints; n++) {
+		udc_ept_desc_fill(g->ept[n], data);
+		data += 7;
+	}
+}
+
+void udc_create_descriptors(udc_device_t *device, udc_gadget_t *gadgetlist)
+{
+	udc_descriptor_t *desc;
+	udc_gadget_t *gadget;
+	unsigned size;
+	uint8_t *data, *p;
+	uint8_t n;
+
+	// create our device descriptor
+	desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18);
+	data = desc->data;
+	data[2] = 0x00; // usb spec rev 2.00
+	data[3] = 0x02;
+	data[4] = 0x00; // class
+	data[5] = 0x00; // subclass
+	data[6] = 0x00; // protocol
+	data[7] = 0x40; // max packet size on ept 0
+	data[8] = device->vendor_id;
+	data[9] = device->vendor_id >> 8;
+	data[10] = device->product_id;
+	data[11] = device->product_id >> 8;
+	data[12] = device->version_id;
+	data[13] = device->version_id >> 8;
+	data[14] = udc_string_desc_alloc(device->manufacturer);
+	data[15] = udc_string_desc_alloc(device->product);
+	data[16] = udc_string_desc_alloc(device->serialno);
+	data[17] = 1; // number of configurations
+	udc_descriptor_register(desc);
+
+	// create our configuration descriptor
+	size = 9;
+	n = 0;
+	for (gadget = gadgetlist; gadget; gadget = gadget->next) {
+		size += udc_ifc_desc_size(gadget);
+		n++;
+	}
+	desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size);
+	data = desc->data;
+	data[0] = 0x09;
+	data[2] = size;
+	data[3] = size >> 8;
+	data[4] = n; // number of interfaces
+	data[5] = 0x01; // configuration value
+	data[6] = 0x00; // configuration string
+	data[7] = 0x80; // attributes
+	data[8] = 0x80; // max power (250ma) -- todo fix this
+
+	n = 0;
+	p = data + 9;
+	for (gadget = gadgetlist; gadget; gadget = gadget->next) {
+		udc_ifc_desc_fill(gadget, n++, p);
+		p += udc_ifc_desc_size(gadget);
+	}
+	udc_descriptor_register(desc);
+}
diff --git a/src/bsp/lk/platform/lpc43xx/udc-common.h b/src/bsp/lk/platform/lpc43xx/udc-common.h
new file mode 100644
index 0000000..014383a
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/udc-common.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ * Copyright (c) 2008 Google, Inc.
+ *
+ * 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 __PRIVATE_UDC_H__
+#define __PRIVATE_UDC_H__
+
+#define GET_STATUS           0
+#define CLEAR_FEATURE        1
+#define SET_FEATURE          3
+#define SET_ADDRESS          5
+#define GET_DESCRIPTOR       6
+#define SET_DESCRIPTOR       7
+#define GET_CONFIGURATION    8
+#define SET_CONFIGURATION    9
+#define GET_INTERFACE        10
+#define SET_INTERFACE        11
+#define SYNCH_FRAME          12
+#define SET_SEL              48
+
+#define TYPE_DEVICE          1
+#define TYPE_CONFIGURATION   2
+#define TYPE_STRING          3
+#define TYPE_INTERFACE       4
+#define TYPE_ENDPOINT        5
+#define TYPE_BOS             15
+#define TYPE_DEVICE_CAP      16
+#define TYPE_SS_EP_COMP      48
+
+#define DEVICE_READ          0x80
+#define DEVICE_WRITE         0x00
+#define INTERFACE_READ       0x81
+#define INTERFACE_WRITE      0x01
+#define ENDPOINT_READ        0x82
+#define ENDPOINT_WRITE       0x02
+
+typedef struct udc_descriptor udc_descriptor_t;
+
+union setup_packet {
+	struct {
+		uint8_t type;
+		uint8_t request;
+		uint16_t value;
+		uint16_t index;
+		uint16_t length;
+	};
+	struct {
+		uint32_t w0;
+		uint32_t w1;
+	};
+} __attribute__ ((packed));
+
+struct udc_descriptor {
+	udc_descriptor_t *next;
+	uint16_t tag; /* ((TYPE << 8) | NUM) */
+	uint16_t len; /* total length */
+	uint8_t data[4];
+};
+
+// driver calls this to build descriptors from device and gadgets
+void udc_create_descriptors(udc_device_t *device, udc_gadget_t *gadget);
+
+// driver uses this to obtain descriptors
+udc_descriptor_t *udc_descriptor_find(unsigned tag);
+
+// driver provides this
+void udc_ept_desc_fill(udc_endpoint_t *ept, unsigned char *data);
+
+#endif
diff --git a/src/bsp/lk/platform/lpc43xx/udc.c b/src/bsp/lk/platform/lpc43xx/udc.c
new file mode 100644
index 0000000..6a3e2ae
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/udc.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ * Copyright (c) 2008 Google, Inc.
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <printf.h>
+#include <assert.h>
+#include <debug.h>
+#include <reg.h>
+#include <arch/arm/cm.h>
+#include <kernel/thread.h>
+#include <kernel/spinlock.h>
+
+#include <platform/lpc43xx-usb.h>
+static_assert(sizeof(usb_dqh_t) == 64);
+static_assert(sizeof(usb_dtd_t) == 32);
+
+#include <dev/udc.h>
+
+#include "udc-common.h"
+
+#define F_LL_INIT	1
+#define F_UDC_INIT	2
+
+// NOTE: I cheat a bit with the locking because this is a UP Cortex-M
+// NOTE: device.  I use spinlocks for code that might be called from
+// NOTE: userspace or irq context, but for the irq-only code I don't
+// NOTE: bother with locking because it's impossible for it to execute
+// NOTE: while the lock is held from userspace.
+
+typedef struct {
+	u32 base;
+	spin_lock_t lock;
+
+	usb_dqh_t *qh;
+	usb_dtd_t *dtd_freelist;
+
+	udc_endpoint_t *ep0in;
+	udc_endpoint_t *ep0out;
+	udc_request_t *ep0req;
+	u8 txd[8];
+	u8 rxd[8];
+
+	udc_endpoint_t *ept_list;
+	uint8_t online;
+	uint8_t highspeed;
+	uint8_t config_value;
+	uint8_t flags;
+
+	udc_device_t *device;
+	udc_gadget_t *gadget;
+
+	uint32_t ept_alloc_table;
+} usb_t;
+
+static usb_t USB;
+
+typedef struct usb_request {
+	udc_request_t req;
+	struct usb_request *next;
+	usb_dtd_t *dtd;
+} usb_request_t;
+
+struct udc_endpoint {
+	udc_endpoint_t *next;
+	usb_dqh_t *head;
+	usb_request_t *req;
+	usb_request_t *last;
+	usb_t *usb;
+	uint32_t bit;
+	uint16_t maxpkt;
+	uint8_t num;
+	uint8_t in;
+};
+
+// ---- endpoint management
+
+#if 1
+#define DBG(x...) do {} while(0)
+#else
+#define DBG(x...) dprintf(INFO, x)
+#endif
+
+static udc_endpoint_t *_udc_endpoint_alloc(usb_t *usb,
+	unsigned num, unsigned in, unsigned max_pkt)
+{
+	udc_endpoint_t *ept;
+	unsigned cfg;
+
+	ept = malloc(sizeof(*ept));
+	ept->maxpkt = max_pkt;
+	ept->num = num;
+	ept->in = !!in;
+	ept->req = 0;
+	ept->last = 0;
+	ept->usb = usb;
+
+	cfg = DQH_CFG_MAXPKT(max_pkt) | DQH_CFG_ZLT;
+
+	if(ept->in) {
+		ept->bit = EPT_TX(ept->num);
+	} else {
+		ept->bit = EPT_RX(ept->num);
+		if(num == 0) {
+			cfg |= DQH_CFG_IOS;
+		}
+	}
+
+	ept->head = usb->qh + (num * 2) + (ept->in);
+	ept->head->config = cfg;
+	ept->next = usb->ept_list;
+	usb->ept_list = ept;
+
+	DBG("ept%d %s @%p/%p max=%d bit=%x\n",
+		num, in ? "in":"out", ept, ept->head, max_pkt, ept->bit);
+
+	return ept;
+}
+
+udc_endpoint_t *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
+{
+	udc_endpoint_t *ept;
+	unsigned n;
+	unsigned in = !!(type & 0x80);
+
+	if (!(USB.flags & F_UDC_INIT)) {
+		panic("udc_init() must be called before udc_endpoint_alloc()\n");
+	}
+
+	for (n = 1; n < 6; n++) {
+		unsigned bit = in ? EPT_TX(n) : EPT_RX(n);
+		if (USB.ept_alloc_table & bit) {
+			continue;
+		}
+		if ((ept = _udc_endpoint_alloc(&USB, n, in, maxpkt))) {
+			USB.ept_alloc_table |= bit;
+		}
+		return ept;
+	}
+	return 0;
+}
+
+void udc_endpoint_free(struct udc_endpoint *ept)
+{
+	// todo
+}
+
+static void handle_ept_complete(struct udc_endpoint *ept);
+
+static void endpoint_flush(usb_t *usb, udc_endpoint_t *ept) {
+	if (ept->req) {
+		// flush outstanding transfers
+		writel(ept->bit, usb->base + USB_ENDPTFLUSH);
+		while (readl(usb->base + USB_ENDPTFLUSH)) ;
+		while (ept->req) {
+			handle_ept_complete(ept);
+		}
+	}
+}
+
+static void endpoint_reset(usb_t *usb, udc_endpoint_t *ept) {
+	unsigned n = readl(usb->base + USB_ENDPTCTRL(ept->num));
+	n |= ept->in ? EPCTRL_TXR : EPCTRL_RXR;
+	writel(n, usb->base + USB_ENDPTCTRL(ept->num));
+}
+
+static void endpoint_enable(usb_t *usb, udc_endpoint_t *ept, unsigned yes)
+{
+	unsigned n = readl(usb->base + USB_ENDPTCTRL(ept->num));
+
+	if(yes) {
+		if(ept->in) {
+			n |= (EPCTRL_TXE | EPCTRL_TXR | EPCTRL_TX_BULK);
+		} else {
+			n |= (EPCTRL_RXE | EPCTRL_RXR | EPCTRL_RX_BULK);
+		}
+
+		if(ept->num != 0) {
+			// todo: support non-max-sized packet sizes
+			if(usb->highspeed) {
+				ept->head->config = DQH_CFG_MAXPKT(512) | DQH_CFG_ZLT;
+			} else {
+				ept->head->config = DQH_CFG_MAXPKT(64) | DQH_CFG_ZLT;
+			}
+		}
+	}
+	writel(n, usb->base + USB_ENDPTCTRL(ept->num));
+}
+
+// ---- request management
+
+udc_request_t *udc_request_alloc(void)
+{
+	spin_lock_saved_state_t state;
+	usb_request_t *req;
+	if ((req = malloc(sizeof(*req))) == NULL) {
+		return NULL;
+	}
+
+	spin_lock_irqsave(&USB.lock, state);
+	if (USB.dtd_freelist == NULL) {
+		spin_unlock_irqrestore(&USB.lock, state);
+		free(req);
+		return NULL;
+	} else {
+		req->dtd = USB.dtd_freelist;
+		USB.dtd_freelist = req->dtd->next;
+		spin_unlock_irqrestore(&USB.lock, state);
+
+		req->req.buffer = 0;
+		req->req.length = 0;
+		return &req->req;
+	}
+}
+
+void udc_request_free(struct udc_request *req)
+{
+	// todo: check if active?
+	free(req);
+}
+
+int udc_request_queue(udc_endpoint_t *ept, struct udc_request *_req)
+{
+	spin_lock_saved_state_t state;
+	usb_request_t *req = (usb_request_t *) _req;
+	usb_dtd_t *dtd = req->dtd;
+	unsigned phys = (unsigned) req->req.buffer;
+	int ret = 0;
+
+	dtd->next_dtd = 1; // terminate bit
+	dtd->config = DTD_LEN(req->req.length) | DTD_IOC | DTD_ACTIVE;
+	dtd->bptr0 = phys;
+	phys &= 0xfffff000;
+	dtd->bptr1 = phys + 0x1000;
+	dtd->bptr2 = phys + 0x2000;
+	dtd->bptr3 = phys + 0x3000;
+	dtd->bptr4 = phys + 0x4000;
+
+	req->next = 0;
+	spin_lock_irqsave(&ept->usb->lock, state);
+	if (!USB.online && ept->num) {
+		ret = -1;
+	} else if (ept->req) {
+		// already a transfer in flight, add us to the list
+		// we'll get queue'd by the irq handler when it's our turn
+		ept->last->next = req;
+	} else {
+		ept->head->next_dtd = (unsigned) dtd;
+		ept->head->dtd_config = 0;
+		DSB;
+		writel(ept->bit, ept->usb->base + USB_ENDPTPRIME);
+		ept->req = req;
+	}
+	ept->last = req;
+	spin_unlock_irqrestore(&ept->usb->lock, state);
+
+	DBG("ept%d %s queue req=%p\n", ept->num, ept->in ? "in" : "out", req);
+	return ret;
+}
+
+static void handle_ept_complete(struct udc_endpoint *ept)
+{
+	usb_request_t *req;
+	usb_dtd_t *dtd;
+	unsigned actual;
+	int status;
+
+	DBG("ept%d %s complete req=%p\n",
+            ept->num, ept->in ? "in" : "out", ept->req);
+
+	if ((req = ept->req)) {
+		if (req->next) {
+			// queue next req to hw
+			ept->head->next_dtd = (unsigned) req->next->dtd;
+			ept->head->dtd_config = 0;
+			DSB;
+			writel(ept->bit, ept->usb->base + USB_ENDPTPRIME);
+			ept->req = req->next;
+		} else {
+			ept->req = 0;
+			ept->last = 0;
+		}
+		dtd = req->dtd;
+		if (dtd->config & 0xff) {
+			actual = 0;
+			status = -1;
+			dprintf(INFO, "EP%d/%s FAIL nfo=%x pg0=%x\n",
+				ept->num, ept->in ? "in" : "out", dtd->config, dtd->bptr0);
+		} else {
+			actual = req->req.length - ((dtd->config >> 16) & 0x7fff);
+			status = 0;
+		}
+		if(req->req.complete) {
+			req->req.complete(&req->req, actual, status);
+		}
+	}
+}
+
+static void setup_ack(usb_t *usb)
+{
+	usb->ep0req->complete = 0;
+	usb->ep0req->length = 0;
+	udc_request_queue(usb->ep0in, usb->ep0req);
+}
+
+static void ep0in_complete(struct udc_request *req, unsigned actual, int status)
+{
+	usb_t *usb = (usb_t*) req->context;
+	DBG("ep0in_complete %p %d %d\n", req, actual, status);
+	if(status == 0) {
+		req->length = 0;
+		req->complete = 0;
+		udc_request_queue(usb->ep0out, req);
+	}
+}
+
+static void setup_tx(usb_t *usb, void *buf, unsigned len)
+{
+	DBG("setup_tx %p %d\n", buf, len);
+	usb->ep0req->buffer = buf;
+	usb->ep0req->complete = ep0in_complete;
+	usb->ep0req->length = len;
+	udc_request_queue(usb->ep0in, usb->ep0req);
+}
+
+static void notify_gadgets(udc_gadget_t *gadget, unsigned event) {
+	while (gadget) {
+		if (gadget->notify) {
+			gadget->notify(gadget, event);
+		}
+		gadget = gadget->next;
+	}
+}
+
+#define SETUP(type,request) (((type) << 8) | (request))
+
+static void handle_setup(usb_t *usb)
+{
+	union setup_packet s;
+
+	// setup procedure, per databook
+	// a. clear setup status by writing and waiting for 0 (1-2uS)
+	writel(1, usb->base + USB_ENDPTSETUPSTAT);
+	while (readl(usb->base + USB_ENDPTSETUPSTAT) & 1) ;
+	do {
+		// b. write 1 to tripwire
+		writel(CMD_RUN | CMD_SUTW, usb->base + USB_CMD);
+		// c. extract setup data
+		s.w0 = usb->qh[0].setup0;
+		s.w1 = usb->qh[0].setup1;
+		// d. if tripwire clear, retry
+	} while ((readl(usb->base + USB_CMD) & CMD_SUTW) == 0);
+	// e. clear tripwire
+	writel(CMD_RUN, usb->base + USB_CMD);
+	// flush any pending io from previous setup transactions
+	usb->ep0in->req = 0;
+	usb->ep0out->req = 0;
+	// f. process packet
+	// g. ensure setup status is 0
+
+	DBG("setup 0x%02x 0x%02x %d %d %d\n",
+            s.type, s.request, s.value, s.index, s.length);
+
+	switch (SETUP(s.type,s.request)) {
+	case SETUP(DEVICE_READ, GET_STATUS): {
+		static unsigned zero = 0;
+		if (s.length == 2) {
+			setup_tx(usb, &zero, 2);
+			return;
+		}
+		break;
+	}
+	case SETUP(DEVICE_READ, GET_DESCRIPTOR): {
+		struct udc_descriptor *desc = udc_descriptor_find(s.value);
+		if (desc) {
+			unsigned len = desc->len;
+			if (len > s.length) len = s.length;
+			setup_tx(usb, desc->data, len);
+			return;
+		}
+		break;
+	}
+	case SETUP(DEVICE_READ, GET_CONFIGURATION):
+		if ((s.value == 0) && (s.index == 0) && (s.length == 1)) {
+			setup_tx(usb, &usb->config_value, 1);
+			return;
+		}
+		break;
+	case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
+		if (s.value == 1) {
+			struct udc_endpoint *ept;
+			/* enable endpoints */
+			for (ept = usb->ept_list; ept; ept = ept->next){
+				if (ept->num != 0) {
+					endpoint_enable(usb, ept, 1);
+				}
+			}
+			usb->config_value = 1;
+			notify_gadgets(usb->gadget, UDC_EVENT_ONLINE);
+		} else {
+			writel(0, usb->base + USB_ENDPTCTRL(1));
+			usb->config_value = 0;
+			notify_gadgets(usb->gadget, UDC_EVENT_OFFLINE);
+		}
+		setup_ack(usb);
+		usb->online = s.value ? 1 : 0;
+		return;
+	case SETUP(DEVICE_WRITE, SET_ADDRESS):
+		// write address delayed (will take effect after the next IN txn)
+		writel(((s.value & 0x7F) << 25) | (1 << 24), usb->base + USB_DEVICEADDR);
+		setup_ack(usb);
+		return;
+	case SETUP(INTERFACE_WRITE, SET_INTERFACE):
+		goto stall;
+	case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): {
+		udc_endpoint_t *ept;
+		unsigned num = s.index & 15;
+		unsigned in = !!(s.index & 0x80);
+
+		if ((s.value != 0) || (s.length != 0)) {
+			break;
+		}
+		DBG("clr feat %d %d\n", num, in);
+		for (ept = usb->ept_list; ept; ept = ept->next) {
+			if ((ept->num == num) && (ept->in == in)) {
+				endpoint_flush(usb, ept);
+				// todo: if callback requeues this could be ugly...
+				endpoint_reset(usb, ept);
+				setup_ack(usb);
+				return;
+			}
+		}
+		break;
+	}
+	}
+
+	dprintf(INFO, "udc: stall %02x %02x %04x %04x %04x\n",
+		s.type, s.request, s.value, s.index, s.length);
+
+stall:
+	writel(EPCTRL_RXS | EPCTRL_TXS, usb->base + USB_ENDPTCTRL(0));
+}
+
+int lpc43xx_usb_init(u32 dmabase, size_t dmasize) {
+	usb_t *usb = &USB;
+	printf("usb_init()\n");
+	if ((dmabase & 0x7FF) || (dmasize < 1024)) {
+		return -1;
+	}
+	usb->qh = (void*) dmabase;
+	usb->dtd_freelist = NULL;
+	memset(usb->qh, 0, dmasize);
+	usb->base = USB0_BASE;
+	dmabase += 768;
+	dmasize -= 768;
+	while (dmasize > sizeof(usb_dtd_t)) {
+		usb_dtd_t *dtd = (void*) dmabase;
+		dtd->next = usb->dtd_freelist;
+		usb->dtd_freelist = dtd;
+		dmabase += sizeof(usb_dtd_t);
+		dmasize -= sizeof(usb_dtd_t);
+	}
+	writel(CMD_RST, usb->base + USB_CMD);
+	while (readl(usb->base + USB_CMD) & CMD_RST) ;
+	printf("usb_init(): reset ok\n");
+	thread_sleep(250);
+
+	// enable USB0 PHY via CREG0
+	writel(readl(0x40043004) & (~0x20), 0x40043004);
+
+	writel(MODE_DEVICE | MODE_SLOM, usb->base + USB_MODE);
+
+	// enable termination in OTG control (required for device mode)
+	writel(OTG_OT, usb->base + USB_OTGSC);
+
+	writel((u32) usb->qh, usb->base + USB_ENDPOINTLISTADDR);
+	usb->flags |= F_LL_INIT;
+	return 0;
+}
+
+static void usb_enable(usb_t *usb, int yes)
+{
+	if (yes) {
+		writel(INTR_UE | INTR_UEE | INTR_PCE | INTR_SEE | INTR_URE,
+			usb->base + USB_INTR);
+
+		writel(CMD_RUN, usb->base + USB_CMD);
+		NVIC_EnableIRQ(USB0_IRQn);
+	} else {
+		NVIC_DisableIRQ(USB0_IRQn);
+		writel(CMD_STOP, usb->base + USB_CMD);
+	}
+}
+
+
+void lpc43xx_USB0_IRQ(void)
+{
+	udc_endpoint_t *ept;
+	usb_t *usb = &USB;
+	int ret = 0;
+	unsigned n;
+
+	arm_cm_irq_entry();
+
+	n = readl(usb->base + USB_STS);
+	writel(n, usb->base + USB_STS);
+
+	if (n & STS_URI) {
+		// reset procedure, per databook
+		// 1. clear setup token semaphores
+		writel(readl(usb->base + USB_ENDPTSETUPSTAT),
+			usb->base + USB_ENDPTSETUPSTAT);
+		// 2. clear completion status bits
+		writel(readl(usb->base + USB_ENDPTCOMPLETE),
+			usb->base + USB_ENDPTCOMPLETE);
+		// 3. cancel primed transfers
+		while (readl(usb->base + USB_ENDPTPRIME)) ;
+		writel(0xFFFFFFFF, usb->base + USB_ENDPTFLUSH);
+		// 4. ensure we finished while reset still active
+		if (!(readl(usb->base + USB_PORTSC1) & PORTSC1_RC)) {
+			printf("usb: failed to reset in time\n");
+		}
+		// 5. free active DTDs
+		usb->online = 0;
+		usb->config_value = 0;
+		notify_gadgets(usb->gadget, UDC_EVENT_OFFLINE);
+		for (ept = usb->ept_list; ept; ept = ept->next) {
+			if (ept->req) {
+				ept->req->dtd->config = DTD_HALTED;
+				handle_ept_complete(ept);
+			}
+		}
+	}
+	if (n & STS_PCI) {
+		unsigned x = readl(usb->base + USB_PORTSC1);
+		usb->highspeed = (x & PORTSC1_HSP) ? 1 : 0;
+	}
+	if (n & (STS_UI | STS_UEI)) {
+		if(readl(usb->base + USB_ENDPTSETUPSTAT) & 1) {
+			handle_setup(usb);
+		}
+		n = readl(usb->base + USB_ENDPTCOMPLETE);
+		writel(n, usb->base + USB_ENDPTCOMPLETE);
+
+		for (ept = usb->ept_list; ept; ept = ept->next) {
+			if (n & ept->bit) {
+				handle_ept_complete(ept);
+				ret = INT_RESCHEDULE;
+			}
+		}
+	}
+	if (n & STS_SEI) {
+		panic("<SEI>");
+	}
+	arm_cm_irq_exit(ret);
+}
+
+// ---- UDC API
+
+int udc_init(struct udc_device *dev)
+{
+	USB.device = dev;
+	USB.ep0out = _udc_endpoint_alloc(&USB, 0, 0, 64);
+	USB.ep0in = _udc_endpoint_alloc(&USB, 0, 1, 64);
+	USB.ep0req = udc_request_alloc();
+	USB.ep0req->context = &USB;
+	USB.flags |= F_UDC_INIT;
+	return 0;
+}
+
+int udc_register_gadget(udc_gadget_t *gadget)
+{
+	if (USB.gadget) {
+		udc_gadget_t *last = USB.gadget;
+		while (last->next) {
+			last = last->next;
+		}
+		last->next = gadget;
+	} else {
+		USB.gadget = gadget;
+	}
+	gadget->next = NULL;
+	return 0;
+}
+
+void udc_ept_desc_fill(udc_endpoint_t *ept, unsigned char *data)
+{
+	data[0] = 7;
+	data[1] = TYPE_ENDPOINT;
+	data[2] = ept->num | (ept->in ? 0x80 : 0x00);
+	data[3] = 0x02; // bulk -- the only kind we support
+	data[4] = ept->maxpkt;
+	data[5] = ept->maxpkt >> 8;
+	data[6] = ept->in ? 0x00 : 0x01;
+}
+
+int udc_start(void)
+{
+	usb_t *usb = &USB;
+
+	dprintf(INFO, "udc_start()\n");
+	if (!(usb->flags & F_LL_INIT)) {
+		panic("udc cannot start before hw init\n");
+	}
+	if (!usb->device) {
+		panic("udc cannot start before init\n");
+	}
+	if (!usb->gadget) {
+		panic("udc has no gadget registered\n");
+	}
+	udc_create_descriptors(usb->device, usb->gadget);
+
+	usb_enable(usb, 1);
+	return 0;
+}
+
+int udc_stop(void)
+{
+	usb_enable(&USB, 0);
+	thread_sleep(10);
+	return 0;
+}
+
diff --git a/src/bsp/lk/platform/lpc43xx/vectab.c b/src/bsp/lk/platform/lpc43xx/vectab.c
new file mode 100644
index 0000000..ab03987
--- /dev/null
+++ b/src/bsp/lk/platform/lpc43xx/vectab.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Brian Swetland
+ *
+ * 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 <compiler.h>
+#include <arch/arm/cm.h>
+
+void lpc43xx_dummy_irq(void)
+{
+	arm_cm_irq_entry();
+	panic("unhandled irq\n");
+}
+
+// default handlers are weak aliases to the dummy handler
+#define DEFIRQ(x) \
+	void lpc43xx_##x##_IRQ(void) __WEAK_ALIAS("lpc43xx_dummy_irq");
+#include <platform/defirq.h>
+#undef DEFIRQ
+
+#define DEFIRQ(x) [x##_IRQn] = lpc43xx_##x##_IRQ,
+const void * const __SECTION(".text.boot.vectab2") vectab2[] = {
+#include <platform/defirq.h>
+};
+#undef DEFIRQ