From f26f60b0ac1dd815cfd167bfff557a9c28368492 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Wed, 13 Aug 2008 00:42:35 +0100 Subject: [PATCH] fix-nand.patch NAND stuff wasn't going to do anything until the controller in the CPU was reset. NAND code was cleaned and other minor meddlings Signed-off-by: Andy Green --- qiboot/src/kboot-stage1.lds | 1 + qiboot/src/lowlevel_init.S | 3 + qiboot/src/nand_read.c | 93 +++++++++++++++------- qiboot/src/phase2.c | 154 ++++++++++++++++++++++++++++++++++++ qiboot/src/start.S | 13 +++ qiboot/src/start_kboot.c | 42 ++++++---- 6 files changed, 263 insertions(+), 43 deletions(-) create mode 100644 qiboot/src/phase2.c diff --git a/qiboot/src/kboot-stage1.lds b/qiboot/src/kboot-stage1.lds index 1998807..551d354 100644 --- a/qiboot/src/kboot-stage1.lds +++ b/qiboot/src/kboot-stage1.lds @@ -35,6 +35,7 @@ SECTIONS src/start.o (.text) src/lowlevel_init.o(.text) src/start_kboot.o (.text) + src/start_kboot.o (.rodata) *(.text) *(.rodata) } diff --git a/qiboot/src/lowlevel_init.S b/qiboot/src/lowlevel_init.S index dcb3adf..4f20d5e 100644 --- a/qiboot/src/lowlevel_init.S +++ b/qiboot/src/lowlevel_init.S @@ -19,6 +19,9 @@ * MA 02111-1307 USA */ +/* NOTE this stuff runs in steppingstone context! */ + + /* * #include * #include diff --git a/qiboot/src/nand_read.c b/qiboot/src/nand_read.c index 8a5778a..8deadb7 100644 --- a/qiboot/src/nand_read.c +++ b/qiboot/src/nand_read.c @@ -15,7 +15,11 @@ * Author: Harald Welte */ +/* NOTE this stuff runs in steppingstone context! */ + + #include "nand_read.h" +#include "kboot.h" #define NAND_CMD_READ0 0 #define NAND_CMD_READSTART 0x30 @@ -67,6 +71,14 @@ static int is_bad_block(unsigned long i) NFCMD = NAND_CMD_READSTART; nand_wait(); data = (NFDATA & 0xff); +#ifdef DEBUG + serial_putc(2, '$'); + serial_putc(2, '0'); + serial_putc(2, 'x'); + print32((unsigned int)data); + serial_putc(2, ' '); +#endif + if (data != 0xff) return 1; @@ -103,38 +115,65 @@ static int nand_read_page_ll(unsigned char *buf, unsigned long addr) /* low level nand read function */ int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { - int i, j; - int bad_count = 0; + int i, j; + int bad_count = 0; - if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) - return -1; /* invalid alignment */ + if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) + return -1; /* invalid alignment */ - /* chip Enable */ - nand_select(); - nand_clear_RnB(); - for (i=0; i<10; i++); + /* chip Enable */ + nand_select(); + nand_clear_RnB(); - for (i=start_addr; i < (start_addr + size);) { - if (i % NAND_BLOCK_SIZE == 0) { - if (is_bad_block(i) || - is_bad_block(i + NAND_PAGE_SIZE)) { - i += NAND_BLOCK_SIZE; - size += NAND_BLOCK_SIZE; - if(bad_count++ == 4) { - return -1; + for (i = 0; i < 10; i++) + ; + + for (i = start_addr; i < (start_addr + size);) { +#ifdef DEBUG + serial_putc(2, 'i'); + serial_putc(2, '0'); + serial_putc(2, 'x'); + print32((unsigned int)i); + serial_putc(2, ' '); +#endif + if (i % NAND_BLOCK_SIZE == 0) { + if (is_bad_block(i) || + is_bad_block(i + NAND_PAGE_SIZE)) { +#ifdef DEBUG + serial_putc(2, '?'); +#endif + i += NAND_BLOCK_SIZE; + size += NAND_BLOCK_SIZE; + if (bad_count++ == 4) { +#ifdef DEBUG + serial_putc(2, '+'); + serial_putc(2, '\n'); +#endif + return -1; + } + serial_putc(2, '\n'); + continue; + } + } + + j = nand_read_page_ll(buf, i); +#ifdef DEBUG + serial_putc(2, 'j'); + serial_putc(2, '0'); + serial_putc(2, 'x'); + print32((unsigned int)j); + serial_putc(2, ' '); +#endif + i += j; + buf += j; +#if DEBUG + serial_putc(2, '\n'); +#endif } - continue; - } - } - j = nand_read_page_ll(buf, i); - i += j; - /* buf += j;*/ - } + /* chip Disable */ + nand_deselect(); - /* chip Disable */ - nand_deselect(); - - return 0; + return 0; } diff --git a/qiboot/src/phase2.c b/qiboot/src/phase2.c new file mode 100644 index 0000000..75ae2fd --- /dev/null +++ b/qiboot/src/phase2.c @@ -0,0 +1,154 @@ +#include "kboot.h" +#include +#include "blink_led.h" +#include +#define __ARM__ +#include +#define u32 unsigned int +#define u16 unsigned short +#define u8 unsigned char +typedef unsigned int uint32_t; + +#include +#include "nand_read.h" + +/* See also ARM920T Technical reference Manual */ +#define C1_MMU (1<<0) /* mmu off/on */ +#define C1_ALIGN (1<<1) /* alignment faults off/on */ +#define C1_DC (1<<2) /* dcache off/on */ + +#define C1_BIG_ENDIAN (1<<7) /* big endian off/on */ +#define C1_SYS_PROT (1<<8) /* system protection */ +#define C1_ROM_PROT (1<<9) /* ROM protection */ +#define C1_IC (1<<12) /* icache off/on */ +#define C1_HIGH_VECTORS (1<<13) /* location of vectors: low/high addresses */ + +size_t strlen(const char *s) +{ + size_t n = 0; + + while (*s++) + n++; + + return n; +} + +char *strcpy(char *dest, const char *src) +{ + char * dest_orig = dest; + + while (*src) + *dest++ = *src++; + + return dest_orig; +} + +unsigned int _ntohl(unsigned int n) { + return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | + ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24); +} + +void bootloader_second_phase(void) +{ + image_header_t *hdr; + unsigned long i = 0; + int machid = 1304; /* GTA02 */ + void (*theKernel)(int zero, int arch, uint params); + struct tag * params_base = (struct tag *)0x30000100; /* atags need to live here */ + struct tag *params = params_base; + const char * cmdline = "rootfstype=ext2 root=/dev/mmcblk0p1 console=ttySAC2,115200 loglevel=8 init=/sbin/init ro"; + const char *p = cmdline; + void * kernel_nand = (void *)(TEXT_BASE - 4 * 1024 * 1024); + + puts("Checking kernel... "); + + if (nand_read_ll(kernel_nand, 0x80000, 4096) < 0) { + puts ("Kernel header read failed\n"); + goto unhappy; + } + + hdr = (image_header_t *)kernel_nand; + + if (_ntohl(hdr->ih_magic) != IH_MAGIC) { + puts("Unknown image magic "); + print32(hdr->ih_magic); + goto unhappy; + } + + puts((const char *)hdr->ih_name); + + puts("Fetching kernel..."); + + if (nand_read_ll(kernel_nand, 0x80000, ((32 * 1024) + + (_ntohl(hdr->ih_size) + + sizeof(hdr) + 2048)) & + ~(2048 - 1)) < 0) { + puts ("Kernel body read failed\n"); + goto unhappy; + } + + puts(" Done"); + + theKernel = (void (*)(int, int, uint)) + (((char *)hdr) + sizeof(image_header_t)); + + /* first tag */ + params->hdr.tag = ATAG_CORE; + params->hdr.size = tag_size (tag_core); + params->u.core.flags = 0; + params->u.core.pagesize = 0; + params->u.core.rootdev = 0; + params = tag_next (params); + + /* revision tag */ + params->hdr.tag = ATAG_REVISION; + params->hdr.size = tag_size (tag_revision); + params->u.revision.rev = 0x350; + params = tag_next (params); + + /* memory tags */ + params->hdr.tag = ATAG_MEM; + params->hdr.size = tag_size (tag_mem32); + params->u.mem.start = 0x30000000; + params->u.mem.size = 128 * 1024 * 1024; + params = tag_next (params); + + /* kernel commandline */ + /* eat leading white space */ + for (p = cmdline; *p == ' '; p++); + + if (*p) { + params->hdr.tag = ATAG_CMDLINE; + params->hdr.size = + (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2; + strcpy (params->u.cmdline.cmdline, p); + params = tag_next (params); + } + + /* needs to always be the last tag */ + params->hdr.tag = ATAG_NONE; + params->hdr.size = 0; + + puts ("Running Linux...\n\n"); + + /* trash the cache */ + + /* turn off I/D-cache */ + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + i &= ~(C1_DC | C1_IC); + asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); + + /* flush I/D-cache */ + i = 0; + asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); + + /* ooh that's it, we're gonna try boot this image! */ + + theKernel(0, machid, (unsigned int)params_base); + + /* that didn't quite pan out */ + +unhappy: + while (1) + blue_on(1); +} diff --git a/qiboot/src/start.S b/qiboot/src/start.S index 5f956ed..c16a2a0 100644 --- a/qiboot/src/start.S +++ b/qiboot/src/start.S @@ -140,6 +140,19 @@ start_code: str r1, [r0, #0x28] */ bl cpu_init_crit + +/* reset nand controller, or it is dead to us */ + + mov r1, #0x4E000000 + ldr r2, =0xfff0 @ initial value tacls=3,rph0=7,rph1=7 + ldr r3, [r1, #0] + orr r3, r3, r2 + str r3, [r1, #0] + + ldr r3, [r1, #4] + orr r3, r3, #1 @ enable nand controller + str r3, [r1, #4] + /* >> CFG_VIDEO_LOGO_MAX_SIZE */ #define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ stack_setup: diff --git a/qiboot/src/start_kboot.c b/qiboot/src/start_kboot.c index 8b46919..b4256d2 100644 --- a/qiboot/src/start_kboot.c +++ b/qiboot/src/start_kboot.c @@ -19,9 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ + +/* NOTE this stuff runs in steppingstone context! */ + + #include "blink_led.h" #include "nand_read.h" #include "kboot.h" +#include + /* unsigned char buf[]={ 0x0d,0xc0,0xa0,0xe1,0x00,0xd8,0x2d,0xe9,0x04,0xb0,0x4c,0xe2,0x4c,0x20,0x9f,0xe5, @@ -33,21 +39,20 @@ unsigned char buf[]={ 0x10,0x00,0x00,0x56,0x18,0x00,0x00,0x56,0xff,0xff,0x00,0x00,0x14,0x00,0x00,0x56, 0x01,0x00,0x50,0xe2,0xfd,0xff,0xff,0x1a,0x0e,0xf0,0xa0,0xe1,0x0a}; */ -unsigned char buf[2*1024]; - -#define ADDR ((volatile unsigned *)&buf) #define stringify(x) #x -static char * hello = "hello"; +extern void bootloader_second_phase(void); -int start_kboot(void) +void start_kboot(void) { - static int n = 0; - void (*p)(unsigned int) = print32; + void (*phase2)(void) = bootloader_second_phase + TEXT_BASE; port_init(); serial_init(0x11, UART2); + puts("Openmoko KBOOT BUILD_HOST BUILD_VERSION BUILD_DATE\n"); + +#if 0 while(1) { serial_putc(2, '0'); serial_putc(2, 'x'); @@ -63,21 +68,26 @@ int start_kboot(void) serial_putc(2, '\n'); - -// printk("Openmoko KBOOT "stringify(BUILD_HOST)" "stringify(BUILD_VERSION)" "stringify(BUILD_DATE)"\n"); blue_on(1); n++; } - /*2. test nand flash */ - if(nand_read_ll(buf, 0x000, sizeof(buf))==-1) +#endif + + /* + * pull the whole U-Boot image into SDRAM + */ + + if (nand_read_ll((unsigned char *)TEXT_BASE, 0, 256 * 1024) < 0) while(1) blink_led(); - asm volatile("mov pc, %0\n" - : /* output */ - :"r"(ADDR) /* input */ - ); + serial_putc(2, '0'); + serial_putc(2, 'x'); + print32((unsigned int)bootloader_second_phase); + serial_putc(2, ' '); + serial_putc(2, '\n'); - return 0; + + (phase2)(); }