diff options
Diffstat (limited to 'arch_msm7k')
-rw-r--r-- | arch_msm7k/Android.mk | 25 | ||||
-rw-r--r-- | arch_msm7k/clock.c | 274 | ||||
-rw-r--r-- | arch_msm7k/gpio.c | 181 | ||||
-rw-r--r-- | arch_msm7k/hsusb.c | 453 | ||||
-rw-r--r-- | arch_msm7k/mddi.c | 285 | ||||
-rw-r--r-- | arch_msm7k/mddi_console.c | 153 | ||||
-rw-r--r-- | arch_msm7k/nand.c | 630 | ||||
-rw-r--r-- | arch_msm7k/shared.c | 197 | ||||
-rw-r--r-- | arch_msm7k/smem.c | 94 | ||||
-rw-r--r-- | arch_msm7k/uart.c | 124 | ||||
-rw-r--r-- | arch_msm7k/vic.c | 111 |
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; +} + |