summaryrefslogtreecommitdiff
path: root/arch_msm7k
diff options
context:
space:
mode:
Diffstat (limited to 'arch_msm7k')
-rw-r--r--arch_msm7k/Android.mk25
-rw-r--r--arch_msm7k/clock.c274
-rw-r--r--arch_msm7k/gpio.c181
-rw-r--r--arch_msm7k/hsusb.c453
-rw-r--r--arch_msm7k/mddi.c285
-rw-r--r--arch_msm7k/mddi_console.c153
-rw-r--r--arch_msm7k/nand.c630
-rw-r--r--arch_msm7k/shared.c197
-rw-r--r--arch_msm7k/smem.c94
-rw-r--r--arch_msm7k/uart.c124
-rw-r--r--arch_msm7k/vic.c111
11 files changed, 2527 insertions, 0 deletions
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;
+}
+