auto import from //depot/cupcake/@135843
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..d915837
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Most of these don't make sense to build unless the board has defined
+# a link script.
+
+ifdef TARGET_BOOTLOADER_LINK_SCRIPT
+  include $(call all-subdir-makefiles)
+endif
diff --git a/README b/README
new file mode 100644
index 0000000..ba997b1
--- /dev/null
+++ b/README
@@ -0,0 +1,51 @@
+
+The bootloader environment consists of a set of libraries that provide
+various features and a couple small driver programs that build against
+these libraries.  The libraries used come from three categories --
+generic (containing code useful to any bootloader), architecture
+(containing code useful to a specific cpu, system-on-chip, etc), and
+board (containing code useful to a single specific device)
+
+For the purpose of this discussion, we will involve the fictional
+companies Outstanding Electronics Manufacturing (OEM) and Silicon
+Engineering Management, Inc (SEMI).  OEM produces the quality Brick
+mobile device using SEMI's 65002 ARM-based system-on-chip.
+
+Common bootloader libraries and base architectures:
+
+boot/include/boot                     headers
+boot/libboot                          libboot.a
+boot/libc                             libboot_c.a
+boot/arch_armv6                       libboot_arch_armv6.a
+
+Architecture-specific libraries for SEMI 65002 SOC:
+
+partner/semi/boot/include/65002       headers
+partner/semi/boot/arch_65002          liboot_arch_65002.a
+
+Device-specific library for OEM Brick phone:
+
+partner/oem/brick/product_config.mk   configuration
+partner/oem/brick/boot                libboot_board_brick.a
+
+The actual bootloader:
+
+boot/bootloader                       bootloader
+
+
+The product_config.mk defines three important build variables:
+
+DEVICE_BOOTLOADER_LIBS := \
+	libboot_board_brick.a \
+	libboot_arch_65002.a \
+	libboot_arch_armv6.a
+
+DEVICE_BOOTLOADER_LINK_SCRIPT := \
+	partner/semi/boot/boot.ld
+
+DEVICE_BOOTLOADER_INIT := \
+	partner/semi/boot/init.S
+
+Which are used by the bootloader to specify which board and
+architecture specific libraries to link against as well as what link
+script and init.S to use
diff --git a/arch_armv6/Android.mk b/arch_armv6/Android.mk
new file mode 100644
index 0000000..7014a68
--- /dev/null
+++ b/arch_armv6/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := irq.S dcc.S jtag.S misc.S
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader)
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+
+LOCAL_MODULE := libboot_arch_armv6
+
+include $(BUILD_RAW_STATIC_LIBRARY)
\ No newline at end of file
diff --git a/arch_armv6/dcc.S b/arch_armv6/dcc.S
new file mode 100644
index 0000000..c789f94
--- /dev/null
+++ b/arch_armv6/dcc.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+.global dcc_putc
+.global dcc_getc
+
+dcc_getc:
+	mrc 14, 0, r0, c0, c1, 0 
+	tst r0, #(1 << 30)
+	moveq r0, #-1
+	mrcne 14, 0, r0, c0, c5, 0
+	bx lr
+
+dcc_putc:
+	/* read status to flags */
+	mrc 14, 0, r15, c0, c1, 0 
+	mcrcc 14, 0, r0, c0, c5, 0
+	movcc r0, #0
+	movcs r0, #-1
+	bx lr
diff --git a/arch_armv6/irq.S b/arch_armv6/irq.S
new file mode 100644
index 0000000..3336b63
--- /dev/null
+++ b/arch_armv6/irq.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+.global enable_irq
+		
+enable_irq:
+	cpsie i
+	bx lr
diff --git a/arch_armv6/jtag.S b/arch_armv6/jtag.S
new file mode 100644
index 0000000..fdcaf40
--- /dev/null
+++ b/arch_armv6/jtag.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+.global jtag_hook, func
+
+jtag_hook:
+	bx lr
diff --git a/arch_armv6/misc.S b/arch_armv6/misc.S
new file mode 100644
index 0000000..1a1acbe
--- /dev/null
+++ b/arch_armv6/misc.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+.global periph_2gb_open
+.global periph_2gb_close
+
+periph_2gb_open:
+	/* open the peripheral port 2gb */
+	/* see 1136trm 3-164 */
+	ldr r0, =0x80000016
+	mcr p15, 0, r0, c15, c2, 4
+	bx lr
+
+periph_2gb_close:
+	mov r0, #0
+	mcr p15, 0, r0, c15, c2, 4
+	bx lr
diff --git a/arch_msm7k/Android.mk b/arch_msm7k/Android.mk
new file mode 100644
index 0000000..3c787ae
--- /dev/null
+++ b/arch_msm7k/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := \
+	clock.c \
+	hsusb.c \
+	mddi_console.c \
+	nand.c \
+	uart.c \
+	gpio.c \
+	mddi.c \
+	vic.c \
+	shared.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader)
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+
+LOCAL_MODULE := libboot_arch_msm7k
+
+include $(BUILD_RAW_STATIC_LIBRARY)
diff --git a/arch_msm7k/clock.c b/arch_msm7k/clock.c
new file mode 100644
index 0000000..0bb0926
--- /dev/null
+++ b/arch_msm7k/clock.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <msm7k/gpt.h>
+
+static inline unsigned rd_cycle_count(void) 
+{
+    unsigned cc;
+    asm volatile (
+        "mrc p15, 0, %0, c15, c12, 1\n" :
+        "=r" (cc) 
+        );   
+    return cc;
+}
+
+static inline unsigned rd_dtcm(void) 
+{
+    unsigned cc;
+    asm volatile (
+        "mrc p15, 0, %0, c9, c1, 0\n" :
+        "=r" (cc) 
+        );   
+    return cc;
+}
+
+static inline unsigned rd_itcm(void) 
+{
+    unsigned cc;
+    asm volatile (
+        "mrc p15, 0, %0, c9, c1, 1\n" :
+        "=r" (cc) 
+        );   
+    return cc;
+}
+
+static inline void perf_enable(void)
+{
+    asm volatile (
+        "mcr p15, 0, %0, c15, c12, 0\n" : : "r" (7) 
+        );
+}
+
+static inline void perf_disable(void)
+{
+    asm volatile (
+        "mcr p15, 0, %0, c15, c12, 0\n" : : "r" (0)
+        );
+}
+
+unsigned cycles_per_second(void)
+{
+    unsigned T0, T1;
+
+    perf_enable();
+    
+    writel(0, GPT_CLEAR);
+    writel(0, GPT_ENABLE);
+    while(readl(GPT_COUNT_VAL) != 0) ;
+    
+    writel(GPT_ENABLE_EN, GPT_ENABLE);    
+    T0 = rd_cycle_count();
+    while(readl(GPT_COUNT_VAL) < 32766) ;
+    T1 = rd_cycle_count();
+
+    writel(0, GPT_ENABLE);
+    writel(0, GPT_CLEAR);
+
+    perf_disable();
+    
+    return T1-T0;
+}
+
+void mdelay(unsigned msecs)
+{
+    msecs *= 33;
+    
+    writel(0, GPT_CLEAR);
+    writel(0, GPT_ENABLE);
+    while(readl(GPT_COUNT_VAL) != 0) ;
+    
+    writel(GPT_ENABLE_EN, GPT_ENABLE);    
+    while(readl(GPT_COUNT_VAL) < msecs) ;
+
+    writel(0, GPT_ENABLE);
+    writel(0, GPT_CLEAR);    
+}
+
+void udelay(unsigned usecs)
+{
+    usecs = (usecs * 33 + 1000 - 33) / 1000;
+    
+    writel(0, GPT_CLEAR);
+    writel(0, GPT_ENABLE);
+    while(readl(GPT_COUNT_VAL) != 0) ;
+    
+    writel(GPT_ENABLE_EN, GPT_ENABLE);    
+    while(readl(GPT_COUNT_VAL) < usecs) ;
+
+    writel(0, GPT_ENABLE);
+    writel(0, GPT_CLEAR);    
+}
+
+void print_cpu_speed(void)
+{
+    unsigned cps = cycles_per_second();
+    dprintf("1 second = %d cycles\n%d MHz\n", cps, cps / 1000000);
+}
+
+#define A11S_CLK_CNTL 0xC0100100
+#define A11S_CLK_SEL  0xC0100104
+
+#define C A11S_CLK_CNTL
+#define S A11S_CLK_SEL
+
+#if FROM_APPSBOOT_MBN
+static unsigned tbl_old[] = {
+    C, 0x640000,
+    S, 2,
+    C, 0x640010,
+    C, 0x64001F,
+    S, 3,
+    C, 0x64101F,
+    C, 0x64171F,
+    S, 2,
+    C, 0x64171F,
+    C, 0x641715,
+    S, 3,
+    S, 5,
+    C, 0x641715,
+    C, 0x641315,
+    S, 4,
+    S, 6,
+    C, 0x641315,
+    C, 0x641312,
+    S, 7,
+    C, 0x641312,
+    C, 0x641112,
+    S, 6,
+    0
+};
+#endif
+
+static unsigned tbl[] = {
+#if EXPLORE
+    C, 0x640000, S, 2,
+    C, 0x640001, S, 3,
+    C, 0x640201, S, 2,
+    C, 0x640203, S, 3,
+    C, 0x640403, S, 2,
+    C, 0x640405, S, 3,
+    C, 0x640605, S, 2,
+    C, 0x640607, S, 3,
+    C, 0x640807, S, 2,
+    C, 0x640809, S, 3,
+    C, 0x640A09, S, 2,
+    C, 0x640A0B, S, 3,
+    C, 0x640C0B, S, 2,
+    C, 0x640C0D, S, 3,
+    C, 0x640E0D, S, 2,
+    C, 0x640E0F, S, 3,
+#endif
+    C, 0x640000, S, 2,
+    C, 0x64001F, S, 3,
+    C, 0x64171F, S, 2,
+    C, 0x641715, S, 5,
+    C, 0x641315, S, 6,
+    C, 0x641312, S, 7,
+    C, 0x641112, S, 6,
+    0
+};
+#undef C
+#undef S
+
+#if TESTCASE
+unsigned cc_div[16] = { 
+	1, 2, 3, 4,  5, 8, 6, 16,  
+	1, 1, 1, 1,  1, 1, 1, 32  /* guess */ 
+};
+
+unsigned cc_base[4] = {
+	19200000,
+    245760000,
+    800000000,
+    0
+};
+
+unsigned cs_div[4] = {
+	1, 2, 3, 4
+};
+
+void info(unsigned c, unsigned s)
+{
+    unsigned src_sel, src_div;
+
+    if(s & 1) {
+            /* src1 selected */
+        src_sel = (c >> 4) & 0x7;
+        src_div = c & 0xF;
+    } else {
+            /* src0 selected */
+        src_sel = (c >> 12) & 0x7;
+        src_div = (c >> 8) & 0xF;
+    }
+    
+    unsigned src = s & 1;
+    unsigned pdiv = cs_div[(s >> 1) & 3];
+    unsigned div = cc_div[src_div];
+    unsigned clk = cc_base[src_sel] / div;
+    unsigned pclk = clk / pdiv;
+
+    unsigned cps = cycles_per_second();
+
+    dprintf("CC=0x%x CS=0x%x SRC=%d PDIV=%d SEL=%d DIV=%d CPS=%d ACLK=%d\n",
+            c, s, src, pdiv, src_sel, div, cps, clk);
+}
+
+
+void arm11_clock_test(void) 
+{
+    unsigned c, s;
+    unsigned *x = tbl;
+
+    while(*x) {
+        unsigned *ptr = (unsigned*) *x++;
+        unsigned val = *x++;
+        *ptr = val;
+
+        if(ptr == ((unsigned*) A11S_CLK_CNTL)) {
+            c = val;
+        } else {
+            s = val;
+            info(c, s);
+        }
+    }
+}
+#endif
+
+void arm11_clock_init(void) 
+{
+    unsigned *x = tbl;
+    while(*x) {
+        unsigned *ptr = (unsigned*) *x++;
+        unsigned val = *x++;
+        *ptr = val;
+    }
+}
+
+    
diff --git a/arch_msm7k/gpio.c b/arch_msm7k/gpio.c
new file mode 100644
index 0000000..f4b0705
--- /dev/null
+++ b/arch_msm7k/gpio.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <msm7k/gpio.h>
+
+/* gross */
+
+typedef struct gpioregs gpioregs;
+
+struct gpioregs
+{
+    unsigned out;
+    unsigned in;
+    unsigned int_status;
+    unsigned int_clear;
+    unsigned int_en;
+    unsigned int_edge;
+    unsigned int_pos;
+    unsigned oe;
+};
+
+static gpioregs GPIO_REGS[] = {
+    {
+        .out =         GPIO_OUT_0,
+        .in =          GPIO_IN_0,
+        .int_status =  GPIO_INT_STATUS_0,
+        .int_clear =   GPIO_INT_CLEAR_0,
+        .int_en =      GPIO_INT_EN_0,
+        .int_edge =    GPIO_INT_EDGE_0,
+        .int_pos =     GPIO_INT_POS_0,
+        .oe =          GPIO_OE_0,
+    },
+    {
+        .out =         GPIO_OUT_1,
+        .in =          GPIO_IN_1,
+        .int_status =  GPIO_INT_STATUS_1,
+        .int_clear =   GPIO_INT_CLEAR_1,
+        .int_en =      GPIO_INT_EN_1,
+        .int_edge =    GPIO_INT_EDGE_1,
+        .int_pos =     GPIO_INT_POS_1,
+        .oe =          GPIO_OE_1,
+    },
+    {
+        .out =         GPIO_OUT_2,
+        .in =          GPIO_IN_2,
+        .int_status =  GPIO_INT_STATUS_2,
+        .int_clear =   GPIO_INT_CLEAR_2,
+        .int_en =      GPIO_INT_EN_2,
+        .int_edge =    GPIO_INT_EDGE_2,
+        .int_pos =     GPIO_INT_POS_2,
+        .oe =          GPIO_OE_2,
+    },
+    {
+        .out =         GPIO_OUT_3,
+        .in =          GPIO_IN_3,
+        .int_status =  GPIO_INT_STATUS_3,
+        .int_clear =   GPIO_INT_CLEAR_3,
+        .int_en =      GPIO_INT_EN_3,
+        .int_edge =    GPIO_INT_EDGE_3,
+        .int_pos =     GPIO_INT_POS_3,
+        .oe =          GPIO_OE_3,
+    },
+    {
+        .out =         GPIO_OUT_4,
+        .in =          GPIO_IN_4,
+        .int_status =  GPIO_INT_STATUS_4,
+        .int_clear =   GPIO_INT_CLEAR_4,
+        .int_en =      GPIO_INT_EN_4,
+        .int_edge =    GPIO_INT_EDGE_4,
+        .int_pos =     GPIO_INT_POS_4,
+        .oe =          GPIO_OE_4,
+    },
+};
+
+static gpioregs *find_gpio(unsigned n, unsigned *bit)
+{
+    if(n > 106) return 0;
+    if(n > 94) {
+        *bit = 1 << (n - 95);
+        return GPIO_REGS + 4;
+    }
+    if(n > 67) {
+        *bit = 1 << (n - 68);
+        return GPIO_REGS + 3;
+    }
+    if(n > 42) {
+        *bit = 1 << (n - 43);
+        return GPIO_REGS + 2;
+    }
+    if(n > 15) {
+        *bit = 1 << (n - 16);
+        return GPIO_REGS + 1;
+    }
+    *bit = 1 << n;
+    return GPIO_REGS + 0;
+}
+
+void gpio_output_enable(unsigned n, unsigned out)
+{
+    gpioregs *r;
+    unsigned b;
+    unsigned v;
+    
+    if((r = find_gpio(n, &b)) == 0) return;
+
+    v = readl(r->oe);
+    if(out) {
+        writel(v | b, r->oe);
+    } else {
+        writel(v & (~b), r->oe);
+    }
+}
+
+void gpio_write(unsigned n, unsigned on)
+{
+    gpioregs *r;
+    unsigned b;
+    unsigned v;
+    
+    if((r = find_gpio(n, &b)) == 0) return;
+
+    v = readl(r->out);
+    if(on) {
+        writel(v | b, r->out);
+    } else {
+        writel(v & (~b), r->out);
+    }
+}
+
+int gpio_read(unsigned n)
+{
+    gpioregs *r;
+    unsigned b;
+    
+    if((r = find_gpio(n, &b)) == 0) return 0;
+
+    return (readl(r->in) & b) ? 1 : 0;
+}
+
+void gpio_dir(int nr, int out)
+{
+	gpio_output_enable(nr, out);
+}
+
+void gpio_set(int nr, int set)
+{
+	gpio_write(nr, set);
+}
+
+int gpio_get(int nr)
+{
+	return gpio_read(nr);
+}
+
+
diff --git a/arch_msm7k/hsusb.c b/arch_msm7k/hsusb.c
new file mode 100644
index 0000000..bdcedca
--- /dev/null
+++ b/arch_msm7k/hsusb.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <msm7k/hsusb.h>
+#include <boot/usb.h>
+#include <boot/usb_descriptors.h>
+
+#if 1
+#define DBG(x...) do {} while(0)
+#else
+#define DBG(x...) dprintf(x)
+#endif
+
+struct usb_endpoint
+{
+    struct usb_endpoint *next;
+    unsigned bit;
+    struct ept_queue_head *head;
+    struct usb_request *req;
+    unsigned char num;
+    unsigned char in;
+};
+
+struct usb_endpoint *ept_list = 0;
+struct ept_queue_head *epts = 0;
+
+static int usb_online = 0;
+static int usb_highspeed = 0;
+
+struct usb_endpoint *usb_endpoint_alloc(unsigned num, unsigned in, unsigned max_pkt)
+{
+    struct usb_endpoint *ept;
+    unsigned cfg;
+
+    ept = alloc(sizeof(*ept));
+    
+    ept->num = num;
+    ept->in = !!in;
+    ept->req = 0;
+    
+    cfg = CONFIG_MAX_PKT(max_pkt) | CONFIG_ZLT;
+
+    if(ept->in) {
+        ept->bit = EPT_TX(ept->num);
+    } else {
+        ept->bit = EPT_RX(ept->num);
+        if(num == 0) 
+            cfg |= CONFIG_IOS;
+    }
+
+    ept->head = epts + (num * 2) + (ept->in);
+    ept->head->config = cfg;
+
+    ept->next = ept_list;
+    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;
+}
+
+static void endpoint_enable(struct usb_endpoint *ept, unsigned yes)
+{
+    unsigned n = readl(USB_ENDPTCTRL(ept->num));
+
+    if(yes) {
+        if(ept->in) {
+            n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+        } else {
+            n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+        }
+
+        if(ept->num != 0) {
+                /* XXX should be more dynamic... */
+            if(usb_highspeed) {
+                ept->head->config = CONFIG_MAX_PKT(512) | CONFIG_ZLT;
+            } else {
+                ept->head->config = CONFIG_MAX_PKT(64) | CONFIG_ZLT;
+            }
+        }
+    }
+    writel(n, USB_ENDPTCTRL(ept->num));
+}
+
+struct usb_request *usb_request_alloc(unsigned bufsiz)
+{
+    struct usb_request *req;
+    req = alloc(sizeof(*req));
+    req->buf = alloc(bufsiz);
+    req->item = alloc(32);
+    return req;
+}
+
+int usb_queue_req(struct usb_endpoint *ept, struct usb_request *req)
+{
+    struct ept_queue_item *item = req->item;
+    unsigned phys = (unsigned) req->buf;
+    
+    item->next = TERMINATE;
+    item->info = INFO_BYTES(req->length) | INFO_IOC | INFO_ACTIVE;
+    item->page0 = phys;
+    item->page1 = (phys & 0xfffff000) + 0x1000;
+    
+    ept->head->next = (unsigned) item;
+    ept->head->info = 0;
+    ept->req = req;
+    
+    DBG("ept%d %s queue req=%p\n",
+            ept->num, ept->in ? "in" : "out", req);
+
+    writel(ept->bit, USB_ENDPTPRIME);
+    return 0;
+}
+
+static void handle_ept_complete(struct usb_endpoint *ept)
+{
+    struct ept_queue_item *item;
+    unsigned actual;
+    int status;
+    struct usb_request *req;
+    
+    DBG("ept%d %s complete req=%p\n",
+            ept->num, ept->in ? "in" : "out", ept->req);
+    
+    req = ept->req;
+    if(req) {
+        ept->req = 0;
+        
+        item = req->item;
+
+        if(item->info & 0xff) {
+            actual = 0;
+            status = -1;
+            dprintf("EP%d/%s FAIL nfo=%x pg0=%x\n",
+                    ept->num, ept->in ? "in" : "out", item->info, item->page0);
+        } else {
+            actual = req->length - ((item->info >> 16) & 0x7fff);
+            status = 0;
+        }
+        if(req->complete)
+            req->complete(req, actual, status);
+    }
+}
+
+static const char *reqname(unsigned r)
+{
+    switch(r) {
+    case GET_STATUS: return "GET_STATUS";
+    case CLEAR_FEATURE: return "CLEAR_FEATURE";
+    case SET_FEATURE: return "SET_FEATURE";
+    case SET_ADDRESS: return "SET_ADDRESS";
+    case GET_DESCRIPTOR: return "GET_DESCRIPTOR";
+    case SET_DESCRIPTOR: return "SET_DESCRIPTOR";
+    case GET_CONFIGURATION: return "GET_CONFIGURATION";
+    case SET_CONFIGURATION: return "SET_CONFIGURATION";
+    case GET_INTERFACE: return "GET_INTERFACE";
+    case SET_INTERFACE: return "SET_INTERFACE";
+    default: return "*UNKNOWN*";
+    }
+}
+
+static struct usb_endpoint *ep0in, *ep0out;
+static struct usb_request *ep0req;
+
+static void setup_ack(void)
+{
+    ep0req->complete = 0;
+    ep0req->length = 0;
+    usb_queue_req(ep0in, ep0req);
+}
+
+static void ep0in_complete(struct usb_request *req, unsigned actual, int status)
+{
+    DBG("ep0in_complete %p %d %d\n", req, actual, status);
+    if(status == 0) {
+        req->length = 0;
+        req->complete = 0;
+        usb_queue_req(ep0out, req);
+    }
+}
+
+static void setup_tx(void *buf, unsigned len)
+{
+    DBG("setup_tx %p %d\n", buf, len);
+    memcpy(ep0req->buf, buf, len);
+    ep0req->complete = ep0in_complete;
+    ep0req->length = len;
+    usb_queue_req(ep0in, ep0req);
+}
+
+static unsigned char usb_config_value = 0;
+
+#define SETUP(type,request) (((type) << 8) | (request))
+
+static void handle_setup(struct usb_endpoint *ept)
+{
+    setup_packet s;
+    
+    memcpy(&s, ept->head->setup_data, sizeof(s));
+    writel(ept->bit, USB_ENDPTSETUPSTAT);
+
+    DBG("handle_setup type=0x%b req=0x%b val=%d idx=%d len=%d (%s)\n",
+            s.type, s.request, s.value, s.index, s.length,
+            reqname(s.request));
+
+    switch(SETUP(s.type,s.request)) {
+    case SETUP(DEVICE_READ, GET_STATUS): {
+        unsigned zero = 0;
+        if(s.length == 2) {
+            setup_tx(&zero, 2);
+            return;
+        }
+        break;
+    }
+    case SETUP(DEVICE_READ, GET_DESCRIPTOR): {
+        dtable *d = usb_highspeed ? descr_hs : descr_fs;
+        while(d->data) {
+            if(s.value == d->id) {
+                unsigned len = d->length;
+                if(len > s.length) len = s.length;
+                setup_tx(d->data, len);
+                return;
+            }
+            d++;
+        }
+        break;
+    }
+    case SETUP(DEVICE_READ, GET_CONFIGURATION):
+            /* disabling this causes data transaction failures on OSX. Why?
+             */
+        if((s.value == 0) && (s.index == 0) && (s.length == 1)) {
+            setup_tx(&usb_config_value, 1);
+            return;
+        }
+        break;
+    case SETUP(DEVICE_WRITE, SET_CONFIGURATION):
+        if(s.value == 1) {
+            struct usb_endpoint *ept;
+                /* enable endpoints */
+            for(ept = ept_list; ept; ept = ept->next){
+                if(ept->num == 0) 
+                    continue;
+                endpoint_enable(ept, s.value);
+            }
+            usb_config_value = 1;
+        } else {
+            writel(0, USB_ENDPTCTRL(1));
+            usb_config_value = 0;
+        }
+        setup_ack();
+        usb_online = s.value ? 1 : 0;
+        usb_status(s.value ? 1 : 0, usb_highspeed);
+        return;
+    case SETUP(DEVICE_WRITE, SET_ADDRESS):
+            /* write address delayed (will take effect
+            ** after the next IN txn)
+            */
+        writel((s.value << 25) | (1 << 24), USB_DEVICEADDR);
+        setup_ack();
+        return;
+    case SETUP(INTERFACE_WRITE, SET_INTERFACE):
+            /* if we ack this everything hangs */
+            /* per spec, STALL is valid if there is not alt func */
+        goto stall;
+    case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): {
+        struct usb_endpoint *ept;
+        unsigned num = s.index & 15;
+        unsigned in = !!(s.index & 0x80);
+        
+        if((s.value == 0) && (s.length == 0)) {
+            DBG("clr feat %d %d\n", num, in);
+            for(ept = ept_list; ept; ept = ept->next) {
+                if((ept->num == num) && (ept->in == in)) {
+                    endpoint_enable(ept, 1);
+                    setup_ack();
+                    return;
+                }
+            }
+        }
+        break;
+    }
+    }
+
+    dprintf("STALL %s %b %b %d %d %d\n",
+            reqname(s.request),
+            s.type, s.request, s.value, s.index, s.length);
+
+stall:
+    writel((1<<16) | (1 << 0), USB_ENDPTCTRL(ept->num));    
+}
+
+unsigned ulpi_read(unsigned reg)
+{
+        /* initiate read operation */
+    writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+               USB_ULPI_VIEWPORT);
+
+        /* wait for completion */
+    while(readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
+    
+    return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+void ulpi_write(unsigned val, unsigned reg)
+{
+        /* initiate write operation */
+    writel(ULPI_RUN | ULPI_WRITE | 
+               ULPI_ADDR(reg) | ULPI_DATA(val),
+               USB_ULPI_VIEWPORT);
+
+        /* wait for completion */
+    while(readl(USB_ULPI_VIEWPORT) & ULPI_RUN) ;
+}
+
+void board_usb_init(void);
+void board_ulpi_init(void);
+
+void usb_init(void) 
+{
+    epts = alloc_page_aligned(4096);
+
+    memset(epts, 0, 32 * sizeof(struct ept_queue_head));
+    
+    board_usb_init();
+    
+        /* select ULPI phy */
+    writel(0x81000000, USB_PORTSC);
+
+        /* RESET */
+    writel(0x00080002, USB_USBCMD);
+    mdelay(20);
+    
+    board_ulpi_init();
+    
+    writel((unsigned) epts, USB_ENDPOINTLISTADDR);
+
+        /* select DEVICE mode */
+    writel(0x02, USB_USBMODE);
+
+    writel(0xffffffff, USB_ENDPTFLUSH);
+    
+        /* go to RUN mode (D+ pullup enable) */
+    writel(0x00080001, USB_USBCMD);
+
+
+    ep0out = usb_endpoint_alloc(0, 0, 64);
+    ep0in = usb_endpoint_alloc(0, 1, 64);
+    ep0req = usb_request_alloc(4096);
+}
+
+void usb_shutdown(void)
+{
+        /* disable pullup */
+    writel(0x0008000, USB_USBCMD);
+    mdelay(10);
+}
+
+void usb_poll(void) 
+{
+    struct usb_endpoint *ept;
+    unsigned n = readl(USB_USBSTS);
+    writel(n, USB_USBSTS);
+    
+    n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
+    
+    if(n == 0) return;
+    
+    if(n & STS_URI) {
+        writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+        writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+        writel(0xffffffff, USB_ENDPTFLUSH);
+        writel(0, USB_ENDPTCTRL(1));
+        DBG("-- reset --\n");
+        usb_online = 0;
+        usb_config_value = 0;
+
+            /* error out any pending reqs */
+        for(ept = ept_list; ept; ept = ept->next) {
+            ept->head->info = INFO_ACTIVE;
+            handle_ept_complete(ept);
+        }
+        usb_status(0, usb_highspeed);
+    }
+    if(n & STS_SLI) {
+        DBG("-- suspend --\n");
+    }
+    if(n & STS_PCI) {
+        DBG("-- portchange --\n");
+        unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
+        if(spd == 2) {
+            usb_highspeed = 1;
+        } else {
+            usb_highspeed = 0;
+        }
+    }
+    if(n & STS_UEI) dprintf("<UEI %x>\n", readl(USB_ENDPTCOMPLETE));
+#if 0
+    DBG("STS: ");
+    if(n & STS_UEI) DBG("ERROR ");
+    if(n & STS_SLI) DBG("SUSPEND ");
+    if(n & STS_URI) DBG("RESET ");
+    if(n & STS_PCI) DBG("PORTCHANGE ");
+    if(n & STS_UI) DBG("USB ");
+    DBG("\n");
+#endif
+    if((n & STS_UI) || (n & STS_UEI)) {
+        n = readl(USB_ENDPTSETUPSTAT);
+        if(n & EPT_RX(0)) {
+            handle_setup(ep0out);
+        }
+
+        n = readl(USB_ENDPTCOMPLETE);
+        if(n != 0) {
+            writel(n, USB_ENDPTCOMPLETE);
+        }
+
+        for(ept = ept_list; ept; ept = ept->next){
+            if(n & ept->bit) {
+                handle_ept_complete(ept);
+            }
+        }
+    }
+//    dprintf("@\n");
+}
+
+
diff --git a/arch_msm7k/mddi.c b/arch_msm7k/mddi.c
new file mode 100644
index 0000000..4cfd735
--- /dev/null
+++ b/arch_msm7k/mddi.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/board.h>
+#include <msm7k/mddi.h>
+
+unsigned fb_width = 0;
+unsigned fb_height = 0;
+
+static unsigned short *FB;
+static mddi_llentry *mlist;
+
+void wr32(void *_dst, unsigned n)
+{
+    unsigned char *src = (unsigned char*) &n;
+    unsigned char *dst = _dst;
+
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+};
+
+void printcaps(mddi_client_caps *c)
+{
+    if((c->length != 0x4a) || (c->type != 0x42)) {
+        dprintf("bad caps header\n");
+        memset(c, 0, sizeof(*c));
+        return;
+    }
+
+    dprintf("mddi: bm: %d,%d win %d,%d rgb %x\n",
+            c->bitmap_width, c->bitmap_height,
+            c->display_window_width, c->display_window_height,
+            c->rgb_cap);
+    dprintf("mddi: vend %x prod %x\n",
+            c->manufacturer_name, c->product_code);
+
+    fb_width = c->bitmap_width;
+    fb_height = c->bitmap_height;
+
+    panel_init(c);
+}
+
+mddi_llentry *mlist_remote_write = 0;
+
+void mddi_remote_write(unsigned val, unsigned reg)
+{
+    mddi_llentry *ll;
+    mddi_register_access *ra;
+    unsigned s;
+
+    if(mlist_remote_write == 0) {
+        mlist_remote_write = alloc(sizeof(mddi_llentry));
+    }
+
+    ll = mlist_remote_write;
+    
+    ra = &(ll->u.r);
+    ra->length = 14 + 4;
+    ra->type = TYPE_REGISTER_ACCESS;
+    ra->client_id = 0;
+    ra->rw_info = MDDI_WRITE | 1;
+    ra->crc = 0;
+
+    wr32(&ra->reg_addr, reg);
+    wr32(&ra->reg_data, val);    
+
+    ll->flags = 1;
+    ll->header_count = 14;
+    ll->data_count = 4;
+    wr32(&ll->data, (unsigned) &ra->reg_data);
+    wr32(&ll->next, 0);
+    ll->reserved = 0;
+
+    writel((unsigned) ll, MDDI_PRI_PTR);
+
+    s = readl(MDDI_STAT);
+    while((s & 0x20) == 0){
+        s = readl(MDDI_STAT);
+    }
+}
+
+void mddi_start_update(void)
+{
+    writel((unsigned) mlist, MDDI_PRI_PTR);
+}
+
+int mddi_update_done(void)
+{
+    return !!(readl(MDDI_STAT) & MDDI_STAT_PRI_LINK_LIST_DONE);
+}
+
+void mddi_do_cmd(unsigned cmd)
+{
+    writel(cmd, MDDI_CMD);
+
+    while (!(readl(MDDI_INT) & MDDI_INT_NO_REQ_PKTS_PENDING)) ;
+}
+
+unsigned char *rev_pkt_buf;
+
+void mddi_get_caps(void)
+{
+    unsigned timeout = 100000;
+    unsigned n;
+
+    memset(rev_pkt_buf, 0xee, 256);
+
+//    writel(CMD_HIBERNATE, MDDI_CMD);
+//    writel(CMD_LINK_ACTIVE, MDDI_CMD);
+    
+    writel(256, MDDI_REV_SIZE);
+    writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
+    mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
+
+        /* sometimes this will fail -- do it three times for luck... */
+    mddi_do_cmd(CMD_RTD_MEASURE);
+    mdelay(1);
+
+    mddi_do_cmd(CMD_RTD_MEASURE);
+    mdelay(1);
+
+    mddi_do_cmd(CMD_RTD_MEASURE);
+    mdelay(1);
+
+    mddi_do_cmd(CMD_GET_CLIENT_CAP);
+
+    do {
+        n = readl(MDDI_INT);
+    } while(!(n & MDDI_INT_REV_DATA_AVAIL) && (--timeout));
+    
+    if(timeout == 0) dprintf("timeout\n");
+    printcaps((mddi_client_caps*) rev_pkt_buf);
+}
+
+
+void mddi_init(void)
+{
+    unsigned n;
+
+//    dprintf("mddi_init()\n");
+
+    rev_pkt_buf = alloc(256);
+    
+    mddi_do_cmd(CMD_RESET);
+
+        /* disable periodic rev encap */
+    mddi_do_cmd(CMD_PERIODIC_REV_ENC | 0);
+
+    writel(0x0001, MDDI_VERSION);
+    writel(0x3C00, MDDI_BPS);
+    writel(0x0003, MDDI_SPM);
+
+    writel(0x0005, MDDI_TA1_LEN);
+    writel(0x000C, MDDI_TA2_LEN);
+    writel(0x0096, MDDI_DRIVE_HI);
+    writel(0x0050, MDDI_DRIVE_LO);
+    writel(0x003C, MDDI_DISP_WAKE);
+    writel(0x0002, MDDI_REV_RATE_DIV);
+
+        /* needs to settle for 5uS */
+    if (readl(MDDI_PAD_CTL) == 0) {
+        writel(0x08000, MDDI_PAD_CTL);
+        udelay(5);
+    }
+
+    writel(0xA850F, MDDI_PAD_CTL);
+    writel(0x60006, MDDI_DRIVER_START_CNT);
+
+    writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
+    writel(256, MDDI_REV_SIZE);
+    writel(256, MDDI_REV_ENCAP_SZ);
+
+    mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
+    
+        /* disable hibernate */
+    mddi_do_cmd(CMD_HIBERNATE | 0);
+
+    panel_backlight(0);
+    
+    panel_poweron();
+    
+    mddi_do_cmd(CMD_LINK_ACTIVE);
+
+    do {
+        n = readl(MDDI_STAT);
+    } while(!(n & MDDI_STAT_LINK_ACTIVE));
+
+        /* v > 8?  v > 8 && < 0x19 ? */
+    writel(2, MDDI_TEST);
+
+//    writel(CMD_PERIODIC_REV_ENC | 0, MDDI_CMD); /* disable */
+        
+	mddi_get_caps();
+
+#if 0
+    writel(0x5666, MDDI_MDP_VID_FMT_DES);
+    writel(0x00C3, MDDI_MDP_VID_PIX_ATTR);
+    writel(0x0000, MDDI_MDP_CLIENTID);
+#endif
+
+    dprintf("panel is %d x %d\n", fb_width, fb_height);
+
+    FB = alloc(2 * fb_width * fb_height);
+    mlist = alloc(sizeof(mddi_llentry) * (fb_height / 8));
+
+//    dprintf("FB @ %x  mlist @ %x\n", (unsigned) FB, (unsigned) mlist);
+    
+    for(n = 0; n < (fb_height / 8); n++) {
+        unsigned y = n * 8;
+        unsigned pixels = fb_width * 8;
+        mddi_video_stream *vs = &(mlist[n].u.v);
+
+        vs->length = sizeof(mddi_video_stream) - 2 + (pixels * 2);
+        vs->type = TYPE_VIDEO_STREAM;
+        vs->client_id = 0;
+        vs->format = 0x5565; // FORMAT_16BPP;
+        vs->pixattr = PIXATTR_BOTH_EYES | PIXATTR_TO_ALL;
+        
+        vs->left = 0;
+        vs->right = fb_width - 1;
+        vs->top = y;
+        vs->bottom = y + 7;
+        
+        vs->start_x = 0;
+        vs->start_y = y;
+        
+        vs->pixels = pixels;
+        vs->crc = 0;
+        vs->reserved = 0;
+        
+        mlist[n].header_count = sizeof(mddi_video_stream) - 2;
+        mlist[n].data_count = pixels * 2;
+        mlist[n].reserved = 0;
+        wr32(&mlist[n].data, ((unsigned) FB) + (y * fb_width * 2));
+
+        mlist[n].flags = 0;
+        wr32(&mlist[n].next, (unsigned) (mlist + n + 1));
+    }
+
+    mlist[n-1].flags = 1;
+    wr32(&mlist[n-1].next, 0);
+
+    writel(CMD_HIBERNATE, MDDI_CMD);
+    writel(CMD_LINK_ACTIVE, MDDI_CMD);
+
+    for(n = 0; n < (fb_width * fb_height); n++) FB[n] = 0;
+
+    mddi_start_update();
+
+    panel_backlight(1);
+}
+
+void *mddi_framebuffer(void)
+{
+    return FB;
+}
+
diff --git a/arch_msm7k/mddi_console.c b/arch_msm7k/mddi_console.c
new file mode 100644
index 0000000..c1389ca
--- /dev/null
+++ b/arch_msm7k/mddi_console.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/font5x12.h>
+
+static unsigned short BGCOLOR = 0x001F;
+static unsigned short FGCOLOR = 0xFFFF;
+
+static void drawglyph(unsigned short *pixels, unsigned short paint,
+                      unsigned stride, unsigned *glyph)
+{
+    unsigned x, y, data;
+    stride -= 5;
+
+    data = glyph[0];
+    for(y = 0; y < 6; y++) {
+        for(x = 0; x < 5; x++) {
+            if(data & 1) *pixels = paint;
+            data >>= 1;
+            pixels++;
+        }
+        pixels += stride;
+    }
+    data = glyph[1];
+    for(y = 0; y < 6; y++) {
+        for(x = 0; x < 5; x++) {
+            if(data & 1) *pixels = paint;
+            data >>= 1;
+            pixels++;
+        }
+        pixels += stride;
+    }
+}
+
+#if 0
+static void drawtext(unsigned x, unsigned y, unsigned paint, const char *text)
+{
+    unsigned short *pixels = mddi_framebuffer();
+    unsigned stride = fb_width;
+    char c;
+
+    while((c = *text++)) {
+        if((c < ' ') || (c > 127)) continue;
+        c = (c - 32) * 2;
+        drawglyph(pixels + y*stride + x, paint, stride, font5x12 + c);
+        x += 6;
+    }
+}
+#endif
+
+static int cx, cy, cmaxx, cmaxy;
+
+void console_clear(void)
+{
+    unsigned short *dst = mddi_framebuffer();
+    unsigned count = fb_width * fb_height;
+    cx = 0;
+    cy = 0;
+    while(count--) *dst++ = BGCOLOR;
+}
+
+static void scroll_up(void)
+{
+    unsigned short *dst = mddi_framebuffer();
+    unsigned short *src = dst + (fb_width * 12);
+    unsigned count = fb_height * (fb_width - 12);
+
+    while(count--) {
+        *dst++ = *src++;
+    }
+    count = fb_width * 12;
+    while(count--) {
+        *dst++ = BGCOLOR;
+    }       
+}
+
+void console_putc(unsigned c)
+{
+    unsigned short *pixels;
+    
+    if(c > 127) return;
+    if(c < 32) {
+        if(c == '\n') goto newline;
+        return;
+    }
+
+    pixels = mddi_framebuffer();
+    drawglyph(pixels + cy * 12 * fb_width + cx * 6, FGCOLOR,
+              fb_width, font5x12 + (c - 32) * 2);
+
+    cx++;
+    if(cx < cmaxx) return;
+
+newline:
+    cy++;
+    cx = 0;
+    if(cy >= cmaxy) {
+        cy = cmaxy - 1;
+        scroll_up();
+    }
+}
+
+void console_flush(void)
+{
+	mddi_start_update();
+	while(!mddi_update_done()) ;
+}
+
+void console_set_colors(unsigned bg, unsigned fg)
+{
+    BGCOLOR = bg;
+    FGCOLOR = fg;
+}
+
+void console_init(void)
+{
+    mddi_init();
+
+    cmaxx = fb_width / 6;
+    cmaxy = (fb_height-1) / 12;
+    cx = 0;
+    cy = 0;
+
+    console_clear();
+    console_flush();
+}
+
diff --git a/arch_msm7k/nand.c b/arch_msm7k/nand.c
new file mode 100644
index 0000000..ea123f0
--- /dev/null
+++ b/arch_msm7k/nand.c
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/flash.h>
+
+#include <msm7k/dmov.h>
+#include <msm7k/nand.h>
+#include <msm7k/shared.h>
+
+#define VERBOSE 0
+
+typedef struct dmov_ch dmov_ch;
+struct dmov_ch 
+{
+    volatile unsigned cmd;
+    volatile unsigned result;
+    volatile unsigned status;
+    volatile unsigned config;
+};
+
+static void dmov_prep_ch(dmov_ch *ch, unsigned id)
+{
+    ch->cmd = DMOV_CMD_PTR(id);
+    ch->result = DMOV_RSLT(id);
+    ch->status = DMOV_STATUS(id);
+    ch->config = DMOV_CONFIG(id);
+}
+
+#define SRC_CRCI_NAND_CMD  CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
+#define DST_CRCI_NAND_CMD  CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
+#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
+#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
+
+static unsigned CFG0, CFG1;
+
+#define CFG1_WIDE_FLASH (1U << 1)
+
+#define paddr(n) ((unsigned) (n))
+
+static int dmov_exec_cmdptr(unsigned id, unsigned *ptr)
+{
+    dmov_ch ch;
+    unsigned n;
+    
+    dmov_prep_ch(&ch, id);
+    
+    writel(DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(paddr(ptr)), ch.cmd);
+    
+    while(!(readl(ch.status) & DMOV_STATUS_RSLT_VALID)) ;
+    
+    n = readl(ch.status);
+    while(DMOV_STATUS_RSLT_COUNT(n)) {
+        n = readl(ch.result);
+        if(n != 0x80000002) {
+            dprintf("ERROR: result: %x\n", n);
+            dprintf("ERROR:  flush: %x %x %x %x\n",
+                    readl(DMOV_FLUSH0(DMOV_NAND_CHAN)),
+                    readl(DMOV_FLUSH1(DMOV_NAND_CHAN)),
+                    readl(DMOV_FLUSH2(DMOV_NAND_CHAN)),
+                    readl(DMOV_FLUSH3(DMOV_NAND_CHAN)));
+        }
+        n = readl(ch.status);
+    }
+
+    return 0;
+}
+
+static unsigned flash_maker = 0;
+static unsigned flash_device = 0;
+
+static void flash_read_id(dmov_s *cmdlist, unsigned *ptrlist)
+{
+    dmov_s *cmd = cmdlist;
+    unsigned *ptr = ptrlist;
+    unsigned *data = ptrlist + 4;
+
+    data[0] = 0 | 4;
+    data[1] = NAND_CMD_FETCH_ID;
+    data[2] = 1;
+    data[3] = 0;
+    data[4] = 0;
+    
+    cmd[0].cmd = 0 | CMD_OCB;
+    cmd[0].src = paddr(&data[0]);
+    cmd[0].dst = NAND_FLASH_CHIP_SELECT;
+    cmd[0].len = 4;
+
+    cmd[1].cmd = DST_CRCI_NAND_CMD;
+    cmd[1].src = paddr(&data[1]);
+    cmd[1].dst = NAND_FLASH_CMD;
+    cmd[1].len = 4;
+
+    cmd[2].cmd = 0;
+    cmd[2].src = paddr(&data[2]);
+    cmd[2].dst = NAND_EXEC_CMD;
+    cmd[2].len = 4;
+
+    cmd[3].cmd = SRC_CRCI_NAND_DATA;
+    cmd[3].src = NAND_FLASH_STATUS;
+    cmd[3].dst = paddr(&data[3]);
+    cmd[3].len = 4;
+
+    cmd[4].cmd = CMD_OCU | CMD_LC;
+    cmd[4].src = NAND_READ_ID;
+    cmd[4].dst = paddr(&data[4]);
+    cmd[4].len = 4;
+    
+    ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
+
+    dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
+
+#if VERBOSE
+    dprintf("status: %x\n", data[3]);
+#endif
+    dprintf("nandid: %x maker %b device %b\n",
+            data[4], data[4] & 0xff, (data[4] >> 8) & 0xff);
+
+    flash_maker = data[4] & 0xff;
+    flash_device = (data[4] >> 8) & 0xff;
+}
+
+static int flash_erase_block(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
+{
+    dmov_s *cmd = cmdlist;
+    unsigned *ptr = ptrlist;
+    unsigned *data = ptrlist + 4;
+
+        /* only allow erasing on block boundaries */
+    if(page & 63) return -1;
+
+    data[0] = NAND_CMD_BLOCK_ERASE;
+    data[1] = page;
+    data[2] = 0;
+    data[3] = 0 | 4;
+    data[4] = 1;
+    data[5] = 0xeeeeeeee;
+    data[6] = CFG0 & (~(7 << 6));  /* CW_PER_PAGE = 0 */
+    data[7] = CFG1;
+    
+    cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
+    cmd[0].src = paddr(&data[0]);
+    cmd[0].dst = NAND_FLASH_CMD;
+    cmd[0].len = 16;
+
+    cmd[1].cmd = 0;
+    cmd[1].src = paddr(&data[6]);
+    cmd[1].dst = NAND_DEV0_CFG0;
+    cmd[1].len = 8;
+    
+    cmd[2].cmd = 0;
+    cmd[2].src = paddr(&data[4]);
+    cmd[2].dst = NAND_EXEC_CMD;
+    cmd[2].len = 4;
+
+    cmd[3].cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
+    cmd[3].src = NAND_FLASH_STATUS;
+    cmd[3].dst = paddr(&data[5]);
+    cmd[3].len = 4;
+
+    ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
+
+    dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
+
+#if VERBOSE
+    dprintf("status: %x\n", data[5]);
+#endif
+    
+        /* we fail if there was an operation error, a mpu error, or the
+        ** erase success bit was not set.
+        */
+    if(data[5] & 0x110) return -1;
+    if(!(data[5] & 0x80)) return -1;
+    
+    return 0;
+}
+
+struct data_flash_io {
+    unsigned cmd;
+    unsigned addr0;
+    unsigned addr1;
+    unsigned chipsel;
+    unsigned cfg0;
+    unsigned cfg1;
+    unsigned exec;
+    unsigned ecc_cfg;
+    unsigned ecc_cfg_save;
+    struct {
+        unsigned flash_status;
+        unsigned buffer_status;
+    } result[4];
+};
+    
+static int _flash_read_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page, void *_addr, void *_spareaddr)
+{
+    dmov_s *cmd = cmdlist;
+    unsigned *ptr = ptrlist;
+    struct data_flash_io *data = (void*) (ptrlist + 4);
+    unsigned addr = (unsigned) _addr;
+    unsigned spareaddr = (unsigned) _spareaddr;
+    unsigned n;
+    
+    data->cmd = NAND_CMD_PAGE_READ_ECC;
+    data->addr0 = page << 16;
+    data->addr1 = (page >> 16) & 0xff;
+    data->chipsel = 0 | 4; /* flash0 + undoc bit */
+
+        /* GO bit for the EXEC register */
+    data->exec = 1;
+
+    data->cfg0 = CFG0;
+    data->cfg1 = CFG1;
+    
+    data->ecc_cfg = 0x203;
+
+        /* save existing ecc config */
+    cmd->cmd = CMD_OCB;
+    cmd->src = NAND_EBI2_ECC_BUF_CFG;
+    cmd->dst = paddr(&data->ecc_cfg_save);
+    cmd->len = 4;
+    cmd++;
+
+    for(n = 0; n < 4; n++) {
+            /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
+        cmd->cmd = DST_CRCI_NAND_CMD;
+        cmd->src = paddr(&data->cmd);
+        cmd->dst = NAND_FLASH_CMD;
+        cmd->len = ((n == 0) ? 16 : 4);
+        cmd++;
+
+        if (n == 0) {
+                /* block on cmd ready, set configuration */
+            cmd->cmd = 0;
+            cmd->src = paddr(&data->cfg0);
+            cmd->dst = NAND_DEV0_CFG0;
+            cmd->len = 8;
+            cmd++;
+
+                /* set our ecc config */
+            cmd->cmd = 0;
+            cmd->src = paddr(&data->ecc_cfg);
+            cmd->dst = NAND_EBI2_ECC_BUF_CFG;
+            cmd->len = 4;
+            cmd++;
+        }
+            /* kick the execute register */
+        cmd->cmd = 0;
+        cmd->src = paddr(&data->exec);
+        cmd->dst = NAND_EXEC_CMD;
+        cmd->len = 4;
+        cmd++;
+
+            /* block on data ready, then read the status register */
+        cmd->cmd = SRC_CRCI_NAND_DATA;
+        cmd->src = NAND_FLASH_STATUS;
+        cmd->dst = paddr(&data->result[n]);
+        cmd->len = 8;
+        cmd++;
+
+            /* read data block */
+        cmd->cmd = 0;
+        cmd->src = NAND_FLASH_BUFFER;
+        cmd->dst = addr + n * 516;
+        cmd->len = ((n < 3) ? 516 : 500);
+        cmd++;
+    }
+
+        /* read extra data */
+    cmd->cmd = 0;
+    cmd->src = NAND_FLASH_BUFFER + 500;
+    cmd->dst = spareaddr;
+    cmd->len = 16;
+    cmd++;
+    
+        /* restore saved ecc config */
+    cmd->cmd = CMD_OCU | CMD_LC;
+    cmd->src = paddr(&data->ecc_cfg_save);
+    cmd->dst = NAND_EBI2_ECC_BUF_CFG;
+    cmd->len = 4;
+
+    ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
+
+    dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
+
+#if VERBOSE
+    dprintf("read page %d: status: %x %x %x %x\n",
+            page, data[5], data[6], data[7], data[8]);
+	for(n = 0; n < 4; n++) {
+	    ptr = (unsigned*)(addr + 512 * n);
+	    dprintf("data%d:   %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
+	    ptr = (unsigned*)(spareaddr + 16 * n);
+	    dprintf("spare data%d   %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
+	}
+#endif
+    
+        /* if any of the writes failed (0x10), or there was a
+        ** protection violation (0x100), we lose
+        */
+    for(n = 0; n < 4; n++) {
+        if (data->result[n].flash_status & 0x110) {
+            return -1;
+        }
+    }
+    
+    return 0;
+}
+
+static int _flash_write_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page,
+                             const void *_addr, const void *_spareaddr)
+{
+    dmov_s *cmd = cmdlist;
+    unsigned *ptr = ptrlist;
+    struct data_flash_io *data = (void*) (ptrlist + 4);
+    unsigned addr = (unsigned) _addr;
+    unsigned spareaddr = (unsigned) _spareaddr;
+    unsigned n;    
+
+    data->cmd = NAND_CMD_PRG_PAGE;
+    data->addr0 = page << 16;
+    data->addr1 = (page >> 16) & 0xff;
+    data->chipsel = 0 | 4; /* flash0 + undoc bit */
+
+    data->cfg0 = CFG0;
+    data->cfg1 = CFG1;
+
+        /* GO bit for the EXEC register */
+    data->exec = 1;
+
+    data->ecc_cfg = 0x203;
+
+        /* save existing ecc config */
+    cmd->cmd = CMD_OCB;
+    cmd->src = NAND_EBI2_ECC_BUF_CFG;
+    cmd->dst = paddr(&data->ecc_cfg_save);
+    cmd->len = 4;
+    cmd++;
+
+    for(n = 0; n < 4; n++) {
+            /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
+        cmd->cmd = DST_CRCI_NAND_CMD;
+        cmd->src = paddr(&data->cmd);
+        cmd->dst = NAND_FLASH_CMD;
+        cmd->len = ((n == 0) ? 16 : 4);
+        cmd++;
+
+        if (n == 0) {
+                /*  set configuration */
+            cmd->cmd = 0;
+            cmd->src = paddr(&data->cfg0);
+            cmd->dst = NAND_DEV0_CFG0;
+            cmd->len = 8;
+            cmd++;
+
+                /* set our ecc config */
+            cmd->cmd = 0;
+            cmd->src = paddr(&data->ecc_cfg);
+            cmd->dst = NAND_EBI2_ECC_BUF_CFG;
+            cmd->len = 4;
+            cmd++;
+        }
+
+            /* write data block */
+        cmd->cmd = 0;
+        cmd->src = addr + n * 516;
+        cmd->dst = NAND_FLASH_BUFFER;
+        cmd->len = ((n < 3) ? 516 : 510);
+        cmd++;
+        
+        if (n == 3) {
+                /* write extra data */
+            cmd->cmd = 0;
+            cmd->src = spareaddr;
+            cmd->dst = NAND_FLASH_BUFFER + 500;
+            cmd->len = 16;
+            cmd++;
+        }
+        
+            /* kick the execute register */
+        cmd->cmd = 0;
+        cmd->src = paddr(&data->exec);
+        cmd->dst = NAND_EXEC_CMD;
+        cmd->len = 4;
+        cmd++;
+
+            /* block on data ready, then read the status register */
+        cmd->cmd = SRC_CRCI_NAND_DATA;
+        cmd->src = NAND_FLASH_STATUS;
+        cmd->dst = paddr(&data->result[n]);
+        cmd->len = 8;
+        cmd++;
+    }
+
+        /* restore saved ecc config */
+    cmd->cmd = CMD_OCU | CMD_LC;
+    cmd->src = paddr(&data->ecc_cfg_save);
+    cmd->dst = NAND_EBI2_ECC_BUF_CFG;
+    cmd->len = 4;
+
+    ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
+
+    dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
+
+#if VERBOSE
+    dprintf("write page %d: status: %x %x %x %x\n",
+            page, data[5], data[6], data[7], data[8]);
+#endif
+    
+        /* if any of the writes failed (0x10), or there was a
+        ** protection violation (0x100), or the program success
+        ** bit (0x80) is unset, we lose
+        */
+    for(n = 0; n < 4; n++) {
+        if(data->result[n].flash_status & 0x110) return -1;
+        if(!(data->result[n].flash_status & 0x80)) return -1;
+    }
+
+    return 0;
+}
+
+unsigned nand_cfg0;
+unsigned nand_cfg1;
+
+static int flash_read_config(dmov_s *cmdlist, unsigned *ptrlist)
+{
+    cmdlist[0].cmd = CMD_OCB;
+    cmdlist[0].src = NAND_DEV0_CFG0;
+    cmdlist[0].dst = paddr(&CFG0);
+    cmdlist[0].len = 4;
+
+    cmdlist[1].cmd = CMD_OCU | CMD_LC;
+    cmdlist[1].src = NAND_DEV0_CFG1;
+    cmdlist[1].dst = paddr(&CFG1);
+    cmdlist[1].len = 4;
+
+    *ptrlist = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
+
+    dmov_exec_cmdptr(DMOV_NAND_CHAN, ptrlist);
+
+    if((CFG0 == 0) || (CFG1 == 0)) {
+        return -1;
+    }
+    
+    dprintf("nandcfg: %x %x (initial)\n", CFG0, CFG1);
+    
+	CFG0 = (3 <<  6)  /* 4 codeword per page for 2k nand */
+		|  (516 <<  9)  /* 516 user data bytes */
+		|   (10 << 19)  /* 10 parity bytes */
+		|    (5 << 27)  /* 5 address cycles */
+		|    (1 << 30)  /* Read status before data */
+		|    (1 << 31)  /* Send read cmd */
+            /* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
+		| ((nand_cfg1 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
+	CFG1 = (0 <<  0)  /* Enable ecc */
+		|    (7 <<  2)  /* 8 recovery cycles */
+		|    (0 <<  5)  /* Allow CS deassertion */
+		|  (465 <<  6)  /* Bad block marker location */
+		|    (0 << 16)  /* Bad block in user data area */
+		|    (2 << 17)  /* 6 cycle tWB/tRB */
+		| (nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
+
+    dprintf("nandcfg: %x %x (used)\n", CFG0, CFG1);
+
+    return 0;
+}
+
+static unsigned *flash_ptrlist;
+static dmov_s *flash_cmdlist;
+static void *flash_spare;
+static void *flash_data;
+
+int flash_init(void)
+{
+    flash_ptrlist = alloc(1024);
+    flash_cmdlist = alloc(1024);
+    flash_data = alloc(2048);
+    flash_spare = alloc(64);
+    
+    if(flash_read_config(flash_cmdlist, flash_ptrlist)) {
+        dprintf("ERROR: could not read CFG0/CFG1 state\n");
+        for(;;);
+    }
+    
+    flash_read_id(flash_cmdlist, flash_ptrlist);
+        
+    return 0;
+}
+
+int flash_erase(ptentry *ptn)
+{
+    unsigned block = ptn->start;
+    unsigned count = ptn->length;
+    
+    while(count-- > 0) {
+        if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * 64)) {
+            dprintf("cannot erase @ %d (bad block?)\n", block);
+        }
+        block++;
+    }
+    return 0;
+}
+
+int flash_read_ext(ptentry *ptn, unsigned extra_per_page, unsigned offset, void *data, unsigned bytes)
+{
+    unsigned page = (ptn->start * 64) + (offset / 2048);
+    unsigned lastpage = (ptn->start + ptn->length) * 64;
+    unsigned count = (bytes + 2047 + extra_per_page) / (2048 + extra_per_page);
+    unsigned *spare = (unsigned*) flash_spare;
+    unsigned errors = 0;
+    unsigned char *image = data;
+    
+    if(offset & 2047)
+        return -1;
+    
+    while(page < lastpage) {
+        if(count == 0) {
+            dprintf("flash_read_image: success (%d errors)\n", errors);
+            return 0;
+        }
+        
+        if(_flash_read_page(flash_cmdlist, flash_ptrlist, page++, image, spare)) {
+            errors++;
+            continue;
+        }
+        image += 2048;
+        memcpy(image, spare, extra_per_page);
+        image += extra_per_page;
+        count -= 1;
+    }
+
+        /* could not find enough valid pages before we hit the end */
+    dprintf("flash_read_image: failed (%d errors)\n", errors);
+    return 0xffffffff;
+}
+
+int flash_write(ptentry *ptn, unsigned extra_per_page, const void *data, unsigned bytes)
+{
+    unsigned page = ptn->start * 64;
+    unsigned lastpage = (ptn->start + ptn->length) * 64;
+    unsigned *spare = (unsigned*) flash_spare;
+    const unsigned char *image = data;
+    unsigned wsize = 2048 + extra_per_page;
+    unsigned n;
+    int r;
+
+    for(n = 0; n < 16; n++) spare[n] = 0xffffffff;
+
+    while(bytes > 0) {
+        if(bytes < wsize) {
+            dprintf("flash_write_image: image undersized (%d < %d)\n", bytes, wsize);
+            return -1;
+        }
+        if(page >= lastpage) {
+            dprintf("flash_write_image: out of space\n");
+            return -1;
+        }
+
+        if((page & 63) == 0) {
+            if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
+                dprintf("flash_write_image: bad block @ %d\n", page >> 6);
+                page += 64;
+                continue;
+            }
+        }
+        
+        if(extra_per_page) {
+            r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, image + 2048);
+        } else {
+            r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, spare);
+        }
+        if(r) {
+            dprintf("flash_write_image: write failure @ page %d (src %d)\n", page, image - (const unsigned char *)data);
+            image -= (page & 63) * wsize;
+            bytes += (page & 63) * wsize;
+            page &= ~63;
+            if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
+                dprintf("flash_write_image: erase failure @ page %d\n", page);
+            }
+            dprintf("flash_write_image: restart write @ page %d (src %d)\n", page, image - (const unsigned char *)data);
+            page += 64;
+            continue;
+        }
+
+        image += wsize;
+        bytes -= wsize;
+    }
+
+        /* erase any remaining pages in the partition */
+    page = (page + 63) & (~63);
+    while(page < lastpage){
+        if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
+            dprintf("flash_write_image: bad block @ %d\n", page >> 6);
+        }
+        page += 64;
+    }
+
+    dprintf("flash_write_image: success\n");
+    return 0;
+}
+
+static int flash_read_page(unsigned page, void *data, void *extra)
+{
+    return _flash_read_page(flash_cmdlist, flash_ptrlist,
+                            page, data, extra);
+}
+
diff --git a/arch_msm7k/shared.c b/arch_msm7k/shared.c
new file mode 100644
index 0000000..0ae8cd4
--- /dev/null
+++ b/arch_msm7k/shared.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <msm7k/shared.h>
+
+static void get_version(char *s, unsigned id)
+{
+    unsigned *ver = (unsigned*) MSM7K_VERSION;
+    unsigned n = ver[id];
+    
+    snprintf(s, 32, "%d.%d", n >> 16, n & 0xffff);
+}
+
+void get_version_modem(char *s)
+{
+    get_version(s, VERSION_MODEM);
+}
+
+void get_version_modem_sbl(char *s)
+{
+    get_version(s, VERSION_MODEM_SBL);
+}
+
+#define MSM_CSR_BASE 0xC0100000
+
+#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4)
+
+static inline void notify_other_proc_comm(void)
+{
+	writel(1, MSM_A2M_INT(6));
+}
+
+#define APP_COMMAND (MSM7K_SHARED_PHYS + 0x00)
+#define APP_STATUS  (MSM7K_SHARED_PHYS + 0x04)
+#define APP_DATA1   (MSM7K_SHARED_PHYS + 0x08)
+#define APP_DATA2   (MSM7K_SHARED_PHYS + 0x0C)
+
+#define MDM_COMMAND (MSM7K_SHARED_PHYS + 0x10)
+#define MDM_STATUS  (MSM7K_SHARED_PHYS + 0x14)
+#define MDM_DATA1   (MSM7K_SHARED_PHYS + 0x18)
+#define MDM_DATA2   (MSM7K_SHARED_PHYS + 0x1C)
+
+
+enum
+{
+	PCOM_CMD_IDLE = 0x0,
+	PCOM_CMD_DONE,
+	PCOM_RESET_APPS,
+	PCOM_RESET_CHIP,
+	PCOM_CONFIG_NAND_MPU,
+	PCOM_CONFIG_USB_CLKS,
+	PCOM_GET_POWER_ON_STATUS,
+	PCOM_GET_WAKE_UP_STATUS,
+	PCOM_GET_BATT_LEVEL,
+	PCOM_CHG_IS_CHARGING,
+	PCOM_POWER_DOWN,
+	PCOM_USB_PIN_CONFIG,
+	PCOM_USB_PIN_SEL,
+	PCOM_SET_RTC_ALARM,
+	PCOM_NV_READ,
+	PCOM_NV_WRITE,
+	PCOM_GET_UUID_HIGH,
+	PCOM_GET_UUID_LOW,
+	PCOM_GET_HW_ENTROPY,
+	PCOM_RPC_GPIO_TLMM_CONFIG_REMOTE,
+	PCOM_CLKCTL_RPC_ENABLE,
+	PCOM_CLKCTL_RPC_DISABLE,
+	PCOM_CLKCTL_RPC_RESET,
+	PCOM_CLKCTL_RPC_SET_FLAGS,
+	PCOM_CLKCTL_RPC_SET_RATE,
+	PCOM_CLKCTL_RPC_MIN_RATE,
+	PCOM_CLKCTL_RPC_MAX_RATE,
+	PCOM_CLKCTL_RPC_RATE,
+	PCOM_CLKCTL_RPC_PLL_REQUEST,
+	PCOM_CLKCTL_RPC_ENABLED,
+	PCOM_VREG_SWITCH,
+	PCOM_VREG_SET_LEVEL,
+	PCOM_GPIO_TLMM_CONFIG_GROUP,
+	PCOM_GPIO_TLMM_UNCONFIG_GROUP,
+	PCOM_NV_READ_HIGH_BITS,
+	PCOM_NV_WRITE_HIGH_BITS,
+	PCOM_NUM_CMDS,
+};
+
+enum
+{
+	 PCOM_INVALID_STATUS = 0x0,
+	 PCOM_READY,
+	 PCOM_CMD_RUNNING,
+	 PCOM_CMD_SUCCESS,
+	 PCOM_CMD_FAIL,
+};
+
+int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
+{
+	int ret = -1;
+
+	while (readl(MDM_STATUS) != PCOM_READY) {
+		/* XXX check for A9 reset */
+	}
+
+	writel(cmd, APP_COMMAND);
+	if (data1)
+		writel(*data1, APP_DATA1);
+	if (data2)
+		writel(*data2, APP_DATA2);
+
+	notify_other_proc_comm();
+	while (readl(APP_COMMAND) != PCOM_CMD_DONE) {
+		/* XXX check for A9 reset */
+	}
+
+	if (readl(APP_STATUS) != PCOM_CMD_FAIL) {
+		if (data1)
+			*data1 = readl(APP_DATA1);
+		if (data2)
+			*data2 = readl(APP_DATA2);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+int clock_enable(unsigned id)
+{
+    return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, 0);
+}
+
+int clock_disable(unsigned id)
+{
+    return msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, 0);
+}
+
+int clock_set_rate(unsigned id, unsigned rate)
+{
+    return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
+}
+
+int clock_get_rate(unsigned id)
+{
+    if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, 0)) {
+        return -1;
+    } else {
+        return (int) id;
+    }
+}
+
+void reboot(void)
+{
+    msm_proc_comm(PCOM_RESET_CHIP, 0, 0);
+    for (;;) ;
+}
+
+int vreg_enable(unsigned id)
+{
+    unsigned n = 1;
+    return msm_proc_comm(PCOM_VREG_SWITCH, &id, &n);
+}
+
+int vreg_disable(unsigned id)
+{
+    unsigned n = 0;
+    return msm_proc_comm(PCOM_VREG_SWITCH, &id, &n);
+}
+
+int vreg_set_level(unsigned id, unsigned level)
+{
+    return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &level);
+}
+
+
diff --git a/arch_msm7k/smem.c b/arch_msm7k/smem.c
new file mode 100644
index 0000000..c7d0c9b
--- /dev/null
+++ b/arch_msm7k/smem.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct smem_heap_info
+{
+	unsigned initialized;
+	unsigned free_offset;
+	unsigned heap_remaining;
+	unsigned reserved;
+};
+
+struct smem_heap_entry
+{
+	unsigned allocated;
+	unsigned offset;
+	unsigned size;
+	unsigned reserved;
+};
+
+struct smem_proc_comm
+{
+	unsigned command;
+	unsigned status;
+	unsigned data1;
+	unsigned data2;
+};
+
+struct smem_shared
+{
+	struct smem_proc_comm proc_comm[4];
+	unsigned version[32];
+	struct smem_heap_info heap_info;
+	struct smem_heap_entry heap_toc[128];
+};	
+	
+struct smsm_shared
+{
+	unsigned host;
+	unsigned state;
+};
+
+#define SZ_DIAG_ERR_MSG 0xC8
+#define ID_DIAG_ERR_MSG 6
+#define ID_HEAP_INFO    3
+#define ID_SMD_CHANNELS 13
+#define ID_SHARED_STATE 82
+
+
+void dump_smem_info(void)
+{
+    unsigned n;
+    struct smem_heap_entry *he;
+    struct smem_shared *shared = (void*) 0x01f00000;
+    dprintf("--- smem info ---\n");
+    
+    dprintf("heap: init=%x free=%x remain=%x\n",
+            shared->heap_info.initialized,
+            shared->heap_info.free_offset,
+            shared->heap_info.heap_remaining);
+    
+    he = shared->heap_toc;
+    for(n = 0; n < 128; n++) {
+        if(he->allocated) {
+            dprintf("%x: alloc=%x offset=%x size=%x\n",
+                    n, he->allocated, he->offset, he->size);
+        }
+        he++;
+    }
+}
diff --git a/arch_msm7k/uart.c b/arch_msm7k/uart.c
new file mode 100644
index 0000000..a7be074
--- /dev/null
+++ b/arch_msm7k/uart.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/uart.h>
+#include <msm7k/uart.h>
+
+static unsigned uart_base = MSM_UART1_BASE;
+
+#define uwr(v,a) writel(v, uart_base + (a))
+#define urd(a) readl(uart_base + (a))
+
+#define UART_NEED_INIT 1
+
+void uart_init(unsigned n)
+{
+
+    switch(n) {
+    case 0:
+        uart_base = MSM_UART1_BASE;
+        break;
+    case 1:
+        uart_base = MSM_UART2_BASE;
+        break;
+    case 2:
+        uart_base = MSM_UART3_BASE;
+        break;
+    }
+
+#if UART_NEED_INIT
+    uwr(0x0A, UART_CR);  /* disable TX and RX */
+
+    uwr(0x30, UART_CR);  /* reset error status */
+    uwr(0x10, UART_CR);  /* reset receiver */
+    uwr(0x20, UART_CR);  /* reset transmitter */
+
+    mdelay(100);
+    
+        /* configuration for 19.2MHz TCXO */
+    uwr(0xC0, UART_MREG);
+    uwr(0xAF, UART_NREG);
+    uwr(0x80, UART_DREG);
+    uwr(0x19, UART_MNDREG);    
+
+    uwr(0x10, UART_CR);  /* reset RX */
+    uwr(0x20, UART_CR);  /* reset TX */
+    uwr(0x30, UART_CR);  /* reset error status */
+    uwr(0x40, UART_CR);  /* reset RX break */
+    uwr(0x70, UART_CR);  /* rest? */
+    uwr(0xD0, UART_CR);  /* reset */
+
+    uwr(0x7BF, UART_IPR); /* stale timeout = 630 * bitrate */
+    uwr(0, UART_IMR);
+    uwr(115, UART_RFWR); /* RX watermark = 58 * 2 - 1 */
+    uwr(10, UART_TFWR);  /* TX watermark */
+
+    uwr(0, UART_RFWR); 
+    
+    uwr(UART_CSR_115200, UART_CSR);
+    uwr(0, UART_IRDA);
+    uwr(0x1E, UART_HCR);
+//    uwr(0x7F4, UART_MR1); /* RFS/ CTS/ 500chr RFR */
+    uwr(16, UART_MR1);
+    uwr(0x34, UART_MR2); /* 8N1 */
+    
+    mdelay(100);
+
+    uwr(0x05, UART_CR); /* enable TX & RX */
+    mdelay(100);
+#endif
+}
+
+int uart_getc(void)
+{
+    if(!(urd(UART_SR) & UART_SR_RX_READY))
+        return -1;
+    return urd(UART_RF);
+}
+
+void uart_putc(unsigned c)
+{
+    while(!(urd(UART_SR) & UART_SR_TX_READY)) ;
+    uwr(c, UART_TF);
+}
+
+int uart_tx_ready(void)
+{
+    return urd(UART_SR) & UART_SR_TX_READY;
+}
+
+
+void uart_puts(const char *s)
+{
+    while(*s) {
+        if(*s == '\n') uart_putc('\r');
+        uart_putc(*s++);
+    }
+}
+
diff --git a/arch_msm7k/vic.c b/arch_msm7k/vic.c
new file mode 100644
index 0000000..a0b820f
--- /dev/null
+++ b/arch_msm7k/vic.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <msm7k/vic.h>
+#include <msm7k/irqs.h>
+
+extern irq_handler irq_vector_table[NR_IRQS];
+
+void unknown_handler(unsigned n)
+{
+    dprintf("unsolicited irq #%d\n", n);
+    for(;;);
+}
+
+void irq_init(void)
+{
+    unsigned n;
+
+    for(n = 0; n < NR_IRQS; n++) {
+        irq_vector_table[n] = unknown_handler;
+    }
+        /* select level interrupts */
+    writel(0, VIC_INT_TYPE0);
+    writel(0, VIC_INT_TYPE1);
+    
+        /* select IRQ for all INTs */
+    writel(0, VIC_INT_SELECT0);
+    writel(0, VIC_INT_SELECT1);
+
+        /* clear interrupts */
+    writel(0xffffffff, VIC_INT_CLEAR0);
+    writel(0xffffffff, VIC_INT_CLEAR1);
+    
+        /* disable all INTs */
+    writel(0, VIC_INT_EN0);
+    writel(0, VIC_INT_EN1);
+
+        /* don't use 1136 vic */
+    writel(0, VIC_CONFIG);
+    
+    writel(1, VIC_INT_MASTEREN);
+    
+        /* enable IRQs */
+    enable_irq();
+
+    (void) readl(VIC_IRQ_VEC_RD);
+}
+
+void irq_unmask(unsigned n)
+{
+    unsigned reg, bit;
+
+    reg = n > 31 ? VIC_INT_EN1 : VIC_INT_EN0;
+    bit = 1 << (n & 31);
+    
+    writel(readl(reg) | bit, reg);
+}
+
+void irq_mask(unsigned n)
+{
+    unsigned reg, bit;
+
+    reg = n > 31 ? VIC_INT_ENCLEAR1 : VIC_INT_ENCLEAR0;
+    bit = 1 << (n & 31);
+    
+    writel(bit, reg);
+}
+
+void irq_install(unsigned n, irq_handler func, int edge)
+{
+    unsigned reg, bit, tmp;
+
+    reg = n > 31 ? VIC_INT_TYPE1 : VIC_INT_TYPE0;
+    bit = 1 << (n & 31);
+    
+    tmp = readl(reg);
+    if(edge) {
+        writel(tmp | bit, reg);
+    } else {
+        writel(tmp & (~bit), reg);
+    }
+
+    irq_vector_table[n] = func;    
+}
+
diff --git a/fastboot_protocol.txt b/fastboot_protocol.txt
new file mode 100644
index 0000000..2248992
--- /dev/null
+++ b/fastboot_protocol.txt
@@ -0,0 +1,173 @@
+
+FastBoot  Version  0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB.  It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for 
+  high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+  multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA", 
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should 
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes 
+      of the response (if present) provide a textual failure message 
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexidecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will 
+   send the indicated amount of data.  Short packets are always 
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.  
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".  
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+   
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+Example Session
+---------------
+
+Host:    "getvar:version"        request version variable
+
+Client:  "OKAY0.4"               return version "0.4"
+
+Host:    "getvar:nonexistant"    request some undefined variable
+
+Client:  "OKAY"                  return value ""
+
+Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+Client:  "DATA00001234"          ready to accept data
+
+Host:    < 0x1234 bytes >        send data
+
+Client:  "OKAY"                  success
+
+Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+Client:  "INFOerasing flash"     indicate status / progress
+         "INFOwriting flash"
+         "OKAY"                  indicate success
+
+Host:    "powerdown"             send a command
+
+Client:  "FAILunknown command"   indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a 
+  lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s"           Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response.
+
+ "download:%08x"       Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough 
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+  "verify:%08x"        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+  "flash:%s"           Write the previously downloaded image to the
+                       named partition (if possible).
+
+  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
+
+  "boot"               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+  "continue"           Continue booting as normal (if possible)
+
+  "reboot"             Reboot the device.
+
+  "reboot-bootloader"  Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+  "powerdown"          Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+  version             Version of FastBoot protocol supported.
+                      It should be "0.3" for this document.
+
+  version-bootloader  Version string for the Bootloader.
+
+  version-baseband    Version string of the Baseband Software
+
+  product             Name of the product
+
+  serialno            Product serial number
+
+  secure              If the value is "yes", this is a secure
+                      bootloader requiring a signature before
+                      it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
+
+
diff --git a/include/boot/arm.h b/include/boot/arm.h
new file mode 100644
index 0000000..13b64f2
--- /dev/null
+++ b/include/boot/arm.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_H
+#define _ARM_H
+
+#define PSR_N               0x80000000
+#define PSR_C               0x40000000
+#define PSR_Z               0x20000000
+#define PSR_V               0x10000000
+
+#define PSR_I               0x00000080
+#define PSR_F               0x00000040
+#define PSR_T               0x00000020
+
+#define PSR_MODE_MASK       0x0000001F
+#define PSR_USR             0x00000010
+#define PSR_FIQ             0x00000011
+#define PSR_IRQ             0x00000012
+#define PSR_SVC             0x00000013
+#define PSR_ABT             0x00000017
+#define PSR_UND             0x0000001B
+#define PSR_SYS             0x0000001F
+
+#endif
diff --git a/include/boot/board.h b/include/boot/board.h
new file mode 100644
index 0000000..19b5c5e
--- /dev/null
+++ b/include/boot/board.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BOARD_H_
+#define _BOARD_H_
+
+/* low-level init and partition table setup */
+void board_init(void);
+void board_reboot(void);
+void board_getvar(const char *name, char *value);
+
+/* keypad init */
+void keypad_init(void);
+
+/* return a linux kernel commandline */
+const char *board_cmdline(void);
+unsigned board_machtype(void);
+
+/* lcd panel initialization */
+struct mddi_client_caps;
+
+void panel_poweron(void);
+void panel_init(struct mddi_client_caps *caps);
+void panel_backlight(int on);
+
+#endif
diff --git a/include/boot/boot.h b/include/boot/boot.h
new file mode 100644
index 0000000..d4a4d64
--- /dev/null
+++ b/include/boot/boot.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BOOT_H_
+#define _BOOT_H_
+
+static inline void DWB(void) /* drain write buffer */
+{
+    asm volatile (
+        "mcr p15, 0, %0, c7, c10, 4\n" : : "r" (0)
+        );
+}
+
+static inline void writel(unsigned val, unsigned addr)
+{
+    DWB();
+    (*(volatile unsigned *) (addr)) = (val);
+    DWB();
+}
+
+static inline void writeb(unsigned val, unsigned addr)
+{
+    DWB();
+    (*(volatile unsigned char *) (addr)) = (val);
+    DWB();
+}
+
+static inline unsigned readl(unsigned addr)
+{
+    return (*(volatile unsigned *) (addr));
+}
+
+int dcc_putc(unsigned c);
+int dcc_getc();
+
+void enable_irq(void);
+
+/* main.c */
+enum boot_keys {
+	BOOT_KEY_STOP_BOOT = 1,
+	BOOT_KEY_CONTINUE_BOOT = 2,
+};
+extern void key_changed(unsigned int key, unsigned int is_down) __attribute__ ((weak));
+
+/* manage a list of functions to call */
+void boot_register_poll_func(void (*func)(void));
+void boot_poll(void);
+
+/* console.c */
+void dcc_init();
+
+void dprintf(const char *fmt, ...);
+void dprintf_set_putc(void (*func)(unsigned));
+void dprintf_set_flush(void (*func)(void));
+
+/* gpio */
+void gpio_output_enable(unsigned n, unsigned out);
+void gpio_write(unsigned n, unsigned on);
+int gpio_read(unsigned n);
+
+/* misc.c */
+void *alloc(unsigned sz); /* alloc 32byte aligned memory */
+void *alloc_page_aligned(unsigned sz);
+
+void *memcpy(void *dst, const void *src, unsigned len);
+void *memset(void *dst, unsigned val, unsigned len);
+char *strcpy(char *dst, const char *src);
+int strcmp(const char *s1, const char *s2);
+int memcmp(const void *a, const void *b, unsigned len);
+char *strstr(const char *s1, const char *s2);
+int strlen(const char *s);
+
+/* clock */
+unsigned cycles_per_second(void);
+void print_cpu_speed(void);
+void arm11_clock_init(void);
+void mdelay(unsigned msecs);
+void udelay(unsigned usecs);
+
+/* LCD */
+void console_init(void);
+void console_set_colors(unsigned bg, unsigned fg);
+void console_clear(void);
+void console_putc(unsigned n);
+void console_flush(void);
+
+void cprintf(const char *fmt, ...);
+
+void mddi_init(void);
+void mddi_start_update(void);
+int mddi_update_done(void);
+void *mddi_framebuffer(void);
+void mddi_remote_write(unsigned val, unsigned reg);
+extern unsigned fb_width;
+extern unsigned fb_height;
+
+/* provided by board files */
+void set_led(int on);
+
+/* provided by jtag.c */
+void jtag_okay(const char *msg);
+void jtag_fail(const char *msg);
+void jtag_dputc(unsigned ch);
+void jtag_cmd_loop(void (*do_cmd)(const char *, unsigned, unsigned, unsigned));
+
+typedef void (*irq_handler)(unsigned n);
+
+
+#define DIGEST_SIZE 20
+#define SIGNATURE_SIZE 256
+
+void compute_digest(void *data, unsigned len, void *digest_out);
+int is_signature_okay(void *digest, void *signature, void *pubkey);
+
+#if 0
+#define __attr_used __attribute__((used))
+#define __attr_init __attribute__((__section__(".init.func.0")))
+#define boot_init_hook(func) \
+static int (*__boot_init_hook__)(void) __attr_used __attr_init = func
+#endif
+
+#endif
diff --git a/include/boot/bootimg.h b/include/boot/bootimg.h
new file mode 100644
index 0000000..44fde92
--- /dev/null
+++ b/include/boot/bootimg.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BOOT_IMAGE_H_
+#define _BOOT_IMAGE_H_
+
+typedef struct boot_img_hdr boot_img_hdr;
+
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+#define BOOT_NAME_SIZE 16
+#define BOOT_ARGS_SIZE 512
+
+struct boot_img_hdr
+{
+    unsigned char magic[BOOT_MAGIC_SIZE];
+
+    unsigned kernel_size;  /* size in bytes */
+    unsigned kernel_addr;  /* physical load addr */
+
+    unsigned ramdisk_size; /* size in bytes */
+    unsigned ramdisk_addr; /* physical load addr */
+
+    unsigned second_size;  /* size in bytes */
+    unsigned second_addr;  /* physical load addr */
+
+    unsigned tags_addr;    /* physical addr for kernel tags */
+    unsigned page_size;    /* flash page size we assume */
+    unsigned unused[2];    /* future expansion: should be 0 */
+
+    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+    
+    unsigned char cmdline[BOOT_ARGS_SIZE];
+
+    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+** +-----------------+ 
+** | boot header     | 1 page
+** +-----------------+
+** | kernel          | n pages  
+** +-----------------+
+** | ramdisk         | m pages  
+** +-----------------+
+** | second stage    | o pages
+** +-----------------+
+**
+** n = (kernel_size + page_size - 1) / page_size
+** m = (ramdisk_size + page_size - 1) / page_size
+** o = (second_size + page_size - 1) / page_size
+**
+** 0. all entities are page_size aligned in flash
+** 1. kernel and ramdisk are required (size != 0)
+** 2. second is optional (second_size == 0 -> no second)
+** 3. load each element (kernel, ramdisk, second) at
+**    the specified physical address (kernel_addr, etc)
+** 4. prepare tags at tag_addr.  kernel_args[] is
+**    appended to the kernel commandline in the tags.
+** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+** 6. if second_size != 0: jump to second_addr
+**    else: jump to kernel_addr
+*/
+
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
+                        void *ramdisk, unsigned ramdisk_size,
+                        void *second, unsigned second_size,
+                        unsigned page_size,
+                        unsigned *bootimg_size);
+
+void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);                
+#endif
diff --git a/include/boot/flash.h b/include/boot/flash.h
new file mode 100644
index 0000000..c746415
--- /dev/null
+++ b/include/boot/flash.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _INCLUDE_BOOT_FLASH_H_
+#define _INCLUDE_BOOT_FLASH_H_
+
+typedef struct flash_ops flash_ops;
+typedef struct ptentry ptentry;
+
+/* flash partitions are defined in terms of blocks
+** (flash erase units)
+*/
+struct ptentry
+{
+    char name[16];
+    unsigned start;
+    unsigned length;
+    unsigned flags;
+};
+
+/* tools to populate and query the partition table */
+void flash_add_ptn(ptentry *ptn);
+ptentry *flash_find_ptn(const char *name);
+ptentry *flash_get_ptn(unsigned n);
+unsigned flash_get_ptn_count(void);
+void flash_dump_ptn(void);
+
+int flash_init(void);
+int flash_erase(ptentry *ptn);
+int flash_read_ext(ptentry *ptn, unsigned extra_per_page, unsigned offset, 
+               void *data, unsigned bytes);
+#define flash_read(ptn, offset, data, bytes) flash_read_ext(ptn, 0, offset, data, bytes)
+int flash_write(ptentry *ptn, unsigned extra_per_page,
+                const void *data, unsigned bytes);
+#endif
diff --git a/include/boot/font5x12.h b/include/boot/font5x12.h
new file mode 100644
index 0000000..e033bf6
--- /dev/null
+++ b/include/boot/font5x12.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+unsigned font5x12[] = {
+    0x00000000, 0x00000000,
+    0x08421080, 0x00020084,
+    0x00052940, 0x00000000,
+    0x15f52800, 0x0000295f,
+    0x1c52f880, 0x00023e94,
+    0x08855640, 0x0004d542,
+    0x04528800, 0x000b2725,
+    0x00021080, 0x00000000,
+    0x04211088, 0x00821042,
+    0x10841082, 0x00221108,
+    0x09575480, 0x00000000,
+    0x3e420000, 0x00000084,
+    0x00000000, 0x00223000,
+    0x3e000000, 0x00000000,
+    0x00000000, 0x00471000,
+    0x08844200, 0x00008442,
+    0x2318a880, 0x00022a31,
+    0x08429880, 0x000f9084,
+    0x1108c5c0, 0x000f8444,
+    0x1c4443e0, 0x00074610,
+    0x14a62100, 0x000423e9,
+    0x26d087e0, 0x00074610,
+    0x1e10c5c0, 0x00074631,
+    0x088443e0, 0x00010844,
+    0x1d18c5c0, 0x00074631,
+    0x3d18c5c0, 0x00074610,
+    0x08e20000, 0x00471000,
+    0x08e20000, 0x00223000,
+    0x02222200, 0x00082082,
+    0x01f00000, 0x000003e0,
+    0x20820820, 0x00008888,
+    0x1108c5c0, 0x00020084,
+    0x2b98c5c0, 0x000f05b5,
+    0x2318a880, 0x0008c63f,
+    0x1d2949e0, 0x0007ca52,
+    0x0210c5c0, 0x00074421,
+    0x252949e0, 0x0007ca52,
+    0x1e1087e0, 0x000f8421,
+    0x1e1087e0, 0x00008421,
+    0x0210c5c0, 0x00074639,
+    0x3f18c620, 0x0008c631,
+    0x084211c0, 0x00071084,
+    0x10842380, 0x00032508,
+    0x0654c620, 0x0008c525,
+    0x02108420, 0x000f8421,
+    0x2b5dc620, 0x0008c631,
+    0x2b59ce20, 0x0008c739,
+    0x2318c5c0, 0x00074631,
+    0x1f18c5e0, 0x00008421,
+    0x2318c5c0, 0x01075631,
+    0x1f18c5e0, 0x0008c525,
+    0x1c10c5c0, 0x00074610,
+    0x084213e0, 0x00021084,
+    0x2318c620, 0x00074631,
+    0x1518c620, 0x0002114a,
+    0x2b18c620, 0x000556b5,
+    0x08a54620, 0x0008c54a,
+    0x08a54620, 0x00021084,
+    0x088443e0, 0x000f8442,
+    0x0421084e, 0x00e10842,
+    0x08210420, 0x00084108,
+    0x1084210e, 0x00e42108,
+    0x0008a880, 0x00000000,
+    0x00000000, 0x01f00000,
+    0x00000104, 0x00000000,
+    0x20e00000, 0x000b663e,
+    0x22f08420, 0x0007c631,
+    0x22e00000, 0x00074421,
+    0x23e84200, 0x000f4631,
+    0x22e00000, 0x0007443f,
+    0x1e214980, 0x00010842,
+    0x22e00000, 0x1d187a31,
+    0x26d08420, 0x0008c631,
+    0x08601000, 0x00071084,
+    0x10c02000, 0x0c94a108,
+    0x0a908420, 0x0008a4a3,
+    0x084210c0, 0x00071084,
+    0x2ab00000, 0x0008d6b5,
+    0x26d00000, 0x0008c631,
+    0x22e00000, 0x00074631,
+    0x22f00000, 0x0210be31,
+    0x23e00000, 0x21087a31,
+    0x26d00000, 0x00008421,
+    0x22e00000, 0x00074506,
+    0x04f10800, 0x00064842,
+    0x23100000, 0x000b6631,
+    0x23100000, 0x00022951,
+    0x23100000, 0x000556b5,
+    0x15100000, 0x0008a884,
+    0x23100000, 0x1d185b31,
+    0x11f00000, 0x000f8444,
+    0x06421098, 0x01821084,
+    0x08421080, 0x00021084,
+    0x30421083, 0x00321084,
+    0x0004d640, 0x00000000,
+    0x00000000, 0x00000000,
+};
diff --git a/include/boot/gpio.h b/include/boot/gpio.h
new file mode 100644
index 0000000..78db64b
--- /dev/null
+++ b/include/boot/gpio.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GPIO_H_
+#define _GPIO_H_
+
+void gpio_dir(int nr, int out);
+void gpio_set(int nr, int set);
+int gpio_get(int nr);
+
+#endif
diff --git a/include/boot/gpio_keypad.h b/include/boot/gpio_keypad.h
new file mode 100644
index 0000000..11edf45
--- /dev/null
+++ b/include/boot/gpio_keypad.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _GPIO_KEYPAD_H_
+#define _GPIO_KEYPAD_H_
+
+typedef struct {
+	unsigned int *input_gpios;
+	unsigned int *output_gpios;
+	unsigned int ninputs;
+	unsigned int noutputs;
+	unsigned int *key_map;
+	unsigned int settle_time; // micro seconds to wait before reading inputs after driving each output
+	int polarity : 1; // 0: drive active column low, 1: drive active column high
+	int drive_inactive_outputs : 1;
+	unsigned long long state;
+} gpio_keypad_info;
+
+int gpio_keypad_init(gpio_keypad_info *keypad);
+void gpio_keypad_scan_keys(gpio_keypad_info *keypad);
+
+#endif
diff --git a/include/boot/tags.h b/include/boot/tags.h
new file mode 100644
index 0000000..1fc0237
--- /dev/null
+++ b/include/boot/tags.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _INCLUDE_BOOT_TAGS_H_
+#define _INCLUDE_BOOT_TAGS_H_
+
+/* tools to deal with Linux ARM boot tags */
+
+struct tag_handler 
+{
+    unsigned type;
+    void (*func)(unsigned type, void *data, unsigned bytes, void *cookie);
+    void *cookie;
+};
+
+void tags_parse(void *tags, struct tag_handler *h, unsigned count);
+
+/* convenience function */
+void tags_import_partitions(void *tags);
+unsigned tags_get_revision(void *tags);
+void tags_get_serialno(void *tags, void *sn); /* sn is 64bits */
+const char *tags_get_cmdline(void *tags);
+#endif
diff --git a/include/boot/uart.h b/include/boot/uart.h
new file mode 100644
index 0000000..90a8a67
--- /dev/null
+++ b/include/boot/uart.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _INCLUDE_BOOT_UART_H_
+#define _INCLUDE_BOOT_UART_H_
+
+void uart_init(unsigned uart_number);
+
+void uart_putc(unsigned);
+int uart_tx_ready(void);
+
+/* returns -1 if no character available, otherwise 0x00-0xff */
+int uart_getc(void);
+
+#endif
diff --git a/include/boot/usb.h b/include/boot/usb.h
new file mode 100644
index 0000000..73637c2
--- /dev/null
+++ b/include/boot/usb.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _USB_COMMON_DEFINES_H
+#define _USB_COMMON_DEFINES_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 TYPE_DEVICE          1
+#define TYPE_CONFIGURATION   2
+#define TYPE_STRING          3
+#define TYPE_INTERFACE       4
+#define TYPE_ENDPOINT        5
+
+#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 
+{
+    unsigned char type;
+    unsigned char request;
+    unsigned short value;
+    unsigned short index;
+    unsigned short length;
+} __attribute__ ((packed)) setup_packet;
+
+
+struct usb_request
+{
+    struct ept_queue_item *item;
+
+    void *buf;
+    unsigned length;
+    
+    void (*complete)(struct usb_request *req, unsigned actual, int status);
+    void *context;
+};
+
+struct usb_request *usb_request_alloc();
+struct usb_endpoint *usb_endpoint_alloc(unsigned num, unsigned in, unsigned maxpkt);
+int usb_queue_req(struct usb_endpoint *ept, struct usb_request *req);
+
+void usb_init(void);
+void usb_shutdown(void);
+void usb_poll(void);
+
+/* called to indicate online/offline status */
+void usb_status(unsigned online, unsigned highspeed);
+
+#endif
diff --git a/include/boot/usb_descriptors.h b/include/boot/usb_descriptors.h
new file mode 100644
index 0000000..434fcab
--- /dev/null
+++ b/include/boot/usb_descriptors.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static unsigned short manufacturer_string[] = {
+    (TYPE_STRING << 8) | (12 * 2),
+    'G', 'o', 'o', 'g', 'l', 'e', ',', ' ', 'I', 'n', 'c',
+};
+
+static unsigned short product_string[] = {
+    (TYPE_STRING << 8) | (12 * 2),
+    'A', 'n', 'd', 'r', 'o', 'i', 'd', ' ', '1', '.', '0',
+};
+
+static unsigned short default_string[] = {
+    (TYPE_STRING << 8) | (8 * 2),
+    'd', 'e', 'f', 'a', 'u', 'l', 't',
+};
+
+static unsigned short language_table[] = {
+    (TYPE_STRING << 8) | 4,
+    0x0409, // LANGID for US English
+};
+
+static unsigned char device_desc[] = {
+    18,              // length
+    TYPE_DEVICE,     // type
+    0x10, 0x02,      // usb spec rev 1.00
+    0x00,            // class
+    0x00,            // subclass
+    0x00,            // protocol
+    0x40,            // max packet size
+    0xD1, 0x18,      // vendor id
+    0x0D, 0xD0,      // product id
+    0x00, 0x01,      // version 1.0
+    0x01,            // manufacturer str idx
+    0x02,            // product str idx
+    0x00,            // serial number index
+    0x01,            // number of configs,
+};    
+
+static unsigned char config_desc[] = {
+    0x09,            // length
+    TYPE_CONFIGURATION,
+    0x20, 0x00,      // total length
+    0x01,            // # interfaces
+    0x01,            // config value
+    0x00,            // config string
+    0x80,            // attributes
+    0x80,            // XXX max power (250ma)
+
+    0x09,            // length
+    TYPE_INTERFACE,
+    0x00,            // interface number
+    0x00,            // alt number
+    0x02,            // # endpoints
+    0xFF,
+    0x42,
+    0x03,
+    0x00,            // interface string
+
+    0x07,            // length
+    TYPE_ENDPOINT,
+    0x81,            // in, #1
+    0x02,            // bulk
+    0x00, 0x02,      // max packet 512
+    0x00,            // interval
+    
+    0x07,            // length
+    TYPE_ENDPOINT,
+    0x01,            // out, #1
+    0x02,            // bulk
+    0x00, 0x02,      // max packet 512
+    0x01,            // interval
+};
+    
+static unsigned char config_desc_fs[] = {
+    0x09,            // length
+    TYPE_CONFIGURATION,
+    0x20, 0x00,      // total length
+    0x01,            // # interfaces
+    0x01,            // config value
+    0x00,            // config string
+    0x80,            // attributes
+    0x80,            // XXX max power (250ma)
+
+    0x09,            // length
+    TYPE_INTERFACE,
+    0x00,            // interface number
+    0x00,            // alt number
+    0x02,            // # endpoints
+    0xFF,
+    0x42,
+    0x03,
+    0x00,            // interface string
+
+    0x07,            // length
+    TYPE_ENDPOINT,
+    0x81,            // in, #1
+    0x02,            // bulk
+    0x40, 0x00,      // max packet 64
+    0x00,            // interval
+    
+    0x07,            // length
+    TYPE_ENDPOINT,
+    0x01,            // out, #1
+    0x02,            // bulk
+    0x40, 0x00,      // max packet 64
+    0x00,            // interval
+};
+    
+typedef struct 
+{
+    void *data;
+    unsigned short length;
+    unsigned short id;
+} dtable;
+
+#define ID(type,num) ((type << 8) | num)
+
+static dtable descr_hs[] = {
+    { device_desc, sizeof(device_desc), ID(TYPE_DEVICE, 0) },
+    { config_desc, sizeof(config_desc), ID(TYPE_CONFIGURATION, 0) },
+    { manufacturer_string, sizeof(manufacturer_string), ID(TYPE_STRING, 1) },
+    { product_string, sizeof(product_string), ID(TYPE_STRING, 2) },
+    { default_string, sizeof(default_string), ID(TYPE_STRING, 4) },
+    { language_table, sizeof(language_table), ID(TYPE_STRING, 0) },
+    { 0, 0, 0 },
+};    
+
+static dtable descr_fs[] = {
+    { device_desc, sizeof(device_desc), ID(TYPE_DEVICE, 0) },
+    { config_desc_fs, sizeof(config_desc), ID(TYPE_CONFIGURATION, 0) },
+    { manufacturer_string, sizeof(manufacturer_string), ID(TYPE_STRING, 1) },
+    { product_string, sizeof(product_string), ID(TYPE_STRING, 2) },
+    { default_string, sizeof(default_string), ID(TYPE_STRING, 4) },
+    { language_table, sizeof(language_table), ID(TYPE_STRING, 0) },
+    { 0, 0, 0 },
+};    
diff --git a/include/msm7k/dmov.h b/include/msm7k/dmov.h
new file mode 100644
index 0000000..b151289
--- /dev/null
+++ b/include/msm7k/dmov.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_DMOV_H
+#define __ASM_ARCH_MSM7200_DMOV_H
+
+#define MSM_DMOV_BASE 0xA9700000
+
+/* see 80-VA736-2 C pp 415-439 */
+
+#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
+#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2))
+#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2))
+#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2))
+
+/* only security domain 3 is available to the ARM11
+**
+** SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM
+**
+*/
+
+#define DMOV_CMD_PTR(ch)      DMOV_SD3(0x000, ch)
+#define DMOV_CMD_LIST         (0 << 29) /* does not work */
+#define DMOV_CMD_PTR_LIST     (1 << 29) /* works */
+#define DMOV_CMD_INPUT_CFG    (2 << 29) /* untested */
+#define DMOV_CMD_OUTPUT_CFG   (3 << 29) /* untested */
+#define DMOV_CMD_ADDR(addr)   ((addr) >> 3)
+
+#define DMOV_RSLT(ch)         DMOV_SD3(0x040, ch)
+#define DMOV_RSLT_VALID       (1 << 31) /* 0 == host has empties result fifo */
+#define DMOV_RSLT_ERROR       (1 << 3)
+#define DMOV_RSLT_FLUSH       (1 << 2)
+#define DMOV_RSLT_DONE        (1 << 1)  /* top pointer done */
+#define DMOV_RSLT_USER        (1 << 0)  /* command with FR force result */
+
+#define DMOV_FLUSH0(ch)       DMOV_SD3(0x080, ch)
+#define DMOV_FLUSH1(ch)       DMOV_SD3(0x0C0, ch)
+#define DMOV_FLUSH2(ch)       DMOV_SD3(0x100, ch)
+#define DMOV_FLUSH3(ch)       DMOV_SD3(0x140, ch)
+#define DMOV_FLUSH4(ch)       DMOV_SD3(0x180, ch)
+#define DMOV_FLUSH5(ch)       DMOV_SD3(0x1C0, ch)
+
+#define DMOV_STATUS(ch)       DMOV_SD3(0x200, ch)
+#define DMOV_STATUS_RSLT_COUNT(n)    (((n) >> 29))
+#define DMOV_STATUS_CMD_COUNT(n)     (((n) >> 27) & 3) 
+#define DMOV_STATUS_RSLT_VALID       (1 << 1)
+#define DMOV_STATUS_CMD_PTR_RDY      (1 << 0)
+
+#define DMOV_ISR              DMOV_SD3(0x380, 0)
+
+#define DMOV_CONFIG(ch)       DMOV_SD3(0x300, ch)
+#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2)
+#define DMOV_CONFIG_FOREC_FLUSH_RSLT   (1 << 1)
+#define DMOV_CONFIG_IRQ_EN             (1 << 0)
+
+/* channel assignments - from qc/dmov_7500.h */
+
+#define DMOV_NAND_CHAN        7
+#define DMOV_NAND_CRCI_CMD    5
+#define DMOV_NAND_CRCI_DATA   4
+
+#define DMOV_SDC1_CHAN        8
+#define DMOV_SDC1_CRCI        6
+
+#define DMOV_SDC2_CHAN        8
+#define DMOV_SDC2_CRCI        7
+
+#define DMOV_TSIF_CHAN        10
+#define DMOV_TSIF_CRCI        10
+
+#define DMOV_USB_CHAN         11
+
+/* no client rate control ifc (eg, ram) */
+#define DMOV_NONE_CRCI        0
+
+
+/* If the CMD_PTR register has CMD_PTR_LIST selected, the data mover
+** is going to walk a list of 32bit pointers as described below.  Each
+** pointer points to a *array* of dmov_s, etc structs.  The last pointer
+** in the list is marked with CMD_PTR_LP.  The last struct in each array
+** is marked with CMD_LC (see below).
+*/
+#define CMD_PTR_ADDR(addr)  ((addr) >> 3)
+#define CMD_PTR_LP          (1 << 31) /* last pointer */
+#define CMD_PTR_PT          (3 << 29) /* ? */
+
+
+/* Single Item Mode -- seems to work as expected */
+typedef struct {
+    unsigned cmd;
+    unsigned src;
+    unsigned dst;
+    unsigned len;
+} dmov_s;
+
+/* Scatter/Gather Mode -- does this work?*/
+typedef struct {
+    unsigned cmd;
+    unsigned src_dscr;
+    unsigned dst_dscr;
+    unsigned _reserved;
+} dmov_sg;
+
+/* bits for the cmd field of the above structures */
+
+#define CMD_LC      (1 << 31)  /* last command */
+#define CMD_FR      (1 << 22)  /* force result -- does not work? */
+#define CMD_OCU     (1 << 21)  /* other channel unblock */
+#define CMD_OCB     (1 << 20)  /* other channel block */
+#define CMD_TCB     (1 << 19)  /* ? */
+#define CMD_DAH     (1 << 18)  /* destination address hold -- does not work?*/
+#define CMD_SAH     (1 << 17)  /* source address hold -- does not work? */
+
+#define CMD_MODE_SINGLE     (0 << 0) /* dmov_s structure used */
+#define CMD_MODE_SG         (1 << 0) /* untested */
+#define CMD_MODE_IND_SG     (2 << 0) /* untested */
+#define CMD_MODE_BOX        (3 << 0) /* untested */
+
+#define CMD_DST_SWAP_BYTES  (1 << 14) /* exchange each byte n with byte n+1 */
+#define CMD_DST_SWAP_SHORTS (1 << 15) /* exchange each short n with short n+1 */
+#define CMD_DST_SWAP_WORDS  (1 << 16) /* exchange each word n with word n+1 */
+
+#define CMD_SRC_SWAP_BYTES  (1 << 11) /* exchange each byte n with byte n+1 */
+#define CMD_SRC_SWAP_SHORTS (1 << 12) /* exchange each short n with short n+1 */
+#define CMD_SRC_SWAP_WORDS  (1 << 13) /* exchange each word n with word n+1 */
+
+#define CMD_DST_CRCI(n)     (((n) & 15) << 7)
+#define CMD_SRC_CRCI(n)     (((n) & 15) << 3)
+
+
+/* NOTES:
+**
+** Looks like Channels 4, 5, 6, 7, 8, 10, 11 are available to the ARM11
+**
+*/
+#endif
diff --git a/include/msm7k/gpio.h b/include/msm7k/gpio.h
new file mode 100644
index 0000000..8d56a03
--- /dev/null
+++ b/include/msm7k/gpio.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_GPIO_H
+#define __ASM_ARCH_MSM7200_GPIO_H
+
+#define MSM_GPIO1_BASE 0xA9200000
+#define MSM_GPIO2_BASE 0xA9300000
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+
+/* output value */
+#define GPIO_OUT_0         GPIO1_REG(0x00)  /* gpio  15-0  */
+#define GPIO_OUT_1         GPIO2_REG(0x00)  /* gpio  42-16 */
+#define GPIO_OUT_2         GPIO1_REG(0x04)  /* gpio  67-43 */
+#define GPIO_OUT_3         GPIO1_REG(0x08)  /* gpio  94-68 */
+#define GPIO_OUT_4         GPIO1_REG(0x0C)  /* gpio 106-95 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0          GPIO1_REG(0x10)
+#define GPIO_OE_1          GPIO2_REG(0x08)
+#define GPIO_OE_2          GPIO1_REG(0x14)
+#define GPIO_OE_3          GPIO1_REG(0x18)
+#define GPIO_OE_4          GPIO1_REG(0x1C)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0          GPIO1_REG(0x34)
+#define GPIO_IN_1          GPIO2_REG(0x20)
+#define GPIO_IN_2          GPIO1_REG(0x38)
+#define GPIO_IN_3          GPIO1_REG(0x3C)
+#define GPIO_IN_4          GPIO1_REG(0x40)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0    GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1    GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2    GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3    GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4    GPIO1_REG(0x6C)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0     GPIO1_REG(0x70)
+#define GPIO_INT_POS_1     GPIO2_REG(0x58)
+#define GPIO_INT_POS_2     GPIO1_REG(0x74)
+#define GPIO_INT_POS_3     GPIO1_REG(0x78)
+#define GPIO_INT_POS_4     GPIO1_REG(0x7C)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0      GPIO1_REG(0x80)
+#define GPIO_INT_EN_1      GPIO2_REG(0x60)
+#define GPIO_INT_EN_2      GPIO1_REG(0x84)
+#define GPIO_INT_EN_3      GPIO1_REG(0x88)
+#define GPIO_INT_EN_4      GPIO1_REG(0x8C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1   GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1  GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+
+#endif
diff --git a/include/msm7k/gpt.h b/include/msm7k/gpt.h
new file mode 100644
index 0000000..69211ca
--- /dev/null
+++ b/include/msm7k/gpt.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_GPT_H
+#define __ASM_ARCH_MSM7200_GPT_H
+
+#define MSM_GPT_BASE 0xC0100000
+
+#define GPT_REG(off) (MSM_GPT_BASE + (off))
+
+/* See 80-VE113-1 A, pp 229-231 */
+
+#define GPT_MATCH_VAL        GPT_REG(0x0000)
+#define GPT_COUNT_VAL        GPT_REG(0x0004)
+#define GPT_ENABLE           GPT_REG(0x0008)
+#define GPT_ENABLE_CLR_ON_MATCH_EN        2
+#define GPT_ENABLE_EN                     1
+#define GPT_CLEAR            GPT_REG(0x000C)
+
+#define DGT_MATCH_VAL        GPT_REG(0x0010)
+#define DGT_COUNT_VAL        GPT_REG(0x0014)
+#define DGT_ENABLE           GPT_REG(0x0018)
+#define DGT_ENABLE_CLR_ON_MATCH_EN        2
+#define DGT_ENABLE_EN                     1
+#define DGT_CLEAR            GPT_REG(0x001C)
+
+#define CSR_PROTECTION       GPT_REG(0x0020)
+#define CSR_PROTECTION_EN                 1
+
+#endif
diff --git a/include/msm7k/hsusb.h b/include/msm7k/hsusb.h
new file mode 100644
index 0000000..5420d14
--- /dev/null
+++ b/include/msm7k/hsusb.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MSM7200_USB_H_
+#define _MSM7200_USB_H_
+
+#define MSM_USB_BASE 0xA0800000
+
+
+#define USB_ID               (MSM_USB_BASE + 0x0000)
+#define USB_HWGENERAL        (MSM_USB_BASE + 0x0004)
+#define USB_HWHOST           (MSM_USB_BASE + 0x0008)
+#define USB_HWDEVICE         (MSM_USB_BASE + 0x000C)
+#define USB_HWTXBUF          (MSM_USB_BASE + 0x0010)
+#define USB_HWRXBUF          (MSM_USB_BASE + 0x0014)
+#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
+
+#define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (MSM_USB_BASE + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (MSM_USB_BASE + 0x0104)
+#define USB_HCCPARAMS        (MSM_USB_BASE + 0x0108)
+#define USB_DCIVERSION       (MSM_USB_BASE + 0x0120) /* 16 bit */
+#define USB_USBCMD           (MSM_USB_BASE + 0x0140)
+#define USB_USBSTS           (MSM_USB_BASE + 0x0144)
+#define USB_USBINTR          (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
+#define USB_DEVICEADDR       (MSM_USB_BASE + 0x0154)
+#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
+#define USB_BURSTSIZE        (MSM_USB_BASE + 0x0160)
+#define USB_TXFILLTUNING     (MSM_USB_BASE + 0x0164)
+#define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
+#define USB_ENDPTNAK         (MSM_USB_BASE + 0x0178)
+#define USB_ENDPTNAKEN       (MSM_USB_BASE + 0x017C)
+#define USB_PORTSC           (MSM_USB_BASE + 0x0184)
+#define USB_OTGSC            (MSM_USB_BASE + 0x01A4)
+#define USB_USBMODE          (MSM_USB_BASE + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (MSM_USB_BASE + 0x01AC)
+#define USB_ENDPTPRIME       (MSM_USB_BASE + 0x01B0)
+#define USB_ENDPTFLUSH       (MSM_USB_BASE + 0x01B4)
+#define USB_ENDPTSTAT        (MSM_USB_BASE + 0x01B8)
+#define USB_ENDPTCOMPLETE    (MSM_USB_BASE + 0x01BC)
+#define USB_ENDPTCTRL(n)     (MSM_USB_BASE + 0x01C0 + (4 * (n)))
+
+
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+
+struct ept_queue_head 
+{
+    unsigned config;
+    unsigned current; /* read-only */
+
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved_0;
+    
+    unsigned char setup_data[8];
+    
+    unsigned reserved_1;
+    unsigned reserved_2;
+    unsigned reserved_3;
+    unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item
+{
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved;
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TX_ERROR         (1 << 3)
+
+
+#define STS_NAKI              (1 << 16)  /* */
+#define STS_SLI               (1 << 8)   /* R/WC - suspend state entered */
+#define STS_SRI               (1 << 7)   /* R/WC - SOF recv'd */
+#define STS_URI               (1 << 6)   /* R/WC - RESET recv'd - write to clear */
+#define STS_FRI               (1 << 3)   /* R/WC - Frame List Rollover */
+#define STS_PCI               (1 << 2)   /* R/WC - Port Change Detect */
+#define STS_UEI               (1 << 1)   /* R/WC - USB Error */
+#define STS_UI                (1 << 0)   /* R/WC - USB Transaction Complete */
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_TXI              (1 << 21)
+#define CTRL_TXD              (1 << 17)
+#define CTRL_TXS              (1 << 16)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_RXI              (1 << 5)
+#define CTRL_RXD              (1 << 1)
+#define CTRL_RXS              (1 << 0)
+
+#define CTRL_TXT_CTRL         (0 << 18)
+#define CTRL_TXT_ISOCH        (1 << 18)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_TXT_INT          (3 << 18)
+
+#define CTRL_RXT_CTRL         (0 << 2)
+#define CTRL_RXT_ISOCH        (1 << 2)
+#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_RXT_INT          (3 << 2)
+
+#define ULPI_WAKEUP           (1 << 31)
+#define ULPI_RUN              (1 << 30)
+#define ULPI_WRITE            (1 << 29)
+#define ULPI_READ             (0 << 29)
+#define ULPI_STATE_NORMAL     (1 << 27)
+#define ULPI_ADDR(n)          (((n) & 255) << 16)
+#define ULPI_DATA(n)          ((n) & 255)
+#define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
+
+#endif
diff --git a/include/msm7k/irqs.h b/include/msm7k/irqs.h
new file mode 100644
index 0000000..d37d50d
--- /dev/null
+++ b/include/msm7k/irqs.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_IRQS_H
+
+/* MSM7200 ARM11 Interrupt Numbers */
+/* See 80-VE113-1 A, pp219-221     */
+
+#define INT_A9_M2A_0         0
+#define INT_A9_M2A_1         1
+#define INT_A9_M2A_2         2
+#define INT_A9_M2A_3         3
+#define INT_A9_M2A_4         4
+#define INT_A9_M2A_5         5
+#define INT_A9_M2A_6         6
+#define INT_GP_TIMER_EXP     7
+#define INT_DEBUG_TIMER_EXP  8
+#define INT_UART1            9
+#define INT_UART2            10
+#define INT_UART3            11
+#define INT_UART1_RX         12
+#define INT_UART2_RX         13
+#define INT_UART3_RX         14
+#define INT_USB_OTG          15
+#define INT_MDDI_PRI         16
+#define INT_MDDI_EXT         17
+#define INT_MDDI_CLIENT      18
+#define INT_MDP              19
+#define INT_GRAPHICS         20
+#define INT_ADM_AARM         21
+#define INT_ADSP_A11         22
+#define INT_ADSP_A9_A11      23
+#define INT_SDC1_0           24
+#define INT_SDC1_1           25
+#define INT_SDC2_0           26
+#define INT_SDC2_1           27
+#define INT_KEYSENSE         28
+#define INT_TCHSCRN_SSBI     29
+#define INT_TCHSCRN1         30
+#define INT_TCHSCRN2         31
+
+#define INT_GPIO_GROUP1      (32 + 0)
+#define INT_GPIO_GROUP2      (32 + 1)
+#define INT_PWB_I2C          (32 + 2)
+#define INT_NAND_WR_ER_DONE  (32 + 3)
+#define INT_NAND_OP_DONE     (32 + 4)
+#define INT_SOFTRESET        (32 + 5)
+#define INT_PBUS_ARM11       (32 + 6)
+#define INT_AXI_MPU_SMI      (32 + 7)
+#define INT_AXI_MPU_EBI1     (32 + 8)
+#define INT_AD_HSSD          (32 + 9)
+#define INT_ARM11_PM         (32 + 10)
+#define INT_ARM11_DMA        (32 + 11)
+#define INT_TSIF_IRQ         (32 + 12)
+#define INT_UART1DM_IRQ      (32 + 13)
+#define INT_UART1DM_RX       (32 + 14)
+#define INT_SPARE0           (32 + 15)
+
+#define MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
+
+#define NR_IRQS 48
+
+#endif
diff --git a/include/msm7k/mddi.h b/include/msm7k/mddi.h
new file mode 100644
index 0000000..619655e
--- /dev/null
+++ b/include/msm7k/mddi.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_MDDI_H
+#define __ASM_ARCH_MSM7200_MDDI_H
+
+#define MSM_MDDI_BASE 0xAA600000
+
+/* see 80-VA736-2 C pp 776-787 */
+
+#define MDDI_REG(off) (MSM_MDDI_BASE + (off))
+
+#define MDDI_CMD               MDDI_REG(0x0000)
+#define MDDI_VERSION           MDDI_REG(0x0004)
+#define MDDI_PRI_PTR           MDDI_REG(0x0008)
+#define MDDI_SEC_PTR           MDDI_REG(0x000C)
+#define MDDI_BPS               MDDI_REG(0x0010)
+#define MDDI_SPM               MDDI_REG(0x0014)
+#define MDDI_INT               MDDI_REG(0x0018)
+
+#define MDDI_INT_PRI_PTR_READ          (1 << 0)
+#define MDDI_INT_SEC_PTR_READ          (1 << 1)
+#define MDDI_INT_REV_DATA_AVAIL        (1 << 2)
+#define MDDI_INT_DISP_REQ              (1 << 3)
+#define MDDI_INT_PRI_UNDERFLOW         (1 << 4)
+#define MDDI_INT_SEC_UNDERFLOW         (1 << 5)
+#define MDDI_INT_REV_OVERFLOW          (1 << 6)
+#define MDDI_INT_CRC_ERROR             (1 << 7)
+#define MDDI_INT_MDDI_IN               (1 << 8)
+#define MDDI_INT_PRI_OVERWRITE         (1 << 9)
+#define MDDI_INT_SEC_OVERWRITE         (1 << 10)
+#define MDDI_INT_REV_OVERWRITE         (1 << 11)
+#define MDDI_INT_DMA_FAILURE           (1 << 12)
+#define MDDI_INT_LINK_ACTIVE           (1 << 13)
+#define MDDI_INT_IN_HIBERNATION        (1 << 14)
+#define MDDI_INT_PRI_LINK_LIST_DONE    (1 << 15)
+#define MDDI_INT_SEC_LINK_LIST_DONE    (1 << 16)
+#define MDDI_INT_NO_REQ_PKTS_PENDING   (1 << 17)
+#define MDDI_INT_RTD_FAILURE           (1 << 18)
+#define MDDI_INT_REV_PKT_RECEIVED      (1 << 19)
+#define MDDI_INT_REV_PKTS_AVAIL        (1 << 20)
+
+#define MDDI_INTEN             MDDI_REG(0x001C)
+#define MDDI_REV_PTR           MDDI_REG(0x0020)
+#define MDDI_REV_SIZE          MDDI_REG(0x0024)
+#define MDDI_STAT              MDDI_REG(0x0028)
+
+#define MDDI_STAT_LINK_ACTIVE                (1 << 0)
+#define MDDI_STAT_NEW_REV_PTR                (1 << 1)
+#define MDDI_STAT_NEW_PRI_PTR                (1 << 2)
+#define MDDI_STAT_NEW_SEC_PTR                (1 << 3)
+#define MDDI_STAT_IN_HIBERNATION             (1 << 4)
+#define MDDI_STAT_PRI_LINK_LIST_DONE         (1 << 5)
+#define MDDI_STAT_SEC_LINK_LIST_DONE         (1 << 6)
+#define MDDI_STAT_SEND_TIMING_PKT            (1 << 7)
+#define MDDI_STAT_SEND_REV_ENCAP_WITH_FLAGS  (1 << 8)
+#define MDDI_STAT_SEND_POWER_DOWN            (1 << 9)
+#define MDDI_STAT_DO_HANDSHAKE               (1 << 10)
+#define MDDI_STAT_RTD_MEAS_FAIL              (1 << 11)
+#define MDDI_STAT_CLIENT_WAKEUP_REQ          (1 << 12)
+#define MDDI_STAT_DMA_ABORT                  (1 << 13)
+#define MDDI_STAT_REV_OVERFLOW_RESET         (1 << 14)
+#define MDDI_STAT_FORCE_NEW_REV_PTR          (1 << 15)
+#define MDDI_STAT_CRC_ERRORS                 (1 << 16)
+
+#define MDDI_REV_RATE_DIV      MDDI_REG(0x002C)
+#define MDDI_REV_CRC_ERR       MDDI_REG(0x0030)
+#define MDDI_TA1_LEN           MDDI_REG(0x0034)
+#define MDDI_TA2_LEN           MDDI_REG(0x0038)
+#define MDDI_TEST_BUS          MDDI_REG(0x003C)
+#define MDDI_TEST              MDDI_REG(0x0040)
+#define MDDI_REV_PKT_CNT       MDDI_REG(0x0044)
+#define MDDI_DRIVE_HI          MDDI_REG(0x0048)
+#define MDDI_DRIVE_LO          MDDI_REG(0x004C)
+#define MDDI_DISP_WAKE         MDDI_REG(0x0050)
+#define MDDI_REV_ENCAP_SZ      MDDI_REG(0x0054)
+#define MDDI_RTD_VAL           MDDI_REG(0x0058)
+#define MDDI_MDP_VID_FMT_DES   MDDI_REG(0x005C)
+#define MDDI_MDP_VID_PIX_ATTR  MDDI_REG(0x0060)
+#define MDDI_MDP_VID_CLIENTID  MDDI_REG(0x0064)
+#define MDDI_PAD_CTL           MDDI_REG(0x0068)
+#define MDDI_DRIVER_START_CNT  MDDI_REG(0x006C)
+#define MDDI_NEXT_PRI_PTR      MDDI_REG(0x0070)
+#define MDDI_NEXT_SEC_PTR      MDDI_REG(0x0074)
+#define MDDI_MISR_CTL          MDDI_REG(0x0078)
+#define MDDI_MISR_DATA         MDDI_REG(0x007C)
+#define MDDI_SF_CNT            MDDI_REG(0x0080)
+#define MDDI_MF_CNT            MDDI_REG(0x0084)
+#define MDDI_CURR_REV_PTR      MDDI_REG(0x0088)
+#define MDDI_CORE_VER          MDDI_REG(0x008C)
+
+#define CMD_POWER_DOWN         0x0100
+#define CMD_POWER_UP           0x0200
+#define CMD_HIBERNATE          0x0300
+#define CMD_RESET              0x0400
+#define CMD_IGNORE             0x0500
+#define CMD_REV_ENC_REQ        0x0600
+#define CMD_RTD_MEASURE        0x0700
+#define CMD_LINK_ACTIVE        0x0900
+#define CMD_PERIODIC_REV_ENC   0x0A00
+#define CMD_FORCE_NEW_REV_PTR  0x0C00
+
+#define CMD_GET_CLIENT_CAP     0x0601
+#define CMD_GET_CLIENT_STATUS  0x0602
+
+#if 1
+#define FORMAT_18BPP           0x5666
+#define FORMAT_24BPP           0x5888
+#define FORMAT_16BPP           0x5565
+#else
+#define FORMAT_MONOCHROME      (0 << 13)
+#define FORMAT_PALETTE         (1 << 13)
+#define FORMAT_RGB             (2 << 13)
+#define FORMAT_YCBCR422        (3 << 13)
+#define FORMAT_BAYER           (4 << 13)
+#endif
+
+#define PIXATTR_BOTH_EYES      3
+#define PIXATTR_LEFT_EYE       2
+#define PIXATTR_RIGHT_EYE      1
+#define PIXATTR_ALT_DISPLAY    0
+
+#define PIXATTR_PROGRESSIVE    0
+#define PIXATTR_INTERLACED     (1 << 2)
+#define PIXATTR_ALTERNATE      (1 << 3)
+
+#define PIXATTR_IGNORE_LRTB    (1 << 5)
+
+#define PIXATTR_TO_REFRESH     (0 << 6)
+#define PIXATTR_TO_OFFLINE     (1 << 6)
+#define PIXATTR_TO_ALL         (3 << 6)
+
+#define PIXATTR_LAST_ROW       (1 << 15)
+
+#define TYPE_VIDEO_STREAM      16
+#define TYPE_CLIENT_CAPS       66
+#define TYPE_REGISTER_ACCESS   146
+#define TYPE_CLIENT_STATUS     70
+
+typedef struct mddi_video_stream mddi_video_stream;
+typedef struct mddi_register_access mddi_register_access;
+typedef struct mddi_client_caps mddi_client_caps;
+
+typedef struct mddi_llentry mddi_llentry;
+
+struct __attribute__((packed)) mddi_video_stream 
+{
+    unsigned short length;      /* length in bytes excluding this field */
+    unsigned short type;        /* MDDI_TYPE_VIDEO_STREAM */
+    unsigned short client_id;   /* set to zero */
+    
+    unsigned short format;
+    unsigned short pixattr;
+
+    unsigned short left;
+    unsigned short top;
+    unsigned short right;
+    unsigned short bottom;
+
+    unsigned short start_x;
+    unsigned short start_y;
+
+    unsigned short pixels;
+
+    unsigned short crc;
+    unsigned short reserved;
+};
+
+struct __attribute__((packed)) mddi_register_access
+{
+    unsigned short length;
+    unsigned short type;
+    unsigned short client_id;
+
+    unsigned short rw_info;    /* flag below | count of reg_data */
+#define MDDI_WRITE     (0 << 14)
+#define MDDI_READ      (2 << 14)
+#define MDDI_READ_RESP (3 << 14)
+    
+    unsigned reg_addr;
+    unsigned short crc;        /* 16 bit crc of the above */
+
+    unsigned reg_data;         /* "list" of 3byte data values */
+};
+
+struct __attribute__((packed)) mddi_llentry {
+    unsigned short flags;
+    unsigned short header_count;
+    unsigned short data_count;
+    void *data;
+    mddi_llentry *next;
+    unsigned short reserved;
+    union {
+        mddi_video_stream v;
+        mddi_register_access r;
+        unsigned _[12];
+    } u;
+};
+
+struct __attribute__((packed)) mddi_client_caps 
+{
+    unsigned short length;
+    unsigned short type;
+    unsigned short client_id;
+
+    unsigned short protocol_ver;
+    unsigned short min_protocol_ver;
+    unsigned short data_rate_cap;
+    unsigned char interface_type_cap;
+    unsigned char num_alt_displays;
+    unsigned short postcal_data_rate;
+    unsigned short bitmap_width;
+    unsigned short bitmap_height;
+    unsigned short display_window_width;
+    unsigned short display_window_height;
+    unsigned cmap_size;
+    unsigned short cmap_rgb_width;
+    unsigned short rgb_cap;
+    unsigned char mono_cap;
+    unsigned char reserved1;
+    unsigned short ycbcr_cap;
+    unsigned short bayer_cap;
+    unsigned short alpha_cursor_planes;
+    unsigned client_feature_cap;
+    unsigned char max_video_frame_rate_cap;
+    unsigned char min_video_frame_rate_cap;
+    unsigned short min_sub_frame_rate;
+    unsigned short audio_buf_depth;
+    unsigned short audio_channel_cap;
+    unsigned short audio_sampe_rate_rap;
+    unsigned char audio_sample_res;
+    unsigned char mic_audio_sample_res;
+    unsigned short mic_sample_rate_cap;
+    unsigned char keyboard_data_fmt;
+    unsigned char pointing_device_data_fmt;
+    unsigned short content_protection_type;
+    unsigned short manufacturer_name;
+    unsigned short product_code;
+    unsigned short reserved3;
+    unsigned serial_no;
+    unsigned char week_of_manufacture;
+    unsigned char year_of_manufacture;
+
+    unsigned short crc;    
+};
+
+#endif
diff --git a/include/msm7k/mdp.h b/include/msm7k/mdp.h
new file mode 100644
index 0000000..11f05e8
--- /dev/null
+++ b/include/msm7k/mdp.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_MDP_H
+#define __ASM_ARCH_MSM7200_MDP_H
+
+#define MSM_MDP_BASE1 0xAA200000
+#define MSM_MDP_BASE2 0xAA210100
+
+/* see 80-VA736-2 C pp 587-627 */
+
+#define MDP_REG1(off) (MSM_MDP_BASE1 + (off))
+#define MDP_REG(off) (MSM_MDP_BASE2 + (off))
+
+
+#define MDP_SYNC_CONFIG_0       MDP_REG1(0x0000)
+#define MDP_SYNC_CONFIG_1       MDP_REG1(0x0004)
+#define MDP_SYNC_CONFIG_2       MDP_REG1(0x0008)
+#define MDP_SYNC_VSYNC_EN       (1 << 17)
+#define MDP_SYNC_SYNC_EN        (1 << 16)
+#define MDP_SYNC_DIV_CNT(n)     ((n) & 0xffff)
+
+#define MDP_SYNC_STATUS_0       MDP_REG1(0x000C)
+#define MDP_SYNC_STATUS_1       MDP_REG1(0x0010)
+#define MDP_SYNC_STATUS_2       MDP_REG1(0x0014)
+#define MDP_SYNC_FRAME_COUNT(n) (((n) >> 16) & 0xfff)
+#define MDP_SYNC_LINE_COUNT(n)  ((n) & 0x3ff)
+
+#define MDP_SYNC_THRESH_0       MDP_REG1(0x0018)
+#define MDP_SYNC_SEC_ABOVE(n)   (((n) & 0xFF) << 24)
+#define MDP_SYNC_SEC_BELOW(n)   (((n) & 0xFF) << 16)
+#define MDP_SYNC_PRIM_ABOVE(n)  (((n) & 0xFF) << 8)
+#define MDP_SYNC_PRIM_BELOW(n)  ((n) & 0xFF)
+
+#define MDP_SYNC_THRESH_1       MDP_REG1(0x001C)
+#define MDP_SYNC_EXT_ABOVE(n)   (((n) & 0xFF) << 8)
+#define MDP_SYNC_EXT_BELOW(n)   ((n) & 0xFF)
+
+#define MDP_INTR_ENABLE         MDP_REG1(0x0020)
+#define MDP_INTR_STATUS         MDP_REG1(0x0024)
+#define MDP_INTR_CLEAR          MDP_REG1(0x0028)
+#define MDP_INTR_LIST0_DONE     (1 << 0)
+#define MDP_INTR_LIST1_DONE     (1 << 1)
+#define MDP_INTR_DMA_DONE       (1 << 2)
+#define MDP_INTR_TV_DONE        (1 << 3)
+#define MDP_INTR_CONFIG_ERR     (1 << 4)
+#define MDP_INTR_ROI_ERR        (1 << 5)
+#define MDP_INTR_TV_UNDERRUN    (1 << 6)
+
+#define MDP_HW_VERSION          MDP_REG1(0x0070)
+
+
+#define MDP_EDGE_CONFIG         MDP_REG(0x0000)
+#define MDP_TILE_CONFIG         MDP_REG(0x0004)
+
+/* BLT controls */
+#define MDP_SRC_ROI             MDP_REG(0x0008)
+#define MDP_SRCP0_ADDR          MDP_REG(0x000C)
+#define MDP_SRCP1_ADDR          MDP_REG(0x0010)
+#define MDP_SRCP2_ADDR          MDP_REG(0x0014)
+#define MDP_SRCP3_ADDR          MDP_REG(0x0018)
+#define MDP_SRCP01_STRIDE       MDP_REG(0x001C)
+#define MDP_SRCP23_STRIDE       MDP_REG(0x0020)
+#define MDP_SRC_CONFIG          MDP_REG(0x0024)
+#define MDP_UNPACK_PATTERN0     MDP_REG(0x0028)
+#define MDP_UNPACK_PATTERN1     MDP_REG(0x002C)
+#define MDP_UNPACK_PATTERN2     MDP_REG(0x0030)
+#define MDP_UNPACK_PATTERN3     MDP_REG(0x0034)
+#define MDP_PPP_CONFIG          MDP_REG(0x0038)
+#define MDP_PHASEX_INIT         MDP_REG(0x003C)
+#define MDP_PHASEY_INIT         MDP_REG(0x0040)
+#define MDP_PHASEX_STEP         MDP_REG(0x0044)
+#define MDP_PHASEY_STEP         MDP_REG(0x0048)
+#define MDP_ALPHA_CONFIG        MDP_REG(0x004C)
+#define MDP_DST_CONFIG          MDP_REG(0x0050)
+#define MDP_PACK_PATTERN0       MDP_REG(0x0054)
+#define MDP_PACK_PATTERN1       MDP_REG(0x0058)
+#define MDP_PACK_PATTERN2       MDP_REG(0x005C)
+#define MDP_PACK_PATTERN3       MDP_REG(0x0060)
+#define MDP_DST_ROI             MDP_REG(0x0064)
+#define MDP_DSTP0_ADDR          MDP_REG(0x0068)
+#define MDP_DSTP1_ADDR          MDP_REG(0x006C)
+#define MDP_DSTP2_ADDR          MDP_REG(0x0070)
+#define MDP_DSTP3_ADDR          MDP_REG(0x0074)
+#define MDP_DSTP01_STRIDE       MDP_REG(0x0078)
+#define MDP_DSTP23_STRIDE       MDP_REG(0x007C)
+
+#endif
diff --git a/include/msm7k/nand.h b/include/msm7k/nand.h
new file mode 100644
index 0000000..12f2f9a
--- /dev/null
+++ b/include/msm7k/nand.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_NAND_H
+#define __ASM_ARCH_MSM7200_NAND_H
+
+#define MSM_NAND_BASE 0xA0A00000
+
+/* see 80-VA736-2 C pp 354-414 */
+
+#define NAND_REG(off) (MSM_NAND_BASE + (off))
+
+#define NAND_FLASH_CMD            NAND_REG(0x0000)
+#define NAND_ADDR0                NAND_REG(0x0004)
+#define NAND_ADDR1                NAND_REG(0x0008)
+#define NAND_FLASH_CHIP_SELECT    NAND_REG(0x000C)
+#define NAND_EXEC_CMD             NAND_REG(0x0010)
+#define NAND_FLASH_STATUS         NAND_REG(0x0014)
+#define NAND_BUFFER_STATUS        NAND_REG(0x0018)
+#define NAND_DEV0_CFG0            NAND_REG(0x0020)
+#define NAND_DEV0_CFG1            NAND_REG(0x0024)
+#define NAND_DEV1_CFG0            NAND_REG(0x0030)
+#define NAND_DEV1_CFG1            NAND_REG(0x0034)
+#define NAND_READ_ID              NAND_REG(0x0040)
+#define NAND_READ_STATUS          NAND_REG(0x0044)
+#define NAND_CONFIG_DATA          NAND_REG(0x0050)
+#define NAND_CONFIG               NAND_REG(0x0054)
+#define NAND_CONFIG_MODE          NAND_REG(0x0058)
+#define NAND_CONFIG_STATUS        NAND_REG(0x0060)
+#define NAND_MACRO1_REG           NAND_REG(0x0064)
+#define NAND_XFR_STEP1            NAND_REG(0x0070)
+#define NAND_XFR_STEP2            NAND_REG(0x0074)
+#define NAND_XFR_STEP3            NAND_REG(0x0078)
+#define NAND_XFR_STEP4            NAND_REG(0x007C)
+#define NAND_XFR_STEP5            NAND_REG(0x0080)
+#define NAND_XFR_STEP6            NAND_REG(0x0084)
+#define NAND_XFR_STEP7            NAND_REG(0x0088)
+#define NAND_DEV_CMD0             NAND_REG(0x00A0)
+#define NAND_DEV_CMD1             NAND_REG(0x00A4)
+#define NAND_DEV_CMD2             NAND_REG(0x00A8)
+#define NAND_DEV_CMD_VLD          NAND_REG(0x00AC)
+#define NAND_EBI2_MISR_SIG_REG    NAND_REG(0x00B0)
+#define NAND_EBI2_ECC_BUF_CFG     NAND_REG(0x00F0)
+#define NAND_FLASH_BUFFER         NAND_REG(0x0100)
+
+/* device commands */
+
+#define NAND_CMD_SOFT_RESET         0x01
+#define NAND_CMD_PAGE_READ          0x32
+#define NAND_CMD_PAGE_READ_ECC      0x33
+#define NAND_CMD_PAGE_READ_ALL      0x34
+#define NAND_CMD_SEQ_PAGE_READ      0x15
+#define NAND_CMD_PRG_PAGE           0x36
+#define NAND_CMD_PRG_PAGE_ECC       0x37
+#define NAND_CMD_PRG_PAGE_ALL       0x39
+#define NAND_CMD_BLOCK_ERASE        0x3A
+#define NAND_CMD_FETCH_ID           0x0B
+#define NAND_CMD_STATUS             0x0C
+#define NAND_CMD_RESET              0x0D
+
+#endif
diff --git a/include/msm7k/shared.h b/include/msm7k/shared.h
new file mode 100644
index 0000000..b81732b
--- /dev/null
+++ b/include/msm7k/shared.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MSM7K_SHARED_H
+#define MSM7K_SHARED_H
+
+#define MSM7K_SHARED_PHYS  0x01F00000
+
+#define MSM7K_VERSION (MSM7K_SHARED_PHYS + 0x40)
+
+#define VERSION_QDSP6     4
+#define VERSION_APPS_SBL  6
+#define VERSION_MODEM_SBL 7
+#define VERSION_APPS      8
+#define VERSION_MODEM     9
+
+void get_version_modem(char *s);
+void get_version_modem_sbl(char *s);
+
+
+#define ACPU_CLK           0  /* Applications processor clock */
+#define ADM_CLK            1  /* Applications data mover clock */
+#define ADSP_CLK           2  /* ADSP clock */
+#define EBI1_CLK           3  /* External bus interface 1 clock */
+#define EBI2_CLK           4  /* External bus interface 2 clock */
+#define ECODEC_CLK         5  /* External CODEC clock */
+#define EMDH_CLK           6  /* External MDDI host clock */
+#define GP_CLK             7  /* General purpose clock */
+#define GRP_CLK            8  /* Graphics clock */
+#define I2C_CLK            9  /* I2C clock */
+#define ICODEC_RX_CLK     10  /* Internal CODEX RX clock */
+#define ICODEC_TX_CLK     11  /* Internal CODEX TX clock */
+#define IMEM_CLK          12  /* Internal graphics memory clock */
+#define MDC_CLK           13  /* MDDI client clock */
+#define MDP_CLK           14  /* Mobile display processor clock */
+#define PBUS_CLK          15  /* Peripheral bus clock */
+#define PCM_CLK           16  /* PCM clock */
+#define PMDH_CLK          17  /* Primary MDDI host clock */
+#define SDAC_CLK          18  /* Stereo DAC clock */
+#define SDC1_CLK          19  /* Secure Digital Card clocks */
+#define SDC1_PCLK         20
+#define SDC2_CLK          21
+#define SDC2_PCLK         22
+#define SDC3_CLK          23 
+#define SDC3_PCLK         24 
+#define SDC4_CLK          25
+#define SDC4_PCLK         26
+#define TSIF_CLK          27  /* Transport Stream Interface clocks */
+#define TSIF_REF_CLK      28
+#define TV_DAC_CLK        29  /* TV clocks */
+#define TV_ENC_CLK        30
+#define UART1_CLK         31  /* UART clocks */
+#define UART2_CLK         32
+#define UART3_CLK         33
+#define UART1DM_CLK       34
+#define UART2DM_CLK       35
+#define USB_HS_CLK        36  /* High speed USB core clock */
+#define USB_HS_PCLK       37  /* High speed USB pbus clock */
+#define USB_OTG_CLK       38  /* Full speed USB clock */
+#define VDC_CLK           39  /* Video controller clock */
+#define VFE_CLK           40  /* Camera / Video Front End clock */
+#define VFE_MDC_CLK       41  /* VFE MDDI client clock */
+
+enum 
+{
+    VREG_MSMA_ID,
+    VREG_MSMP_ID,
+    VREG_MSME1_ID, /* Not supported in Panoramix */
+    VREG_MSMC1_ID, /* Not supported in PM6620 */
+    VREG_MSMC2_ID, /* Supported in PM7500 only */
+    VREG_GP3_ID, /* Supported in PM7500 only */   
+    VREG_MSME2_ID, /* Supported in PM7500 and Panoramix only */
+    VREG_GP4_ID, /* Supported in PM7500 only */
+    VREG_GP1_ID, /* Supported in PM7500 only */
+    VREG_TCXO_ID,
+    VREG_PA_ID,
+    VREG_RFTX_ID,
+    VREG_RFRX1_ID,
+    VREG_RFRX2_ID,
+    VREG_SYNT_ID,
+    VREG_WLAN_ID,
+    VREG_USB_ID,
+    VREG_BOOST_ID,
+    VREG_MMC_ID,
+    VREG_RUIM_ID,
+    VREG_MSMC0_ID, /* Supported in PM6610 only */
+    VREG_GP2_ID, /* Supported in PM7500 only */
+    VREG_GP5_ID, /* Supported in PM7500 only */
+    VREG_GP6_ID, /* Supported in PM7500 only */
+    VREG_RF_ID,
+    VREG_RF_VCO_ID,
+    VREG_MPLL_ID,
+    VREG_S2_ID,
+    VREG_S3_ID,
+    VREG_RFUBM_ID,
+    VREG_NCP_ID, 
+};
+
+int clock_enable(unsigned id);
+int clock_disable(unsigned id);
+int clock_set_rate(unsigned id, unsigned hz);
+int clock_get_rate(unsigned id);
+
+int vreg_enable(unsigned id);
+int vreg_disable(unsigned id);
+int vreg_set_level(unsigned id, unsigned mv);
+
+void reboot(void);
+
+#endif
diff --git a/include/msm7k/uart.h b/include/msm7k/uart.h
new file mode 100644
index 0000000..cbcd960
--- /dev/null
+++ b/include/msm7k/uart.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_UART_H
+#define __ASM_ARCH_MSM7200_UART_H
+
+#define MSM_UART1_BASE 0xA9A00000
+#define MSM_UART2_BASE 0xA9B00000
+#define MSM_UART3_BASE 0xA9C00000
+
+#define UART_MR1         0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0(n) (((n) & 0x3f) << 8)
+#define UART_MR1_RX_RDY_CTL    (1 << 7)
+#define UART_MR1_CTS_CTL       (1 << 6)
+#define UART_MR1_AUTO_RFR_LEVEL1(n) ((n) & 0x3f)
+
+#define UART_MR2         0x0004
+#define UART_MR2_ERROR_MODE        (1 << 6)
+#define UART_MR2_BITS_PER_CHAR_5   (0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6   (1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7   (2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8   (3 << 4)
+#define UART_MR2_STOP_BIT_LEN_0563 (0 << 2)
+#define UART_MR2_STOP_BIT_LEN_1000 (1 << 2)
+#define UART_MR2_STOP_BIT_LEN_1563 (2 << 2)
+#define UART_MR2_STOP_BIT_LEN_2000 (3 << 2)
+#define UART_MR2_PARITY_MODE_NONE  (0)
+#define UART_MR2_PARITY_MODE_ODD   (1)
+#define UART_MR2_PARITY_MODE_EVEN  (2)
+#define UART_MR2_PARITY_MODE_SPACE (3)
+
+#define UART_CSR         0x0008
+#define UART_CSR_115200  0xFF
+#define UART_CSR_57600   0xEE
+#define UART_CSR_38400   0xDD
+#define UART_CSR_19200   0xBB
+
+#define UART_TF          0x000C
+
+#define UART_CR          0x0010
+#define UART_CR_CMD_NULL           (0 << 4)
+#define UART_CR_CMD_RESET_RX       (1 << 4)
+#define UART_CR_CMD_RESET_TX       (2 << 4)
+#define UART_CR_CMD_RESET_ERR      (3 << 4)
+#define UART_CR_CMD_RESET_BCI      (4 << 4)
+#define UART_CR_CMD_START_BREAK    (5 << 4)
+#define UART_CR_CMD_STOP_BREAK     (6 << 4)
+#define UART_CR_CMD_RESET_CTS_N    (7 << 4)
+#define UART_CR_CMD_PACKET_MODE    (9 << 4)
+#define UART_CR_CMD_MODE_RESET     (12<< 4)
+#define UART_CR_CMD_SET_RFR_N      (13<< 4)
+#define UART_CR_CMD_RESET_RFR_ND   (14<< 4)
+#define UART_CR_TX_DISABLE         (1 << 3)
+#define UART_CR_TX_ENABLE          (1 << 3)
+#define UART_CR_RX_DISABLE         (1 << 3)
+#define UART_CR_RX_ENABLE          (1 << 3)
+
+#define UART_IMR         0x0014
+#define UART_IMR_RXLEV (1 << 4)
+#define UART_IMR_TXLEV (1 << 0)
+
+#define UART_IPR         0x0018
+#define UART_TFWR        0x001C
+#define UART_RFWR        0x0020
+#define UART_HCR         0x0024
+
+#define UART_MREG        0x0028
+#define UART_NREG        0x002C
+#define UART_DREG        0x0030
+#define UART_MNDREG      0x0034
+#define UART_IRDA        0x0038
+#define UART_MISR_MODE   0x0040
+#define UART_MISR_RESET  0x0044
+#define UART_MISR_EXPORT 0x0048
+#define UART_MISR_VAL    0x004C
+#define UART_TEST_CTRL   0x0050
+
+#define UART_SR          0x0008
+#define UART_SR_HUNT_CHAR      (1 << 7)
+#define UART_SR_RX_BREAK       (1 << 6)
+#define UART_SR_PAR_FRAME_ERR  (1 << 5)
+#define UART_SR_OVERRUN        (1 << 4)
+#define UART_SR_TX_EMPTY       (1 << 3)
+#define UART_SR_TX_READY       (1 << 2)
+#define UART_SR_RX_FULL        (1 << 1)
+#define UART_SR_RX_READY       (1 << 0)
+
+#define UART_RF          0x000C
+#define UART_MISR        0x0010
+#define UART_ISR         0x0014
+
+
+#endif
diff --git a/include/msm7k/vic.h b/include/msm7k/vic.h
new file mode 100644
index 0000000..46f3adf
--- /dev/null
+++ b/include/msm7k/vic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __ASM_ARCH_MSM7200_VIC_H
+#define __ASM_ARCH_MSM7200_VIC_H
+
+#define MSM_VIC_BASE 0xC0000000
+
+#define VIC_REG(off) (MSM_VIC_BASE + (off))
+
+/* See 80-VE113-1 A, pp 218-228 */
+
+#define VIC_IRQ_STATUS0     VIC_REG(0x0000)
+#define VIC_IRQ_STATUS1     VIC_REG(0x0004)
+#define VIC_FIQ_STATUS0     VIC_REG(0x0008)
+#define VIC_FIQ_STATUS1     VIC_REG(0x000C)
+#define VIC_RAW_STATUS0     VIC_REG(0x0010)
+#define VIC_RAW_STATUS1     VIC_REG(0x0014)
+#define VIC_INT_CLEAR0      VIC_REG(0x0018)
+#define VIC_INT_CLEAR1      VIC_REG(0x001C)
+#define VIC_INT_SELECT0     VIC_REG(0x0020)  /* 1: FIQ, 0: IRQ */
+#define VIC_INT_SELECT1     VIC_REG(0x0024)  /* 1: FIQ, 0: IRQ */
+#define VIC_INT_EN0         VIC_REG(0x0028)
+#define VIC_INT_EN1         VIC_REG(0x002C)
+#define VIC_INT_ENCLEAR0    VIC_REG(0x0040)
+#define VIC_INT_ENCLEAR1    VIC_REG(0x0044)
+#define VIC_SOFTINT0        VIC_REG(0x0050)
+#define VIC_SOFTINT1        VIC_REG(0x0054)
+#define VIC_INT_MASTEREN    VIC_REG(0x0060)  /* 1: IRQ, 2: FIQ     */
+#define VIC_PROTECTION      VIC_REG(0x0064)  /* 1: ENABLE          */
+#define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
+#define VIC_INT_TYPE0       VIC_REG(0x0070)  /* 1: EDGE, 0: LEVEL  */
+#define VIC_INT_TYPE1       VIC_REG(0x0074)  /* 1: EDGE, 0: LEVEL  */
+#define VIC_IRQ_VEC_RD      VIC_REG(0x0F00)  /* pending int # */
+#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x0F20)  /* pending vector addr */
+
+#define VIC_VECTADDR(n)     VIC_REG(0x0100+((n) * 4))
+#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
+
+#endif
diff --git a/libboot/Android.mk b/libboot/Android.mk
new file mode 100644
index 0000000..d2085f3
--- /dev/null
+++ b/libboot/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := \
+	flash.c \
+	poll.c \
+	tags_partition.c \
+	tags_revision.c \
+	tags_serialno.c \
+	tags_cmdline.c \
+	gpio_keypad.c \
+	init.c \
+	tags.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader)
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+
+LOCAL_MODULE := libboot
+
+include $(BUILD_RAW_STATIC_LIBRARY)
diff --git a/libboot/flash.c b/libboot/flash.c
new file mode 100644
index 0000000..f1503dc
--- /dev/null
+++ b/libboot/flash.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/flash.h>
+
+#define MAX_PTN 16
+
+static ptentry ptable[MAX_PTN];
+static unsigned pcount = 0;
+
+void flash_add_ptn(ptentry *ptn)
+{
+    if(pcount < MAX_PTN){
+        memcpy(ptable + pcount, ptn, sizeof(*ptn));
+        pcount++;
+    }
+}
+
+void flash_dump_ptn(void)
+{
+    unsigned n;
+    for(n = 0; n < pcount; n++) {
+        ptentry *ptn = ptable + n;
+        dprintf("ptn %d name='%s' start=%d len=%d\n",
+                n, ptn->name, ptn->start, ptn->length);
+    }
+}
+
+
+ptentry *flash_find_ptn(const char *name)
+{
+    unsigned n;
+    for(n = 0; n < pcount; n++) {
+        if(!strcmp(ptable[n].name, name)) {
+            return ptable + n;
+        }
+    }
+    return 0;
+}
+
+ptentry *flash_get_ptn(unsigned n)
+{
+    if(n < pcount) {
+        return ptable + n;
+    } else {
+        return 0;
+    }
+}
+
+unsigned flash_get_ptn_count(void)
+{
+    return pcount;
+}
diff --git a/libboot/gpio_keypad.c b/libboot/gpio_keypad.c
new file mode 100644
index 0000000..b1ec7c2
--- /dev/null
+++ b/libboot/gpio_keypad.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/gpio.h>
+#include <boot/gpio_keypad.h>
+
+int gpio_keypad_init(gpio_keypad_info *keypad)
+{
+	unsigned i;
+	for(i = 0; i < keypad->noutputs; i++) {
+		gpio_set(keypad->output_gpios[i], keypad->polarity ^ keypad->drive_inactive_outputs);
+		gpio_dir(keypad->output_gpios[i], keypad->drive_inactive_outputs);
+	}
+	for(i = 0; i < keypad->ninputs; i++) {
+		gpio_dir(keypad->input_gpios[i], 0);
+	}
+	keypad->state = 0;
+	return 0;
+}
+
+void gpio_keypad_scan_keys(gpio_keypad_info *keypad)
+{
+	unsigned out, in;
+	unsigned long long keys;
+	unsigned npolarity = !keypad->polarity;
+	unsigned int shift;
+
+	keys = 0;
+	out = keypad->noutputs;
+	shift = keypad->noutputs * keypad->ninputs;
+	while(out > 0) {
+		out--;
+		if(keypad->drive_inactive_outputs)
+			gpio_set(keypad->output_gpios[out], !npolarity);
+		else	
+			gpio_dir(keypad->output_gpios[out], 1);
+		udelay(keypad->settle_time);
+		in = keypad->ninputs;
+		while(in > 0) {
+			in--;
+			shift--;
+			keys = (keys << 1) | (gpio_get(keypad->input_gpios[in]) ^ npolarity);
+			if(((unsigned)(keypad->state >> shift) ^ (unsigned)keys) & 1) {
+				unsigned int mapped_key = 0;
+				if(keypad->key_map)
+					mapped_key = keypad->key_map[shift];
+				//dprintf("gpio_keypad_scan_keys: %d-%d (%d-%d) %d (%d): %d\n", out, in,
+				//        keypad->output_gpios[out], keypad->input_gpios[in],
+				//        shift, mapped_key, keys & 1);
+				if(mapped_key && key_changed)
+					key_changed(mapped_key, keys & 1);
+			}
+		}
+		if(keypad->drive_inactive_outputs)
+			gpio_set(keypad->output_gpios[out], npolarity);
+		else	
+			gpio_dir(keypad->output_gpios[out], 0);
+	}
+	if(keys != keypad->state) {
+		keypad->state = keys;
+		//dprintf("gpio_keypad_scan_keys: %x %x\n", (unsigned long)(keys >> 32), (unsigned long)keys);
+	}
+}
+
diff --git a/libboot/init.c b/libboot/init.c
new file mode 100644
index 0000000..3223dda
--- /dev/null
+++ b/libboot/init.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+char data[3];
+
+extern unsigned BOOTLOADER_INIT_FIRST;
+extern unsigned BOOTLOADER_INIT_LAST;
+
+void call_init_hooks()
+{
+	unsigned x;
+	for(x = BOOTLOADER_INIT_FIRST; x < BOOTLOADER_INIT_LAST; x += 4) {
+		int (*hook)(void) = (void*) x;
+		hook();
+	}
+}
diff --git a/libboot/poll.c b/libboot/poll.c
new file mode 100644
index 0000000..4b87140
--- /dev/null
+++ b/libboot/poll.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+
+#define MAX_POLL_FUNCS 16
+
+typedef void (*poll_func)(void);
+
+static poll_func poll_funcs[MAX_POLL_FUNCS];
+static unsigned poll_count = 0;
+
+void boot_register_poll_func(void (*func)(void))
+{
+    if(poll_count < MAX_POLL_FUNCS) {
+        poll_funcs[poll_count++] = func;
+    }
+}
+
+void boot_poll(void)
+{
+    unsigned n;
+    for(n = 0; n < poll_count; n++) {
+        poll_funcs[n]();
+    }
+}
diff --git a/libboot/tags.c b/libboot/tags.c
new file mode 100644
index 0000000..3fbf23b
--- /dev/null
+++ b/libboot/tags.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/tags.h>
+
+#define DBG(x...) do{}while(0)
+//#define DBG(x...) dprintf(x)
+
+void tags_parse(void *_tags, struct tag_handler *handlers, unsigned count)
+{
+    unsigned n;
+    unsigned *tags = _tags;
+    
+    DBG("tags_parse %p\n", tags);
+     
+        /* make sure there's a CORE marker first */
+    if(tags[0] != 2) return;
+    if(tags[1] != 0x54410001) return;
+
+    for(;;) {
+        unsigned size = tags[0];
+        unsigned type = tags[1];
+        
+        DBG("tags_parse %x %x\n", size, type);
+        
+        if(size < 2) break;
+        
+        for(n = 0; n < count; n++) {
+            struct tag_handler *h = handlers + n;
+            if((h->type == type) || (h->type == 0)) {
+                h->func(type, (void*) &tags[2], (size - 2) * 4, h->cookie);
+                break;
+            }
+        }
+
+        tags += size;
+    }
+}
+
diff --git a/libboot/tags_cmdline.c b/libboot/tags_cmdline.c
new file mode 100644
index 0000000..4496e53
--- /dev/null
+++ b/libboot/tags_cmdline.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/tags.h>
+#include <boot/flash.h>
+
+static void tag_cmdline(unsigned tag, void *data, unsigned bytes, void *cookie)
+{
+    *((const char **) cookie) = data;
+}
+
+const char *tags_get_cmdline(void *tags)
+{
+    const char *cmdline = "";
+    struct tag_handler h;
+
+    h.type = 0x54410009;
+    h.func = tag_cmdline;
+    h.cookie = &cmdline;
+    
+    tags_parse(tags, &h, 1);
+
+    return cmdline;
+}
diff --git a/libboot/tags_partition.c b/libboot/tags_partition.c
new file mode 100644
index 0000000..5881a48
--- /dev/null
+++ b/libboot/tags_partition.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/tags.h>
+#include <boot/flash.h>
+
+static void ptn_importer(unsigned tag, void *data, unsigned bytes, void *cookie)
+{
+    struct ptentry *ptn = data;
+    unsigned n = 0;
+    
+    while(bytes >= sizeof(*ptn)) {
+        flash_add_ptn(ptn);
+        ptn++;
+        n++;
+        bytes -= sizeof(*ptn);
+    }       
+}
+
+static struct tag_handler ptn_handler = {
+    .type = 0x4d534d70,
+    .func = ptn_importer,
+};
+    
+void tags_import_partitions(void *tags)
+{
+    tags_parse(tags, &ptn_handler, 1);
+}
diff --git a/libboot/tags_revision.c b/libboot/tags_revision.c
new file mode 100644
index 0000000..d4eeb40
--- /dev/null
+++ b/libboot/tags_revision.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/tags.h>
+#include <boot/flash.h>
+
+static void tag_revision(unsigned tag, void *data, unsigned bytes, void *cookie)
+{
+    if(bytes == 4) {
+        memcpy(cookie, data, 4);
+    }
+}
+
+unsigned tags_get_revision(void *tags)
+{
+    unsigned n = 0;
+    struct tag_handler h;
+
+    h.type = 0x54410007;
+    h.func = tag_revision;
+    h.cookie = &n;
+    
+    tags_parse(tags, &h, 1);
+
+    return n;
+}
diff --git a/libboot/tags_serialno.c b/libboot/tags_serialno.c
new file mode 100644
index 0000000..a647c21
--- /dev/null
+++ b/libboot/tags_serialno.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/tags.h>
+#include <boot/flash.h>
+
+static void tag_serialno(unsigned tag, void *data, unsigned bytes, void *cookie)
+{
+    if(bytes == 8) {
+        memcpy(cookie, data, 8);
+    }
+}
+
+void tags_get_serialno(void *tags, void *sn)
+{
+    struct tag_handler h;
+
+    h.type = 0x54410006;
+    h.func = tag_serialno;
+    h.cookie = sn;
+    
+    tags_parse(tags, &h, 1);
+}
diff --git a/libc/Android.mk b/libc/Android.mk
new file mode 100644
index 0000000..570bd6e
--- /dev/null
+++ b/libc/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := \
+	dprintf.c \
+	xprintf.c \
+	cprintf.c \
+	sprintf.c \
+	malloc.c \
+	memcmp.c \
+	memcpy.c \
+	memset.c \
+	strcpy.c \
+	strlen.c \
+	strcmp.c \
+	strstr.c \
+	crypto.c \
+	rsa.c \
+	sha.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader)
+LOCAL_C_INCLUDES += include/mincrypt
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+
+LOCAL_MODULE := libboot_c
+
+include $(BUILD_RAW_STATIC_LIBRARY)
diff --git a/libc/cprintf.c b/libc/cprintf.c
new file mode 100644
index 0000000..3f3425b
--- /dev/null
+++ b/libc/cprintf.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include <boot/boot.h>
+#include "libc_private.h"
+
+void cprintf(const char *fmt, ...)
+{
+    va_list ap;
+    
+    va_start(ap, fmt);
+    __xprintf(fmt, ap, (void*) console_putc, 0);
+    va_end(ap);
+
+    console_flush();
+}
diff --git a/libc/crypto.c b/libc/crypto.c
new file mode 100644
index 0000000..7c3f96c
--- /dev/null
+++ b/libc/crypto.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include "sha.h"
+#include "rsa.h"
+
+void compute_digest(void *data, unsigned dlen, void *digest_out)
+{
+    uint8_t *digest = digest_out;
+    SHA(data, dlen, digest);
+}
+
+int is_signature_okay(void *digest, void *signature, void *pubkey)
+{
+    return RSA_verify(pubkey, signature, SIGNATURE_SIZE, digest);
+}
diff --git a/libc/dprintf.c b/libc/dprintf.c
new file mode 100644
index 0000000..f54d24b
--- /dev/null
+++ b/libc/dprintf.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include <boot/boot.h>
+#include "libc_private.h"
+
+static void do_nothing(void)
+{
+}
+
+static void (*dputc)(unsigned) = (void *) do_nothing;
+static void (*dflush)(void) = (void *) do_nothing;
+
+void dprintf_set_putc(void (*func)(unsigned))
+{
+    dputc = func;
+}
+void dprintf_set_flush(void (*func)(void))
+{
+    dflush = func;
+}
+
+void dprintf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    __xprintf(fmt, ap, (void*) dputc, 0);
+    va_end(ap);
+}
diff --git a/libc/inttypes.h b/libc/inttypes.h
new file mode 100644
index 0000000..e6a22e3
--- /dev/null
+++ b/libc/inttypes.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _INTTYPES_H_
+#define _INTTYPES_H_
+
+typedef unsigned long long uint64_t;
+typedef unsigned long uint32_t;
+typedef unsigned char uint8_t;
+typedef long long int64_t;
+
+#endif
diff --git a/libc/libc_private.h b/libc/libc_private.h
new file mode 100644
index 0000000..58fa4b9
--- /dev/null
+++ b/libc/libc_private.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBC_PRIVATE_H_
+#define _LIBC_PRIVATE_H_
+
+void __xprintf(const char *fmt, va_list ap,
+               void (*xputc)(unsigned n, void *cookie),
+               void *cookie);
+
+#endif
diff --git a/libc/malloc.c b/libc/malloc.c
new file mode 100644
index 0000000..0d2880a
--- /dev/null
+++ b/libc/malloc.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern unsigned BOOTLOADER_HEAP;
+
+static unsigned __alloc_next = (unsigned) &BOOTLOADER_HEAP;
+    
+void *alloc(unsigned sz)
+{
+    void *ptr;
+    
+    ptr = (void*) __alloc_next;
+    __alloc_next = (__alloc_next + sz + 31) & (~31);
+
+    return ptr;
+}
+
+void *alloc_page_aligned(unsigned sz)
+{
+    __alloc_next = (__alloc_next + 4095) & (~4095);
+    
+    return alloc(sz);
+}
+
+void func(unsigned n)
+{
+    __alloc_next *= n;
+    __alloc_next *= n;
+}
diff --git a/libc/memcmp.c b/libc/memcmp.c
new file mode 100644
index 0000000..e1f83c3
--- /dev/null
+++ b/libc/memcmp.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+int memcmp(void *_a, void *_b, unsigned len)
+{
+    char *a = _a;
+    char *b = _b;
+
+    while(len-- > 0) {
+        if(*a++ != *b++) return 1;
+    }
+    return 0;
+}
diff --git a/libc/memcpy.c b/libc/memcpy.c
new file mode 100644
index 0000000..9144dae
--- /dev/null
+++ b/libc/memcpy.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void *memcpy(void *_dst, const void *_src, unsigned len)
+{
+	unsigned char *dst = _dst;
+	const unsigned char *src = _src;
+	while(len-- > 0) {
+		*dst++ = *src++;
+	}
+	return _dst;
+}
diff --git a/libc/memset.c b/libc/memset.c
new file mode 100644
index 0000000..6886df9
--- /dev/null
+++ b/libc/memset.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void *memset(void *_p, unsigned v, unsigned count)
+{
+    unsigned char *p = _p;
+    while(count-- > 0) *p++ = 0;
+    return _p;
+}
diff --git a/libc/rsa.c b/libc/rsa.c
new file mode 100644
index 0000000..2aea562
--- /dev/null
+++ b/libc/rsa.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "rsa.h"
+#include "sha.h"
+
+/* a[] -= mod */
+static void subM(RSAPublicKey *key, uint32_t *a) {
+    int64_t A = 0;
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        A += (uint64_t)a[i] - key->n[i];
+        a[i] = (uint32_t)A;
+        A >>= 32;
+    }
+}
+
+/* return a[] >= mod */
+static int geM(RSAPublicKey *key, const uint32_t *a) {
+    int i;
+    for (i = key->len; i;) {
+        --i;
+        if (a[i] < key->n[i]) return 0;
+        if (a[i] > key->n[i]) return 1;
+    }
+    return 1;  /* equal */
+}
+
+/* montgomery c[] += a * b[] / R % mod */
+static void montMulAdd(RSAPublicKey *key,
+                       uint32_t* c,
+                       const uint32_t a,
+                       const uint32_t* b) {
+    uint64_t A = (uint64_t)a * b[0] + c[0];
+    uint32_t d0 = (uint32_t)A * key->n0inv;
+    uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+    int i;
+
+    for (i = 1; i < key->len; ++i) {
+        A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+        B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+        c[i - 1] = (uint32_t)B;
+    }
+
+    A = (A >> 32) + (B >> 32);
+
+    c[i - 1] = (uint32_t)A;
+
+    if (A >> 32) {
+        subM(key, c);
+    }
+}
+
+/* montgomery c[] = a[] * b[] / R % mod */
+static void montMul(RSAPublicKey *key,
+                    uint32_t* c,
+                    const uint32_t* a,
+                    const uint32_t* b) {
+    int i;
+    for (i = 0; i < key->len; ++i) {
+        c[i] = 0;
+    }
+    for (i = 0; i < key->len; ++i) {
+        montMulAdd(key, c, a[i], b);
+    }
+}
+
+/* In-place public exponentiation.
+** Input and output big-endian byte array in inout.
+*/
+static void modpow3(RSAPublicKey *key,
+                    uint8_t* inout) {
+    uint32_t a[RSANUMWORDS];
+    uint32_t aR[RSANUMWORDS];
+    uint32_t aaR[RSANUMWORDS];
+    uint32_t *aaa = aR;  /* Re-use location. */
+    int i;
+
+    /* Convert from big endian byte array to little endian word array. */
+    for (i = 0; i < key->len; ++i) {
+        uint32_t tmp =
+            (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+            (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+            (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+            (inout[((key->len - 1 - i) * 4) + 3] << 0);
+        a[i] = tmp;
+    }
+
+    montMul(key, aR, a, key->rr);  /* aR = a * RR / R mod M   */
+    montMul(key, aaR, aR, aR);     /* aaR = aR * aR / R mod M */
+    montMul(key, aaa, aaR, a);     /* aaa = aaR * a / R mod M */
+
+    /* Make sure aaa < mod; aaa is at most 1x mod too large. */
+    if (geM(key, aaa)) {
+        subM(key, aaa);
+    }
+
+    /* Convert to bigendian byte array */
+    for (i = key->len - 1; i >= 0; --i) {
+        uint32_t tmp = aaa[i];
+        *inout++ = tmp >> 24;
+        *inout++ = tmp >> 16;
+        *inout++ = tmp >> 8;
+        *inout++ = tmp >> 0;
+    }
+}
+
+/* Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+** Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+** other flavor which omits the optional parameter entirely). This code does not
+** accept signatures without the optional parameter.
+*/
+static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
+    0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+    0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,
+    0x04,0x14
+};
+
+/* Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash.
+** Returns 0 on failure, 1 on success.
+*/
+int RSA_verify(RSAPublicKey *key,
+               const uint8_t *signature,
+               const int len,
+               const uint8_t *sha) {
+    uint8_t buf[RSANUMBYTES];
+    int i;
+
+    if (key->len != RSANUMWORDS) {
+        return 0;  /* Wrong key passed in. */
+    }
+
+    if (len != sizeof(buf)) {
+        return 0;  /* Wrong input length. */
+    }
+
+    for (i = 0; i < len; ++i) {
+        buf[i] = signature[i];
+    }
+
+    modpow3(key, buf);
+
+    /* Check pkcs1.5 padding bytes. */
+    for (i = 0; i < (int) sizeof(padding); ++i) {
+        if (buf[i] != padding[i]) {
+            return 0;
+        }
+    }
+
+    /* Check sha digest matches. */
+    for (; i < len; ++i) {
+        if (buf[i] != *sha++) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
diff --git a/libc/rsa.h b/libc/rsa.h
new file mode 100644
index 0000000..ebe3881
--- /dev/null
+++ b/libc/rsa.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _EMBEDDED_RSA_H_
+#define _EMBEDDED_RSA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSANUMBYTES 256           /* 2048 bit key length */
+#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
+
+typedef struct RSAPublicKey {
+    int len;                  /* Length of n[] in number of uint32_t */
+    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
+    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
+    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+} RSAPublicKey;
+
+int RSA_verify(RSAPublicKey *key,
+               const uint8_t* signature,
+               const int len,
+               const uint8_t* sha);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libc/sha.c b/libc/sha.c
new file mode 100644
index 0000000..69e1f58
--- /dev/null
+++ b/libc/sha.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "sha.h"
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_transform(SHA_CTX *ctx) {
+    uint32_t W[80];
+    uint32_t A, B, C, D, E;
+    uint8_t *p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 80; t++) {
+        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    for(t = 0; t < 80; t++) {
+        uint32_t tmp = rol(5,A) + E + W[t];
+
+        if (t < 20)
+            tmp += (D^(B&(C^D))) + 0x5A827999;
+        else if ( t < 40)
+            tmp += (B^C^D) + 0x6ED9EBA1;
+        else if ( t < 60)
+            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+        else
+            tmp += (B^C^D) + 0xCA62C1D6;
+
+        E = D;
+        D = C;
+        C = rol(30,B);
+        B = A;
+        A = tmp;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void SHA_init(SHA_CTX *ctx) {
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+    ctx->count = 0;
+}
+
+void SHA_update(SHA_CTX *ctx, const void *data, int len) {
+    int i = ctx->count % sizeof(ctx->buf);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == sizeof(ctx->buf)) {
+            SHA1_transform(ctx);
+            i = 0;
+        }
+    }
+}
+const uint8_t *SHA_final(SHA_CTX *ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = cnt >> ((7 - i) * 8);
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
+    const uint8_t *p;
+    int i;
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    SHA_update(&ctx, data, len);
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+        digest[i] = *p++;
+    }
+    return digest;
+}
diff --git a/libc/sha.h b/libc/sha.h
new file mode 100644
index 0000000..1761a7b
--- /dev/null
+++ b/libc/sha.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _EMBEDDED_SHA_H_
+#define _EMBEDDED_SHA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SHA_CTX {
+    uint64_t count;
+    uint8_t buf[64];
+    uint32_t state[5];
+} SHA_CTX;
+
+void SHA_init(SHA_CTX *ctx);
+void SHA_update(SHA_CTX *ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX *ctx);
+
+/* Convenience method. Returns digest parameter value. */
+const uint8_t* SHA(const void *data, int len, uint8_t *digest);
+
+#define SHA_DIGEST_SIZE 20
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libc/sprintf.c b/libc/sprintf.c
new file mode 100644
index 0000000..4075724
--- /dev/null
+++ b/libc/sprintf.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include <boot/boot.h>
+#include "libc_private.h"
+
+struct snprintf_ctxt 
+{
+    char *next;
+    int avail;
+};
+
+static void snprintf_putc(unsigned n, void *cookie)
+{
+    struct snprintf_ctxt *ctxt = cookie;
+    
+    if(ctxt->avail > 0) {
+        *ctxt->next++ = n;
+        ctxt->avail--;
+    }
+}
+
+int snprintf(char *str, int sz, const char *fmt, ...)
+{
+    va_list ap;
+    struct snprintf_ctxt ctxt;
+    
+    if(sz < 1) return 0;
+    
+    ctxt.avail = sz - 1;
+    ctxt.next = str;
+    
+    va_start(ap, fmt);
+    __xprintf(fmt, ap, snprintf_putc, &ctxt);
+    va_end(ap);
+
+    *ctxt.next = 0;
+    return ctxt.next - str;
+}
diff --git a/libc/strcmp.c b/libc/strcmp.c
new file mode 100644
index 0000000..aa5284a
--- /dev/null
+++ b/libc/strcmp.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+int strcmp(const char *a, const char *b)
+{
+    while(*a && *b) {
+        if(*a++ != *b++) return 1;
+    }
+    if(*a || *b) return 1;
+    return 0;
+}
diff --git a/libc/strcpy.c b/libc/strcpy.c
new file mode 100644
index 0000000..154b256
--- /dev/null
+++ b/libc/strcpy.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+char *strcpy(char *dst, const char *src)
+{
+    char *ret = dst;
+    while (*dst++ = *src++) ;	
+    return ret;
+}
diff --git a/libc/strlen.c b/libc/strlen.c
new file mode 100644
index 0000000..9a73799
--- /dev/null
+++ b/libc/strlen.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+int strlen(const char *s)
+{
+    int len = 0;
+    while(*s++) len++;
+    return len;
+}
diff --git a/libc/strstr.c b/libc/strstr.c
new file mode 100644
index 0000000..2ca92a5
--- /dev/null
+++ b/libc/strstr.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+
+char *strstr(const char *s1, const char *s2)
+{
+    int l1 = strlen(s1);
+    int l2 = strlen(s2);
+    
+    while (l1 >= l2) {
+        if (memcmp(s1, s2, l2) == 0) {
+            return s1;
+        }
+        s1++;
+        l1--;
+    }
+    return 0;
+}
diff --git a/libc/xprintf.c b/libc/xprintf.c
new file mode 100644
index 0000000..8f0fe94
--- /dev/null
+++ b/libc/xprintf.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include "libc_private.h"
+
+static int hex2asc(int n)
+{
+    n &= 15;
+    if(n > 9){
+        return ('a' - 10) + n;
+    } else {
+        return '0' + n;
+    }
+}
+
+static void xputs(const char *s, void (*xputc)(unsigned n, void *cookie), void *cookie)
+{
+    while (*s) {
+        xputc(*s++, cookie);
+    }
+}
+
+void __xprintf(const char *fmt, va_list ap,
+               void (*xputc)(unsigned n, void *cookie),
+               void *cookie)
+{
+    char scratch[16];
+
+    for(;;){
+        switch(*fmt){
+        case 0:
+            va_end(ap);
+            return;
+        case '%':
+            switch(fmt[1]) {
+            case 'c': {
+                unsigned n = va_arg(ap, unsigned);
+                xputc(n, cookie);
+                fmt += 2;
+                continue;
+            }
+            case 'h': {
+                unsigned n = va_arg(ap, unsigned);
+                xputc(hex2asc(n >> 12), cookie);
+                xputc(hex2asc(n >> 8), cookie);
+                xputc(hex2asc(n >> 4), cookie);
+                xputc(hex2asc(n >> 0), cookie);
+                fmt += 2;
+                continue;
+            }
+            case 'b': {
+                unsigned n = va_arg(ap, unsigned);
+                xputc(hex2asc(n >> 4), cookie);
+                xputc(hex2asc(n >> 0), cookie);
+                fmt += 2;
+                continue;
+            }                
+            case 'p':
+            case 'X':
+            case 'x': {
+                unsigned n = va_arg(ap, unsigned);
+                char *p = scratch + 15;
+                *p = 0;
+                do {
+                    *--p = hex2asc(n);
+                    n = n >> 4; 
+                } while(n != 0);
+                while(p > (scratch + 7)) *--p = '0';
+                xputs(p, xputc, cookie);
+                fmt += 2;
+                continue;
+            }
+            case 'd': {
+                int n = va_arg(ap, int);
+                char *p = scratch + 15;
+                *p = 0;
+                if(n < 0) {
+                    xputc('-', cookie);
+                    n = -n;
+                }
+                do {
+                    *--p = (n % 10) + '0';
+                    n /= 10;
+                } while(n != 0);
+                xputs(p, xputc, cookie);
+                fmt += 2;
+                continue;
+            }
+            case 's': {
+                char *s = va_arg(ap, char*);
+                if(s == 0) s = "(null)";
+                xputs(s, xputc, cookie);
+                fmt += 2;
+                continue;
+            }
+            }
+            xputc(*fmt++, cookie);
+            break;
+        case '\n':
+            xputc('\r', cookie);
+        default:
+            xputc(*fmt++, cookie);
+        }
+    }
+}
diff --git a/nandwrite/Android.mk b/nandwrite/Android.mk
new file mode 100644
index 0000000..be97da9
--- /dev/null
+++ b/nandwrite/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader mkbootimg)
+
+LOCAL_SRC_FILES := init.S jtag.c nandwrite.c
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+
+LOCAL_MODULE := nandwrite
+
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)
+LOCAL_STATIC_LIBRARIES := $(TARGET_BOOTLOADER_LIBS) libboot libboot_c 
+
+include $(BUILD_RAW_EXECUTABLE)
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_LINK_SCRIPT := $(TARGET_BOOTLOADER_LINK_SCRIPT)
diff --git a/nandwrite/init.S b/nandwrite/init.S
new file mode 100644
index 0000000..c542503
--- /dev/null
+++ b/nandwrite/init.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/arm.h>
+
+v_reset:
+	b start
+v_undefined:
+	b .
+v_swi:
+	b .
+v_prefetch_abt:
+	b .
+v_data_abt:
+	b .
+v_reserved:		
+	b .
+v_irq:	
+	b .
+v_fiq:	
+	b .
+
+start:
+	/* save registers for main() */
+	mov r7, r0
+	mov r8, r1
+	mov r9, r2
+	mov r10, r3
+
+	/* init stacks */
+	ldr r0, =BOOTLOADER_STACK
+	msr cpsr_c, #(PSR_I | PSR_F | PSR_SVC)
+	mov sp, r0
+
+	/* zero the BSS */
+	ldr r1, =BOOTLOADER_BSS
+	ldr r2, =BOOTLOADER_END
+	mov r0, #0
+1:	str r0, [r1], #4
+	cmp r1, r2
+	ble 1b
+		
+	bl periph_2gb_open
+
+	/* restore registers for main() */
+	mov r0, r7
+	mov r1, r8
+	mov r2, r9
+	mov r3, r10
+		
+	ldr r4, =_main
+	blx r4
+	b .
diff --git a/nandwrite/jtag.c b/nandwrite/jtag.c
new file mode 100644
index 0000000..e91d1e8
--- /dev/null
+++ b/nandwrite/jtag.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+
+#define STATUS_NOMSG 0
+#define STATUS_OKAY  1
+#define STATUS_FAIL  2
+#define STATUS_PRINT 3
+
+void jtag_hook();
+
+volatile unsigned _jtag_cmd = 0;
+volatile unsigned _jtag_msg = 0;
+unsigned char _jtag_cmd_buffer[128];
+unsigned char _jtag_msg_buffer[128];
+
+volatile unsigned _jtag_arg0 = 0;
+volatile unsigned _jtag_arg1 = 0;
+volatile unsigned _jtag_arg2 = 0;
+
+static void jtag_msg(unsigned status, const char *msg)
+{
+    unsigned char *out = _jtag_msg_buffer;
+    while((*out++ = *msg++) != 0) ;
+    _jtag_msg = status;
+    do {
+        jtag_hook();
+    } while(_jtag_msg != 0);
+}
+
+void jtag_okay(const char *msg)
+{
+    if(msg == 0) msg = "OKAY";
+    jtag_msg(STATUS_OKAY, msg);
+}
+
+void jtag_fail(const char *msg)
+{
+    if(msg == 0) msg = "FAIL";
+    jtag_msg(STATUS_FAIL, msg);
+}
+
+int jtag_cmd_pending()
+{
+    jtag_hook();
+    return (int) _jtag_cmd;
+}
+
+void jtag_cmd_loop(void (*do_cmd)(const char *, unsigned, unsigned, unsigned))
+{
+    unsigned n;
+    for(;;) {
+        if(jtag_cmd_pending()){
+            do_cmd((const char*) _jtag_cmd_buffer, _jtag_arg0, _jtag_arg1, _jtag_arg2);
+            for(n = 0; n < 256; n++) _jtag_cmd_buffer[n] = 0;
+            _jtag_arg0 = 0;
+            _jtag_arg1 = 0;
+            _jtag_arg2 = 0;
+            _jtag_cmd = 0;
+        }
+    }
+}
+
+static char jtag_putc_buffer[128];
+static unsigned jtag_putc_count = 0;
+
+static void jtag_push_buffer(void)
+{
+    jtag_putc_buffer[jtag_putc_count] = 0;
+    jtag_putc_count = 0;
+    jtag_msg(STATUS_PRINT, jtag_putc_buffer);
+}
+    
+void jtag_dputc(unsigned c)
+{
+    if((c < 32) || (c > 127)) {
+        if(c == '\n') {
+            jtag_push_buffer();
+        }
+        return;
+    }
+        
+    jtag_putc_buffer[jtag_putc_count++] = c;
+    if(jtag_putc_count == 127) {
+        jtag_push_buffer();
+    }
+}
+
diff --git a/nandwrite/nandwrite.c b/nandwrite/nandwrite.c
new file mode 100644
index 0000000..c715095
--- /dev/null
+++ b/nandwrite/nandwrite.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/board.h>
+#include <boot/flash.h>
+
+#define FLASH_PAGE_SIZE 2048
+#define FLASH_PAGE_BITS 11
+
+int startswith(const char *str, const char *prefix)
+{
+    while(*prefix){
+        if(*prefix++ != *str++) return 0;
+    }
+    return 1;
+}
+
+void verify_flash(ptentry *p, void *addr, unsigned len, int extra)
+{
+	int offset = 0;
+	void *buf = alloc(FLASH_PAGE_SIZE + extra);
+	int verify_extra = extra;
+	if(verify_extra > 4)
+		verify_extra = 16;
+	while(len > 0) {
+		flash_read_ext(p, extra, offset, buf, FLASH_PAGE_SIZE);
+		if(memcmp(addr, buf, FLASH_PAGE_SIZE + verify_extra)) {
+			dprintf("verify failed at %x\n", offset);
+	        jtag_fail("verify failed");
+			return;
+		}
+		offset += FLASH_PAGE_SIZE;
+		addr += FLASH_PAGE_SIZE;
+		len -= FLASH_PAGE_SIZE;
+		if(extra) {
+			addr += extra;
+			len -= extra;
+		}
+	}
+	dprintf("verify done %d extra bytes\n", verify_extra);
+	jtag_okay("verify done");
+}
+
+void handle_flash(const char *name, unsigned addr, unsigned len)
+{
+    int r;
+    ptentry *p;
+
+    dprintf("image @ %x (%d bytes)\n", addr, len);
+    dprintf("write to '%s' partition\n", name);
+
+    p = flash_find_ptn(name);
+
+    if(p == 0) {
+        jtag_fail("partition not found");
+        return;
+    } else {
+        if(flash_init()) {
+            jtag_fail("flash_init() failed");
+            return;
+        }
+
+        dprintf("erasing flash @ %d (len=%d)\n", p->start, p->length);
+        flash_erase(p);
+
+        if(len) {
+            dprintf("writing flash at @ %d\n", p->start);
+
+            if(!strcmp(name, "system") || !strcmp(name, "userdata")) {
+                r = flash_write(p, 64, (void*) addr, len);
+            } else {
+                len = (len + FLASH_PAGE_SIZE - 1) & (~(FLASH_PAGE_SIZE-1));
+                r = flash_write(p, 0, (void*) addr, len);
+            }
+			//verify_flash(p, addr, len, (!strcmp(name, "system") || !strcmp(name, "userdata")) ? 64 : 0);
+            if(r) {
+                jtag_fail("partition write failed");
+            } else {
+                jtag_okay("partition written");
+            }
+            return;
+        } else {
+            jtag_okay("partition erased");
+            return;
+        }
+    }
+}
+
+void hexdump(void *ptr, unsigned len)
+{
+    unsigned char *b = ptr;
+    int count = 0;
+
+    dprintf("%x: ", (unsigned) b);
+    while(len-- > 0) {
+        dprintf("%b ", *b++);
+        if(++count == 16) {
+            dprintf("\n%x: ", (unsigned) b);
+            count = 0;
+        }
+    }
+    if(count != 0) dprintf("\n");
+}
+
+static unsigned char *tmpbuf = 0;
+
+void handle_dump(const char *name, unsigned offset)
+{
+    ptentry *p;
+    
+    if(tmpbuf == 0) {
+        tmpbuf = alloc(4096);
+    }
+
+    dprintf("dump '%s' partition\n", name);
+    p = flash_find_ptn(name);
+
+    if(p == 0) {
+        jtag_fail("partition not found");
+        return;
+    }
+    
+    if(flash_init()) {
+        jtag_fail("flash_init() failed");
+        return;
+    }
+
+#if 0
+        /* XXX reimpl */
+    if(flash_read_page(p->start * 64, tmpbuf, tmpbuf + 2048)){
+        jtag_fail("flash_read() failed");
+        return;
+    }
+#endif
+
+    dprintf("page %d data:\n", p->start * 64);
+    hexdump(tmpbuf, 256);
+    dprintf("page %d extra:\n", p->start * 64);
+    hexdump(tmpbuf, 16);
+    jtag_okay("done");
+}
+
+void handle_command(const char *cmd, unsigned a0, unsigned a1, unsigned a2)
+{
+    if(startswith(cmd,"flash:")){
+        handle_flash(cmd + 6, a0, a1);
+        return;
+    }
+
+    if(startswith(cmd,"dump:")){
+        handle_dump(cmd + 5, a0);
+        return;
+    }
+
+    jtag_fail("unknown command");
+}
+
+int _main(void)
+{
+    arm11_clock_init();
+
+    dprintf_set_putc(jtag_dputc);
+
+    board_init();
+    
+    jtag_cmd_loop(handle_command);
+
+    return 0;
+}
diff --git a/usbloader/Android.mk b/usbloader/Android.mk
new file mode 100644
index 0000000..66c9e53
--- /dev/null
+++ b/usbloader/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_C_INCLUDES := $(call include-path-for, bootloader mkbootimg)
+
+LOCAL_SRC_FILES := init.S main.c usbloader.c
+
+LOCAL_CFLAGS := -O2 -g -W -Wall
+LOCAL_CFLAGS += -march=armv6
+LOCAL_CFLAGS += -DPRODUCTNAME='"$(strip $(TARGET_BOOTLOADER_BOARD_NAME))"'
+
+LOCAL_MODULE := usbloader
+
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)
+LOCAL_STATIC_LIBRARIES := $(TARGET_BOOTLOADER_LIBS) libboot libboot_c 
+
+include $(BUILD_RAW_EXECUTABLE)
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_LINK_SCRIPT := $(TARGET_BOOTLOADER_LINK_SCRIPT)
diff --git a/usbloader/init.S b/usbloader/init.S
new file mode 100644
index 0000000..9d048ea
--- /dev/null
+++ b/usbloader/init.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+.global irq_glue
+.global irq_vector_table
+
+#include <boot/arm.h>
+
+v_reset:
+	b start
+v_undefined:
+	b .
+v_swi:
+	b .
+v_prefetch_abt:
+	b .
+v_data_abt:
+	b .
+v_reserved:		
+	b .
+v_irq:
+	b .
+v_fiq:	
+	b .
+
+start:
+	ldr r5, =0xfffff000
+	ands r4, pc, r5
+	beq already_at_zero
+
+	/* we're not loaded at 0 -- relocate us back down to where we belong */
+	mov r5, #0
+	ldr r6, =BOOTLOADER_END
+1:	ldr r7, [r4], #4
+	str r7, [r5], #4
+	cmp r5, r6
+	bne 1b
+		
+	mov pc, #0
+
+already_at_zero:		
+	/* save registers for main() */
+	mov r7, r0
+	mov r8, r1
+	mov r9, r2
+	mov r10, r3
+
+	/* init stack */
+	ldr r0, =BOOTLOADER_STACK
+	msr cpsr_c, #(PSR_I | PSR_F | PSR_SVC)
+	mov sp, r0
+
+	/* zero the BSS */
+	ldr r1, =BOOTLOADER_BSS
+	ldr r2, =BOOTLOADER_END
+	mov r0, #0
+1:	str r0, [r1], #4
+	cmp r1, r2
+	ble 1b
+		
+	bl periph_2gb_open
+
+	/* restore registers for main() */
+	mov r0, r7
+	mov r1, r8
+	mov r2, r9
+	mov r3, r10
+		
+	ldr r4, =_main
+	blx r4
+	b .
diff --git a/usbloader/main.c b/usbloader/main.c
new file mode 100644
index 0000000..490b138
--- /dev/null
+++ b/usbloader/main.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/uart.h>
+#include <boot/tags.h>
+#include <boot/flash.h>
+#include <boot/board.h>
+
+#include <bootimg.h>
+
+#define FLASH_PAGE_SIZE 2048
+#define FLASH_PAGE_BITS 11
+
+#define ADDR_TAGS    0x10000100
+
+static void create_atags(unsigned taddr, const char *cmdline,
+                         unsigned raddr, unsigned rsize)
+{
+    unsigned n = 0;
+    unsigned pcount;
+    unsigned *tags = (unsigned *) taddr;
+
+        // ATAG_CORE 
+    tags[n++] = 2;
+    tags[n++] = 0x54410001;
+
+    if(rsize) {
+        // ATAG_INITRD2
+        tags[n++] = 4;
+        tags[n++] = 0x54420005;
+        tags[n++] = raddr;
+        tags[n++] = rsize;
+    }
+
+    if((pcount = flash_get_ptn_count())){
+        ptentry *ptn;
+        unsigned pn;
+        unsigned m = n + 2;
+
+        for(pn = 0; pn < pcount; pn++) {
+            ptn = flash_get_ptn(pn);
+            memcpy(tags + m, ptn, sizeof(ptentry));
+            m += (sizeof(ptentry) / sizeof(unsigned));
+        }
+        
+        tags[n + 0] = m - n;
+        tags[n + 1] = 0x4d534d70;
+        n = m;
+    }
+    if(cmdline && cmdline[0]) {
+        const char *src;
+        char *dst;
+        unsigned len = 0;
+        
+        dst = (char*) (tags + n + 2);
+        src = cmdline;
+        while((*dst++ = *src++)) len++;
+        
+        len++;
+        len = (len + 3) & (~3);
+
+            // ATAG_CMDLINE
+        tags[n++] = 2 + (len / 4);
+        tags[n++] = 0x54410009;
+
+        n += (len / 4);
+    }
+    
+        // ATAG_NONE
+    tags[n++] = 0;
+    tags[n++] = 0;
+}
+
+static void boot_linux(unsigned kaddr)
+{
+    void (*entry)(unsigned,unsigned,unsigned) = (void*) kaddr;
+
+    entry(0, board_machtype(), ADDR_TAGS);
+}
+
+unsigned char raw_header[2048];
+
+int boot_linux_from_flash(void)
+{
+    boot_img_hdr *hdr = (void*) raw_header;
+    unsigned n;
+    ptentry *p;
+    unsigned offset = 0;
+    const char *cmdline;
+
+    if((p = flash_find_ptn("boot")) == 0) {
+        cprintf("NO BOOT PARTITION\n");
+        return -1;
+    }
+
+    if(flash_read(p, offset, raw_header, 2048)) {
+        cprintf("CANNOT READ BOOT IMAGE HEADER\n");
+        return -1;
+    }
+    offset += 2048;
+    
+    if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+        cprintf("INVALID BOOT IMAGE HEADER\n");
+        return -1;
+    }
+
+    n = (hdr->kernel_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));
+    if(flash_read(p, offset, (void*) hdr->kernel_addr, n)) {
+        cprintf("CANNOT READ KERNEL IMAGE\n");
+        return -1;
+    }
+    offset += n;
+
+    n = (hdr->ramdisk_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1));
+    if(flash_read(p, offset, (void*) hdr->ramdisk_addr, n)) {
+        cprintf("CANNOT READ RAMDISK IMAGE\n");
+        return -1;
+    }
+    offset += n;
+    
+    dprintf("\nkernel  @ %x (%d bytes)\n", hdr->kernel_addr, hdr->kernel_size);
+    dprintf("ramdisk @ %x (%d bytes)\n\n\n", hdr->ramdisk_addr, hdr->ramdisk_size);
+
+    if(hdr->cmdline[0]) {
+        cmdline = (char*) hdr->cmdline;
+    } else {
+        cmdline = board_cmdline();
+        if(cmdline == 0) {
+            cmdline = "mem=50M console=null";
+        }
+    }
+    cprintf("cmdline = '%s'\n", cmdline);
+    
+    cprintf("\nBooting Linux\n");
+
+    create_atags(ADDR_TAGS, cmdline,
+                 hdr->ramdisk_addr, hdr->ramdisk_size);
+    
+    boot_linux(hdr->kernel_addr);
+    return 0;
+}
+
+void usbloader_init(void);
+void uart_putc(unsigned);
+const char *get_fastboot_version(void);
+
+extern unsigned linux_type;
+extern unsigned linux_tags;
+
+static unsigned revision = 0;
+
+char serialno[32];
+
+void dump_smem_info(void);
+
+static void tag_dump(unsigned tag, void *data, unsigned sz, void *cookie)
+{
+    dprintf("tag type=%x data=%x size=%x\n", tag, (unsigned) data, sz);
+}
+
+static struct tag_handler tag_dump_handler = {
+    .func = tag_dump,
+    .type = 0,
+};
+
+void xdcc_putc(unsigned x)
+{
+    while (dcc_putc(x) < 0) ;
+}
+
+#define SERIALNO_STR "androidboot.serialno="
+#define SERIALNO_LEN strlen(SERIALNO_STR)
+
+static int boot_from_flash = 1;
+
+void key_changed(unsigned int key, unsigned int down)
+{
+    if(!down) return;
+    if(key == BOOT_KEY_STOP_BOOT) boot_from_flash = 0;
+}
+
+static int tags_okay(unsigned taddr)
+{
+    unsigned *tags = (unsigned*) taddr;
+
+    if(taddr != ADDR_TAGS) return 0;
+    if(tags[0] != 2) return 0;
+    if(tags[1] != 0x54410001) return 0;
+
+    return 1;
+}
+
+int _main(unsigned zero, unsigned type, unsigned tags)
+{    
+    const char *cmdline = 0;
+    int n;
+    
+    arm11_clock_init();
+
+        /* must do this before board_init() so that we
+        ** use the partition table in the tags if it 
+        ** already exists 
+        */
+    if((zero == 0) && (type != 0) && tags_okay(tags)) {
+        linux_type = type;
+        linux_tags = tags;
+
+        cmdline = tags_get_cmdline((void*) linux_tags);
+        
+        tags_import_partitions((void*) linux_tags);
+        revision = tags_get_revision((void*) linux_tags);
+        if(revision == 1) {
+            console_set_colors(0x03E0, 0xFFFF);
+        }
+        if(revision == 2) {
+            console_set_colors(0x49B2, 0xFFFF);
+        }
+
+            /* we're running as a second-stage, so wait for interrupt */
+        boot_from_flash = 0;
+    } else {
+        linux_type = board_machtype();
+        linux_tags = 0;
+    }
+
+    board_init();
+    keypad_init();
+    
+    console_init();
+    dprintf_set_putc(uart_putc);    
+
+    if(linux_tags == 0) {
+            /* generate atags containing partitions 
+             * from the bootloader, etc 
+             */
+        linux_tags = ADDR_TAGS;
+        create_atags(linux_tags, 0, 0, 0);
+    }
+    
+    if (cmdline) {
+        char *sn = strstr(cmdline, SERIALNO_STR);
+        if (sn) {
+            char *s = serialno;
+            sn += SERIALNO_LEN;
+            while (*sn && (*sn != ' ') && ((s - serialno) < 31)) {
+                *s++ = *sn++;
+            }
+            *s++ = 0;
+        }
+    }
+
+    cprintf("\n\nUSB FastBoot:  V%s\n", get_fastboot_version());
+    cprintf("Machine ID:    %d v%d\n", linux_type, revision);
+    cprintf("Build Date:    "__DATE__", "__TIME__"\n\n");
+
+    cprintf("Serial Number: %s\n\n", serialno[0] ? serialno : "UNKNOWN");
+
+    flash_dump_ptn();
+
+    flash_init();
+
+        /* scan the keyboard a bit */
+    for(n = 0; n < 50; n++) {
+        boot_poll();
+    }
+
+    if (boot_from_flash) {
+        cprintf("\n ** BOOTING LINUX FROM FLASH **\n");
+        boot_linux_from_flash();
+    }
+
+    usbloader_init();
+    
+    for(;;) {
+        usb_poll();
+    }
+    return 0;
+}
diff --git a/usbloader/usbloader.c b/usbloader/usbloader.c
new file mode 100644
index 0000000..ca7b4fa
--- /dev/null
+++ b/usbloader/usbloader.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <boot/boot.h>
+#include <boot/flash.h>
+#include <boot/board.h>
+#include <boot/usb.h>
+
+#include <boot/bootimg.h>
+#include <boot/tags.h>
+
+#include <boot/gpio.h>
+
+#define VERSION "0.5"
+
+#define REQUIRE_SIGNATURE 0
+
+#if REQUIRE_SIGNATURE
+unsigned key_engineering[2 + 64 + 64] = {
+    64,0x5b022317,-60769447,648742897,-13657530,585562035,591851935,
+    454860199,-1809625305,1868200692,-155297008,-1688439840,-1333607631,
+    -483027189,-2051438457,1030069735,819944365,2133377257,-1978924214,
+    2109678622,1974978919,-1811463608,765849268,1984092281,921245328,
+    -1055062768,1487475997,1209618652,871985152,-611178965,-2057018571,
+    335641539,-1196119550,1550548229,-356223887,1909799623,1281016007,
+    957001635,1005656532,-1027634024,-1576447610,-1917246637,589192795,
+    -1137386186,-1958135372,1933245070,64958951,-1820428322,-1577697840,
+    1824253519,555306239,-1588272058,-1925773018,1205934271,-836584444,
+    -1140961670,-185198349,1293769947,37045923,1516796974,-297288651,
+    651582073,-1337054592,-543971216,-1706823885,-1040652818,-594113104,
+    260093481,-1277656496,56493468,1577037283,773995876,244894933,
+    -2075797967,783894843,880611008,-1433369702,380946504,-2081431477,
+    1377832804,2089455451,-410001201,1245307237,-1228170341,-2062569137,
+    -1327614308,-1671042654,1242248660,-418803721,40890010,-1806767460,
+    -1468529145,-1058158532,1243817302,-527795003,175453645,-210650325,
+    -827053868,-571422860,886300657,2129677324,846504590,-1413102805,
+    -1287448511,-1991140134,56194155,1375685594,-129884114,1393568535,
+    -1098719620,-935279550,1717137954,-1782544741,272581921,-669183778,
+    584824755,1434974827,-1122387971,-810584927,-2147338547,-937541680,
+    -313561073,5506366,-1594059648,-1744451574,1896015834,1496367069,
+    1742853908,508461291,1905056764
+};
+#endif
+
+const char *get_fastboot_version(void)
+{
+    return VERSION;
+}
+
+unsigned linux_type = 0;
+unsigned linux_tags = 0;
+
+unsigned ramdisk_addr = 0x10400000;
+unsigned ramdisk_size = 0;
+unsigned kernel_addr = 0x10008000;
+unsigned kernel_size = 0;
+
+static void fixup_tags(unsigned *tags, unsigned *out, const char *cmdline)
+{
+    unsigned *newtags = (unsigned *) 0x10004000;
+    unsigned *np = newtags;
+    unsigned n;
+    char *oldcmdline = "";
+    
+    if(cmdline == 0) cmdline = "";
+
+        /* CORE */
+    *np++ = 2;
+    *np++ = 0x54410001;
+
+    if(tags != 0) {
+        while(*tags) {
+            if(tags[1] == 0x54410001) {
+                    /* skip core tag */
+                tags += tags[0];
+            } else if((tags[1] == 0x54420005) && (ramdisk_size != 0)) {
+                    /* skip ramdisk if we have one of our own */
+                tags += tags[0];
+            } else if((tags[1] == 0x54410009) && (cmdline[0])) {
+                    /* skip existing cmdline so we can replace it */
+                oldcmdline = (char*) (tags + 2);
+                tags += tags[0];
+            } else {
+                    /* copy any unknown tags */
+                n = tags[0];
+                while(n-- > 0) {
+                    *np++ = *tags++;
+                }
+            }
+        }
+    }
+
+        /* create a ramdisk tag if we need to */
+    if(ramdisk_size) {
+        *np++ = 4;
+        *np++ = 0x54420005;
+        *np++ = ramdisk_addr;
+        *np++ = ramdisk_size;
+    }
+
+    dprintf("cmdline: '%s'\n", oldcmdline);
+    dprintf("cmdline: '%s'\n", cmdline);
+    
+        /* create a cmdline tag if we need to */
+    if(cmdline[0]) {
+        int len;
+        char *str = (char*) (np + 2);
+        
+        len = strlen(oldcmdline);
+        if(len) {
+            memcpy(str, oldcmdline, len);
+            str += len;
+            *str++ = ' ';
+        }
+
+        len = strlen(cmdline);
+        memcpy(str, cmdline, len);
+        str += len;
+        *str++ = 0;
+        
+            /* length in words */
+        len = ((str - ((char*) (np + 2))) + 3) / 4;
+
+        dprintf("CMDLINE: '%s'\n", ((char*) (np + 2)));
+        
+        *np++ = 2 + len;
+        *np++ = 0x54410009;
+        
+        np += len;
+    }
+
+        /* add footer tag */
+    *np++ = 0;
+    *np++ = 0;
+    
+        /* copy it all back to the original tags area */
+    while(newtags < np) {
+        *out++ = *newtags++;
+    }
+}
+
+static char cmdline[BOOT_ARGS_SIZE];
+
+static void boot_linux(void)
+{
+    unsigned *tags = (unsigned*) 0x10000100;
+    void (*entry)(unsigned,unsigned,unsigned) = (void*) kernel_addr;
+
+    if(linux_type == 0) {
+        linux_type = board_machtype();
+    }
+    
+    fixup_tags((unsigned*) linux_tags, tags, cmdline);    
+
+    entry(0, linux_type, tags);
+    
+    for(;;);
+}
+
+/* convert a boot_image at kernel_addr into a kernel + ramdisk + tags */
+static int init_boot_linux(void)
+{
+    boot_img_hdr *hdr = (void*) kernel_addr;
+    unsigned page_mask = 2047;
+    unsigned kernel_actual;
+    unsigned ramdisk_actual;
+    unsigned second_actual;
+    
+    if((kernel_size < 2048) || memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){
+        dprintf("bootimg: bad header\n");
+        return -1;
+    }
+
+    if(hdr->page_size != 2048) {
+        dprintf("bootimg: invalid page size\n");
+        return -1;
+    }
+
+    kernel_actual = (hdr->kernel_size + page_mask) & (~page_mask);
+    ramdisk_actual = (hdr->ramdisk_size + page_mask) & (~page_mask);
+    second_actual = (hdr->second_size + page_mask) & (~page_mask);
+    
+    if(kernel_size != (kernel_actual + ramdisk_actual + second_actual + 2048)) {
+        dprintf("bootimg: invalid image size");
+        return -1;
+    }
+
+        /* XXX process commandline here */
+    if(hdr->cmdline[0]){
+        hdr->cmdline[BOOT_ARGS_SIZE - 1] = 0;
+        memcpy(cmdline, hdr->cmdline, BOOT_ARGS_SIZE);
+    }
+
+        /* XXX how to validate addresses? */
+    ramdisk_addr = hdr->ramdisk_addr;
+    ramdisk_size = hdr->ramdisk_size;
+
+    kernel_addr = hdr->kernel_addr;
+    kernel_size = hdr->kernel_size;
+    
+    dprintf("bootimg: kernel addr=%x size=%x\n",
+            kernel_addr, kernel_size);
+    dprintf("bootimg: ramdisk addr=%x size=%x\n",
+            ramdisk_addr, ramdisk_size);
+    
+    memcpy((void*) ramdisk_addr, 
+           hdr->magic + 2048 + kernel_actual,
+           ramdisk_size);
+    
+    memcpy((void*) kernel_addr,
+           hdr->magic + 2048,
+           kernel_size);
+    
+    return 0; 
+}
+
+static struct usb_endpoint *ep1in, *ep1out;
+static struct usb_request *rx_req, *tx_req;
+static unsigned rx_addr;
+static unsigned rx_length;
+
+static char *cmdbuf;
+
+static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status);
+static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status);
+
+static void rx_cmd(void)
+{
+    struct usb_request *req = rx_req;
+    req->buf = cmdbuf;
+    req->length = 4096;
+    req->complete = usb_rx_cmd_complete;
+    usb_queue_req(ep1out, req);
+}
+
+static void rx_data(void)
+{
+    struct usb_request *req = rx_req;
+    req->buf = (void*) rx_addr;
+    req->length = (rx_length > 4096) ? 4096 : rx_length;
+    req->complete = usb_rx_data_complete;
+    usb_queue_req(ep1out, req);
+}
+
+static void tx_status(const char *status)
+{
+    struct usb_request *req = tx_req;
+    int len = strlen(status);
+//    dprintf("tx_status('%s')\n", status);
+    memcpy(req->buf, status, len);
+    req->length = len;
+    req->complete = 0;
+    usb_queue_req(ep1in, req);
+}
+
+static void usb_rx_data_complete(struct usb_request *req, unsigned actual, int status)
+{
+    if(status != 0) return;
+
+    if(actual > rx_length) {
+        actual = rx_length;
+    }
+
+    rx_addr += actual;
+    rx_length -= actual;
+    
+    if(rx_length > 0) {
+        rx_data();
+    } else {
+        tx_status("OKAY");
+        rx_cmd();
+    }
+}
+
+static unsigned hex2unsigned(char *x)
+{
+    unsigned n = 0;
+
+    while(*x) {
+        switch(*x) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            n = (n << 4) | (*x - '0');
+            break;
+        case 'a': case 'b': case 'c':
+        case 'd': case 'e': case 'f':
+            n = (n << 4) | (*x - 'a' + 10);
+            break;
+        case 'A': case 'B': case 'C':
+        case 'D': case 'E': case 'F':
+            n = (n << 4) | (*x - 'A' + 10);
+            break;
+        default:
+            return n;
+        }
+        x++;
+    }
+
+    return n;
+}
+
+static void num_to_hex8(unsigned n, char *out)
+{
+    static char tohex[16] = "0123456789abcdef";
+    int i;
+    for(i = 7; i >= 0; i--) {
+        out[i] = tohex[n & 15];
+        n >>= 4;
+    }
+    out[8] = 0;
+}
+
+extern char serialno[];
+
+static char signature[SIGNATURE_SIZE];
+
+static void usb_rx_cmd_complete(struct usb_request *req, unsigned actual, int status)
+{
+    if(status != 0) return;
+    
+    if(actual > 4095) actual = 4095;    
+    cmdbuf[actual] = 0;
+
+    dprintf("\n> %s\n",cmdbuf);
+    
+//    dprintf("usb_rx_cmd_complete() '%s'\n", cmdbuf);  
+    
+    if(memcmp(cmdbuf, "reboot", 6) == 0) {
+        tx_status("OKAY");
+        rx_cmd();
+        mdelay(100);
+        board_reboot();
+    }
+#if 0
+    if(memcmp(cmdbuf, "debug:", 6) == 0) {
+        void debug(char *cmd, char *resp);
+        memcpy(cmdbuf, "OKAY", 5);
+        tx_status(cmdbuf);
+        rx_cmd();
+        mdelay(5000);
+        dprintf("NOW!\n");
+        debug(cmdbuf + 6, cmdbuf + 4);
+        return;
+    }
+#endif
+    if(memcmp(cmdbuf, "getvar:", 7) == 0) {
+        char response[64];
+        strcpy(response,"OKAY");
+        
+        if(!strcmp(cmdbuf + 7, "version")) {
+            strcpy(response + 4, VERSION);
+        } else if(!strcmp(cmdbuf + 7, "product")) {
+            strcpy(response + 4, PRODUCTNAME);
+        } else if(!strcmp(cmdbuf + 7, "serialno")) {
+            strcpy(response + 4, serialno);
+        } else {
+            board_getvar(cmdbuf + 7, response + 4);
+        }
+        tx_status(response);
+        rx_cmd();
+        return;
+    }
+
+    if(memcmp(cmdbuf, "download:", 9) == 0) {
+        char status[16];
+        rx_addr = kernel_addr;
+        rx_length = hex2unsigned(cmdbuf + 9);
+        if (rx_length > (64*1024*1024)) {
+            tx_status("FAILdata too large");
+            rx_cmd();
+            return;
+        }
+        kernel_size = rx_length;
+        dprintf("recv data addr=%x size=%x\n", rx_addr, rx_length); 
+        strcpy(status,"DATA");
+        num_to_hex8(rx_length, status + 4);
+        tx_status(status);
+        rx_data();
+        return;
+    }
+
+    if(memcmp(cmdbuf, "erase:", 6) == 0){
+        struct ptentry *ptn;
+        ptn = flash_find_ptn(cmdbuf + 6);
+        if(ptn == 0) {
+            tx_status("FAILpartition does not exist");
+            rx_cmd();
+            return;
+        }
+        dprintf("erasing '%s'\n", ptn->name);
+        cprintf("erasing '%s'", ptn->name);
+        if(flash_erase(ptn)) {
+            tx_status("FAILfailed to erase partition");
+            rx_cmd();
+            cprintf(" - FAIL\n");
+            return;
+        } else {
+            dprintf("partition '%s' erased\n", ptn->name);
+            cprintf(" - OKAY\n");
+        }
+        tx_status("OKAY");
+        rx_cmd();
+        return;
+    }
+
+    if(memcmp(cmdbuf, "flash:", 6) == 0){
+        struct ptentry *ptn;
+        int extra = 0;
+        ptn = flash_find_ptn(cmdbuf + 6);
+        if(kernel_size == 0) {
+            tx_status("FAILno image downloaded");
+            rx_cmd();
+            return;
+        }
+        if(ptn == 0) {
+            tx_status("FAILpartition does not exist");
+            rx_cmd();
+            return;
+        }
+        if(!strcmp(ptn->name,"boot") || !strcmp(ptn->name,"recovery")) {
+            if(memcmp((void*) kernel_addr, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+                tx_status("FAILimage is not a boot image");
+                rx_cmd();
+                return;
+            }
+        }
+#if REQUIRE_SIGNATURE
+        {
+            unsigned char digest[DIGEST_SIZE];
+            compute_digest((void*) kernel_addr, kernel_size, digest);
+            if (is_signature_okay(digest, signature, key_engineering)) {
+                dprintf("verified by engineering key\n");
+            } else {
+                tx_status("FAILsignature did not verify");
+                rx_cmd();
+                return;
+            }
+        }
+#endif
+        if(!strcmp(ptn->name,"system") || !strcmp(ptn->name,"userdata")) {
+            extra = 64;
+        } else {
+            kernel_size = (kernel_size + 2047) & (~2047);
+        }
+        dprintf("writing %d bytes to '%s'\n", 
+                kernel_size, ptn->name);
+        cprintf("writing '%s' (%d bytes)", ptn->name, kernel_size);
+        if(flash_write(ptn, extra, (void*) kernel_addr, kernel_size)) {
+            tx_status("FAILflash write failure");
+            rx_cmd();
+            cprintf(" - FAIL\n");
+            return;
+        } else {
+            dprintf("partition '%s' updated\n", ptn->name);
+            cprintf(" - OKAY\n");
+        }
+        tx_status("OKAY");
+        rx_cmd();
+        return;
+    }
+    if(memcmp(cmdbuf, "boot", 4) == 0) {
+        if(init_boot_linux()) {
+            tx_status("FAILinvalid boot image");
+            rx_cmd();
+            return;
+        }
+        dprintf("booting linux...\n");
+        cprintf("\nbooting linux...\n");
+        tx_status("OKAY");
+        mdelay(10);
+        usb_shutdown();
+        boot_linux();
+        return;
+    }
+    if(memcmp(cmdbuf, "signature", 9) == 0) {
+        if (kernel_size != SIGNATURE_SIZE) {
+            tx_status("FAILsignature not 256 bytes long");
+            rx_cmd();
+            return;
+        }
+        memcpy(signature, (void*)kernel_addr, SIGNATURE_SIZE);
+        tx_status("OKAY");
+        rx_cmd();
+        return;
+    }
+
+    tx_status("FAILinvalid command");
+    rx_cmd();
+}
+
+void usb_status(unsigned online, unsigned highspeed)
+{
+    if(online) {
+        dprintf("usb: online (%s)\n", highspeed ? "highspeed" : "fullspeed");
+        rx_cmd();
+    }
+}
+
+void usbloader_init(void)
+{
+    usb_init();
+
+    ep1out = usb_endpoint_alloc(1, 0, 512);
+    ep1in = usb_endpoint_alloc(1, 1, 512);
+    rx_req = usb_request_alloc(4096);
+    tx_req = usb_request_alloc(4096);
+    cmdbuf = rx_req->buf;
+
+    boot_register_poll_func(usb_poll);
+}