From 4a8bada67103938110d4e4ab49175c02e36bb71f Mon Sep 17 00:00:00 2001 From: Andy Green Date: Fri, 28 Nov 2008 10:16:36 +0000 Subject: [PATCH] add-per-board-init-change-qi.patch Giant patch: - renames everything from kboot to qi - changes filenames accordingly in several places - fixes the linker script so stuff that does not execute from steppingstone context has real linked addresses in the relocated region, it means all code and pointers work now outside first 4KBytes - adds src/gta02/gta02.c to contain board-specific init and other functions - adds sophisticated structs to define most features in the board-specific files, including board type detection, board revision detection, and multiple kernel source definition (NAND, SD FAT, SD ext2, etc), including auto sequencing of trying the kernel sources in order (filesystems and partition support not done yet) - GTA02 detects itself by NOR presence and reports A5 / A6 - commandlines for kernel also come from board-specific kernel source definitions so correct kernel commandlines are provided depending on boot device -- on GTA02 now boots NAND kernel into NAND jffs2 filesystem - CRC32 is checked on loaded kernel image to make sure we know about corruption in bootloader Signed-off-by: Andy Green --- qiboot/Makefile | 22 +- qiboot/dfu-kboot | 7 - qiboot/dfu-qi | 7 + qiboot/include/device_configuration.h | 32 --- qiboot/include/neo_gta02.h | 4 + qiboot/include/qi-serial.h | 5 +- qiboot/include/qi.h | 47 ++++ qiboot/src/{start_kboot.c => gta02/gta02.c} | 174 +++++++++------ qiboot/src/lowlevel_init.S | 17 +- qiboot/src/mmc.c | 2 + qiboot/src/nand_read.c | 6 +- qiboot/src/phase2.c | 225 ++++++++++++-------- qiboot/src/{kboot-stage1.lds => qi.lds} | 21 +- qiboot/src/serial.c | 89 ++++---- qiboot/src/start.S | 43 +++- qiboot/src/start_qi.c | 108 ++++++++++ qiboot/src/utils.c | 104 ++++++++- 17 files changed, 619 insertions(+), 294 deletions(-) delete mode 100755 qiboot/dfu-kboot create mode 100755 qiboot/dfu-qi delete mode 100644 qiboot/include/device_configuration.h rename qiboot/src/{start_kboot.c => gta02/gta02.c} (64%) rename qiboot/src/{kboot-stage1.lds => qi.lds} (79%) create mode 100644 qiboot/src/start_qi.c diff --git a/qiboot/Makefile b/qiboot/Makefile index 22851f2..794748c 100644 --- a/qiboot/Makefile +++ b/qiboot/Makefile @@ -22,10 +22,10 @@ BUILD_BRANCH := $(shell git branch | grep ^\* | cut -d' ' -f2) BUILD_HEAD := $(shell git show --pretty=oneline | head -n1 | cut -d' ' -f1 | cut -b1-16) BUILD_VERSION := ${BUILD_BRANCH}_${BUILD_HEAD} -LDS = src/kboot-stage1.lds +LDS = src/qi.lds INCLUDE = include IMAGE_DIR = image -CFLAGS = -Wall -Werror -I $(INCLUDE) -g -c -O2 -fno-strict-aliasing \ +CFLAGS = -Wall -Werror -I $(INCLUDE) -g -c -Os -fno-strict-aliasing -mlong-calls \ -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding \ -march=armv4t -mno-thumb-interwork -Wstrict-prototypes \ -DBUILD_HOST="${BUILD_HOST}" -DBUILD_VERSION="${BUILD_VERSION}" \ @@ -34,7 +34,7 @@ LDFLAGS = #START = start.o lowlevel_init.o S_SRCS = src/start.S src/lowlevel_init.S S_OBJS = $(patsubst %.S,%.o, $(S_SRCS)) -C_SRCS = $(wildcard src/*.c) +C_SRCS = $(wildcard src/*.c) $(wildcard src/gt*/*.c) C_OBJS = $(patsubst %.c,%.o, $(C_SRCS)) #SRCS := $(START: .o=.S) $(COBJS: .o=.c) @@ -47,9 +47,9 @@ UDFU_VID = 0x1d50 UDFU_PID = 0x5119 UDFU_REV = 0x350 -TARGET = src/start_kboot_all -IMAGE = $(IMAGE_DIR)/kboot -UDFU_IMAGE = $(IMAGE_DIR)/kboot.udfu +TARGET = image/start_qi_all +IMAGE = $(IMAGE_DIR)/qi +UDFU_IMAGE = $(IMAGE_DIR)/qi.udfu %.o: %.S @$(CC) $(CFLAGS) -o $@ $< @@ -62,11 +62,11 @@ all:${UDFU_IMAGE} ${OBJS}:${SRCS} ${UDFU_IMAGE}:${OBJS} - $(LD) ${LDFLAGS} -T$(LDS) -g $(OBJS) -o ${TARGET} ${LIBS} - $(OBJCOPY) -O binary -S ${TARGET} ${IMAGE} - $(OBJDUMP) -D ${TARGET} >${IMAGE}.dis - $(MKUDFU) -v ${UDFU_VID} -p ${UDFU_PID} -r ${UDFU_REV} \ + @$(LD) ${LDFLAGS} -T$(LDS) -g $(OBJS) -o ${TARGET} ${LIBS} + @$(OBJCOPY) -O binary -S ${TARGET} ${IMAGE} + @$(MKUDFU) -v ${UDFU_VID} -p ${UDFU_PID} -r ${UDFU_REV} \ -d ${IMAGE} ${UDFU_IMAGE} + @$(OBJDUMP) -d ${TARGET} >${IMAGE}.dis blink_led:src/led_on.S $(CC) $(CFLAGS) led_on.o led_on.S @@ -74,4 +74,4 @@ blink_led:src/led_on.S $(OBJCOPY) -O binary -S led_on_temp.o $(IMAGE)/led_on clean: - rm -f src/*.o src/*~ include/*~ ${IMAGE}* ${TARGET} ${UDFU_IMAGE} + @rm -f src/*.o src/*~ include/*~ ${IMAGE}* ${TARGET} ${UDFU_IMAGE} diff --git a/qiboot/dfu-kboot b/qiboot/dfu-kboot deleted file mode 100755 index eb54a75..0000000 --- a/qiboot/dfu-kboot +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/kboot.udfu -if [ $? -eq 1 ] ; then -../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5120 -D image/kboot.udfu -../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/kboot.udfu -fi - diff --git a/qiboot/dfu-qi b/qiboot/dfu-qi new file mode 100755 index 0000000..1a4e497 --- /dev/null +++ b/qiboot/dfu-qi @@ -0,0 +1,7 @@ +#!/bin/bash +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/qi.udfu +if [ $? -eq 1 ] ; then +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5120 -D image/qi.udfu +../dfu-util/src/dfu-util -a 1 -d 0x1d50:0x5119 -D image/qi.udfu +fi + diff --git a/qiboot/include/device_configuration.h b/qiboot/include/device_configuration.h deleted file mode 100644 index deb7072..0000000 --- a/qiboot/include/device_configuration.h +++ /dev/null @@ -1,32 +0,0 @@ -/* define the easily changed settings for the device here */ - -#define CFG_LINUX_MACHINE_ID 1304 -#define CFG_LINUX_ATAG_ADDRESS 0x30000100 -#define CFG_NAND_OFFSET_FOR_KERNEL_PARTITION 0x80000 -/* - * we follow GTA02 layout actually to make life easier allowing NOR DFU during - * our initial development on GTA02 - */ -#define CFG_LINUX_CMDLINE_BACKUP "mtdparts=neo1973-nand:" \ - "0x00040000(kboot)," \ - "0x00040000(cmdline)," \ - "0x00800000(backupkernel)," \ - "0x000a0000(extra)," \ - "0x00040000(identity)," \ - "0x0f6a0000(backuprootfs) " \ - "rootfstype=jffs2 " \ - "root=/dev/mtdblock5 " \ - "console=ttySAC2,115200 " \ - "loglevel=4 " \ - "init=/sbin/init ro" - -#define CFG_LINUX_CMDLINE "rootfstype=ext2 " \ - "root=/dev/mmcblk0p1 " \ - "console=ttySAC2,115200 " \ - "loglevel=8 " \ - "init=/sbin/init ro" -#define CFG_LINUX_BIGGEST_KERNEL (4 * 1024 * 1024) -#define CFG_MACHINE_REVISION 0x350 -#define CFG_MEMORY_REGION_START 0x30000000 -#define CFG_MEMORY_REGION_SIZE (128 * 1024 * 1024) - diff --git a/qiboot/include/neo_gta02.h b/qiboot/include/neo_gta02.h index c126adb..7492630 100644 --- a/qiboot/include/neo_gta02.h +++ b/qiboot/include/neo_gta02.h @@ -22,6 +22,10 @@ #ifndef __CONFIG_H #define __CONFIG_H +#ifndef __ASM_MODE__ +#include +extern const struct board_api board_api_gta02; +#endif #define TEXT_BASE 0x33000000 diff --git a/qiboot/include/qi-serial.h b/qiboot/include/qi-serial.h index 732fe67..d674178 100644 --- a/qiboot/include/qi-serial.h +++ b/qiboot/include/qi-serial.h @@ -103,9 +103,8 @@ #define rGPJDAT (*(volatile unsigned *)0x560000d4) //Port J data #define rGPJUP (*(volatile unsigned *)0x560000d8) //Port J data -void port_init(void); -void serial_init (const int ubrdiv_val,const int uart); -void serial_putc (const int uart,const char c); +void serial_init(const int uart, const int ubrdiv_val); +void serial_putc(const int uart, const char c); int printk(const char *fmt, ...); int puts(const char *string); diff --git a/qiboot/include/qi.h b/qiboot/include/qi.h index 92d92ca..cc27c0c 100644 --- a/qiboot/include/qi.h +++ b/qiboot/include/qi.h @@ -30,6 +30,51 @@ #define u8 unsigned char typedef unsigned int uint32_t; +enum filesystem { + FS_RAW, + FS_FAT, + FS_EXT2 +}; + +/* describes a source for getting kernel image */ + +struct kernel_source { + const char *name; /* NULL name means invalid */ + int (*block_init)(void); + int (*block_read)(unsigned char * buf, unsigned long byte_start, + int count_bytes); + int partition_index; /* -1 means no partition table */ + int offset_if_no_partition; /* used if partition_index is -1 */ + enum filesystem filesystem; + const char * commandline; +}; + +/* describes a board variant, eg, PCB revision */ + +struct board_variant { + const char * name; + int machine_revision; /* passed in revision tag to linux */ +}; + +/* describes a "board", ie, a device like GTA02 including revisions */ + +struct board_api { + const char * name; + int debug_serial_port; + int linux_machine_id; + unsigned long linux_mem_start; + unsigned long linux_mem_size; + unsigned long linux_tag_placement; + const struct board_variant const * (*get_board_variant)(void); + int (*is_this_board)(void); + void (*port_init)(void); + struct kernel_source kernel_source[8]; +}; + +/* this is the board we are running on */ + +extern struct board_api const * this_board; + int printk(const char *fmt, ...); int vsprintf(char *buf, const char *fmt, va_list args); int puts(const char *string); @@ -37,6 +82,8 @@ void printhex(unsigned char v); void print32(unsigned int u); void hexdump(unsigned char *start, int len); unsigned int _ntohl(unsigned int n); +unsigned long crc32(unsigned long crc, const unsigned char *buf, + unsigned int len); #endif diff --git a/qiboot/src/start_kboot.c b/qiboot/src/gta02/gta02.c similarity index 64% rename from qiboot/src/start_kboot.c rename to qiboot/src/gta02/gta02.c index 8b5078c..066ed23 100644 --- a/qiboot/src/start_kboot.c +++ b/qiboot/src/gta02/gta02.c @@ -1,40 +1,19 @@ -/* - * (C) Copyright 2007 OpenMoko, Inc. - * Author: xiangfu liu - * Andy Green - * - * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* NOTE this stuff runs in steppingstone context! */ - - #include -#include "blink_led.h" -#include "nand_read.h" #include +#include "nand_read.h" -#define stringify2(s) stringify1(s) -#define stringify1(s) #s +static const struct board_variant board_variants[] = { + [0] = { + .name = "A5 PCB", + .machine_revision = 0x350, + }, + [1] = { + .name = "A6 PCB", + .machine_revision = 0x360, + } +}; -extern void bootloader_second_phase(void); - -void port_init(void) +void port_init_gta02(void) { //CAUTION:Follow the configuration order for setting the ports. // 1) setting value(GPnDAT) @@ -121,7 +100,7 @@ void port_init(void) /* * === PORT H GROUP * Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0 - * Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0 + * Signal : CLKOUT1 CLKOUT0 UCLK RXD2 TXD2 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0 * Binary : 10 , 10 10 , 11 11 , 10 10 , 10 10 , 10 10 */ /* pulldown on GPH08: UEXTCLK, just floats! @@ -145,42 +124,113 @@ void port_init(void) */ rGPJDAT |= (1 << 5); /* Set GPJ5 to high 3D RST */ + + serial_init(UART2, 0x11); } +/** + * returns PCB revision information in b9,b8 and b2,b1,b0 + * Pre-GTA02 A6 returns 0x000 + * GTA02 A6 returns 0x001 + */ - -void start_kboot(void) +int gta02_get_pcb_revision(void) { - void (*phase2)(void) = (void (*)(void))((int)bootloader_second_phase + - TEXT_BASE); + int n; + u32 u; - port_init(); - serial_init(UART2); + /* make C13 and C15 pulled-down inputs */ + rGPCCON &= ~0xcc000000; + rGPCUP &= ~((1 << 13) | (1 << 15)); + /* D0, D3 and D4 pulled-down inputs */ + rGPDCON &= ~0x000003c3; + rGPDUP &= ~((1 << 0) | (1 << 3) | (1 << 4)); - puts("Qi Bootloader "stringify2(BUILD_HOST)" " - stringify2(BUILD_VERSION)" " - stringify2(BUILD_DATE)); - puts("Copyright (C) 2008 Openmoko, Inc."); - puts("This is free software; see the source for copying conditions.\n" - "There is NO warranty; not even for MERCHANTABILITY or\n" - "FITNESS FOR A PARTICULAR PURPOSE.\n"); + /* delay after changing pulldowns */ + u = rGPCDAT; + u = rGPDDAT; + + /* read the version info */ + u = rGPCDAT; + n = (u >> (13 - 0)) & 0x001; + n |= (u >> (15 - 1)) & 0x002; + u = rGPDDAT; + n |= (u << (0 + 2)) & 0x004; + + n |= (u << (8 - 3)) & 0x100; + n |= (u << (9 - 4)) & 0x200; /* - * We got the first 4KBytes of the bootloader pulled into the - * steppingstone SRAM for free. Now we pull the whole bootloader - * image into SDRAM. - * - * So this doesn't trash position-dependent code, we took care in the - * linker script to arrange all rodata* segment content to be in the - * first 4K region. + * when not being interrogated, all of the revision GPIO + * are set to output HIGH without pulldown so no current flows + * if they are NC or pulled up. */ + /* make C13 and C15 high ouputs with no pulldowns */ + rGPCCON |= 0x44000000; + rGPCUP |= (1 << 13) | (1 << 15); + rGPCDAT |= (1 << 13) | (1 << 15); + /* D0, D3 and D4 high ouputs with no pulldowns */ + rGPDCON |= 0x00000141; + rGPDUP |= (1 << 0) | (1 << 3) | (1 << 4); + rGPDDAT |= (1 << 0) | (1 << 3) | (1 << 4); - /* We randomly pull 24KBytes of bootloader */ - if (nand_read_ll((unsigned char *)TEXT_BASE, 0, 24 * 1024) < 0) - while(1) - blink_led(); - /* - * jump to bootloader_second_phase() running from DRAM copy - */ - (phase2)(); + return n; } + + + +/* return nonzero if we believe we run on GTA02 */ + +int is_this_board_gta02(void) +{ + /* look for GTA02 NOR */ + + *(volatile unsigned short *)(0x18000000) = 0x98; + + return !!(*(volatile unsigned short *)(0x18000000) == 0x0020); +} + +const struct board_variant const * get_board_variant_gta02(void) +{ + return &board_variants[gta02_get_pcb_revision()]; +} + +/* + * our API for bootloader on this machine + */ + +const struct board_api board_api_gta02 = { + .name = "Freerunner / GTA02", + .debug_serial_port = 2, + .linux_machine_id = 1304, + .linux_mem_start = 0x30000000, + .linux_mem_size = (128 * 1024 * 1024), + .linux_tag_placement = 0x30000000 + 0x100, + .get_board_variant = get_board_variant_gta02, + .is_this_board = is_this_board_gta02, + .port_init = port_init_gta02, + /* these are the ways we could boot GTA02 in order to try */ + .kernel_source = { + [0] = { + .name = "NAND Kernel", + .block_read = nand_read_ll, + .partition_index = -1, + .offset_if_no_partition = 0x80000, + .filesystem = FS_RAW, + .commandline = "mtdparts=physmap-flash:-(nor);" \ + "neo1973-nand:" \ + "0x00040000(qi)," \ + "0x00040000(cmdline)," \ + "0x00800000(backupkernel)," \ + "0x000a0000(extra)," \ + "0x00040000(identity)," \ + "0x0f6a0000(backuprootfs) " \ + "rootfstype=jffs2 " \ + "root=/dev/mtdblock6 " \ + "console=ttySAC2,115200 " \ + "loglevel=4 " \ + "init=/sbin/init "\ + "ro" + }, + }, +}; diff --git a/qiboot/src/lowlevel_init.S b/qiboot/src/lowlevel_init.S index 4f20d5e..2a1654c 100644 --- a/qiboot/src/lowlevel_init.S +++ b/qiboot/src/lowlevel_init.S @@ -26,6 +26,7 @@ * #include * #include */ +#define __ASM_MODE__ #include /* @@ -125,10 +126,8 @@ .globl lowlevel_init lowlevel_init: - /* memory control configuration */ - /* make r0 relative the current location so that it */ - /* reads SMRDATA out of FLASH rather than memory ! */ - adr r0, SMRDATA + + ldr r0, =SMRDATA ldr r1, =BWSCON /* Bus Width Status Controller */ add r2, r0, #13*4 0: @@ -142,21 +141,11 @@ lowlevel_init: orr r1, r1, #0xc0000000 mcr p15, 0, r1, c1, c0, 0 - /* enable KEEPACT(GPJ8) to make sure PMU keeps us alive */ - ldr r0, =0x56000000 /* GPJ base */ - ldr r1, [r0, #0xd0] /* GPJCON */ - orr r1, r1, #(1 << 16) - str r1, [r0, #0xd0] - - ldr r1, [r0, #0xd4] /* GPJDAT */ - orr r1, r1, #(1 << 8) - str r1, [r0, #0xd4] /* everything is fine now */ mov pc, lr .ltorg /* the literal pools origin */ - SMRDATA: .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) diff --git a/qiboot/src/mmc.c b/qiboot/src/mmc.c index 39f1720..b982657 100644 --- a/qiboot/src/mmc.c +++ b/qiboot/src/mmc.c @@ -1,3 +1,4 @@ +#if 0 /* * u-boot S3C2410 MMC/SD card driver * (C) Copyright 2006 by OpenMoko, Inc. @@ -536,3 +537,4 @@ mmc2info(ulong addr) } #endif /* defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C) */ +#endif diff --git a/qiboot/src/nand_read.c b/qiboot/src/nand_read.c index bdd1b6a..6351173 100644 --- a/qiboot/src/nand_read.c +++ b/qiboot/src/nand_read.c @@ -89,8 +89,10 @@ static int nand_read_page_ll(unsigned char *buf, unsigned long addr) { unsigned short *ptr16 = (unsigned short *)buf; unsigned int i, page_num; +#if 0 unsigned char ecc[64]; unsigned short *p16 = (unsigned short *)ecc; +#endif nand_clear_RnB(); @@ -108,11 +110,11 @@ static int nand_read_page_ll(unsigned char *buf, unsigned long addr) for (i = 0; i < NAND_PAGE_SIZE/2; i++) *ptr16++ = NFDATA16; - +#if 0 for (i = 0; i < 64 / 2; i++) { *p16++ = NFDATA16; } - +#endif return NAND_PAGE_SIZE; } diff --git a/qiboot/src/phase2.c b/qiboot/src/phase2.c index 59a18f0..826e90e 100644 --- a/qiboot/src/phase2.c +++ b/qiboot/src/phase2.c @@ -31,111 +31,156 @@ #include #include "nand_read.h" -#include - -#define C1_DC (1<<2) /* dcache off/on */ -#define C1_IC (1<<12) /* icache off/on */ void bootloader_second_phase(void) { - image_header_t *hdr; - unsigned long i = 0; void (*the_kernel)(int zero, int arch, uint params); - struct tag * params_base = (struct tag *)CFG_LINUX_ATAG_ADDRESS; - struct tag *params = params_base; - const char * cmdline = CFG_LINUX_CMDLINE; - const char *p = cmdline; - void * kernel_nand = (void *)(TEXT_BASE - CFG_LINUX_BIGGEST_KERNEL); + int kernel = 0; + const struct board_variant * board_variant = + (this_board->get_board_variant)(); - puts("Checking kernel... "); + /* we try the possible kernels for this board in order */ - if (nand_read_ll(kernel_nand, CFG_NAND_OFFSET_FOR_KERNEL_PARTITION, - 4096) < 0) { - puts ("Kernel header read failed\n"); - goto unhappy; - } + while (this_board->kernel_source[kernel].name) { + const char * cmdline = this_board->kernel_source[kernel].commandline; + const char *p = cmdline; + struct tag *params = (struct tag *)this_board->linux_tag_placement; + void * kernel_dram = (void *)(TEXT_BASE - (8 * 1024 * 1024)); + unsigned long crc; + image_header_t *hdr; - hdr = (image_header_t *)kernel_nand; + /* eat leading white space */ + for (p = cmdline; *p == ' '; p++); - if (_ntohl(hdr->ih_magic) != IH_MAGIC) { - puts("Unknown image magic "); - print32(hdr->ih_magic); - goto unhappy; - } + puts("\nTrying kernel: "); + puts(this_board->kernel_source[kernel].name); + puts("\n"); - puts((const char *)hdr->ih_name); + /* if this device needs initializing, try to init it */ + if (this_board->kernel_source[kernel].block_init) + if ((this_board->kernel_source[kernel].block_init)()) { + puts("block device init failed\n"); + kernel++; + continue; + } - puts("Fetching kernel..."); + /* if there's a partition table implied, parse it, otherwise + * just use a fixed offset + */ + if (this_board->kernel_source[kernel].partition_index != -1) { - if (nand_read_ll(kernel_nand, CFG_NAND_OFFSET_FOR_KERNEL_PARTITION, - ((32 * 1024) + (_ntohl(hdr->ih_size) + sizeof(hdr) + 2048)) & + puts("partitions not supported yet\n"); + kernel++; + continue; + + } else { + if (this_board->kernel_source[kernel].block_read( + kernel_dram, this_board->kernel_source[kernel]. + offset_if_no_partition, 4096) < 0) { + puts ("Bad kernel header\n"); + kernel++; + continue; + } + + hdr = (image_header_t *)kernel_dram; + + if (_ntohl(hdr->ih_magic) != IH_MAGIC) { + puts("bad magic "); + print32(hdr->ih_magic); + kernel++; + continue; + } + + puts(" Found: "); + puts((const char *)hdr->ih_name); + puts("\n Size: 0x"); + print32(_ntohl(hdr->ih_size)); + + if (nand_read_ll(kernel_dram, + this_board->kernel_source[kernel]. + offset_if_no_partition, (_ntohl(hdr->ih_size) + + sizeof(image_header_t) + 2048) & ~(2048 - 1)) < 0) { - puts ("Kernel body read failed\n"); - goto unhappy; + puts ("Bad kernel read\n"); + kernel++; + continue; + } + } + + puts("\n Cmdline: "); + puts(p); + puts("\n"); + + /* + * It's good for now to know that our kernel is intact from + * the storage before we jump into it and maybe crash silently + * even though it costs us some time + */ + crc = crc32(0, kernel_dram + sizeof(image_header_t), + _ntohl(hdr->ih_size)); + if (crc != _ntohl(hdr->ih_dcrc)) { + puts("\nKernel CRC ERROR: read 0x"); + print32(crc); + puts(" vs hdr CRC 0x"); + print32(_ntohl(hdr->ih_dcrc)); + puts("\n"); + kernel++; + continue; + } + + the_kernel = (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 = board_variant->machine_revision; + params = tag_next(params); + + /* memory tags */ + params->hdr.tag = ATAG_MEM; + params->hdr.size = tag_size (tag_mem32); + params->u.mem.start = this_board->linux_mem_start; + params->u.mem.size = this_board->linux_mem_size; + params = tag_next(params); + + /* kernel commandline */ + + 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 ("Starting --->\n\n"); + + /* + * ooh that's it, we're gonna try boot this image! + * never mind the cache, Linux will take care of it + */ + the_kernel(0, this_board->linux_machine_id, + this_board->linux_tag_placement); + + /* we won't come back here no matter what */ } - puts(" Done"); + /* none of the kernels worked out */ - the_kernel = (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 = CFG_MACHINE_REVISION; - params = tag_next (params); - - /* memory tags */ - params->hdr.tag = ATAG_MEM; - params->hdr.size = tag_size (tag_mem32); - params->u.mem.start = CFG_MEMORY_REGION_START; - params->u.mem.size = CFG_MEMORY_REGION_SIZE; - 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! */ - - the_kernel(0, CFG_LINUX_MACHINE_ID, (unsigned int)params_base); - - /* that didn't quite pan out */ - -unhappy: + puts("No usable kernel image found, we've had it :-(\n"); while (1) blue_on(1); } diff --git a/qiboot/src/kboot-stage1.lds b/qiboot/src/qi.lds similarity index 79% rename from qiboot/src/kboot-stage1.lds rename to qiboot/src/qi.lds index 5c8d50c..29ec63f 100644 --- a/qiboot/src/kboot-stage1.lds +++ b/qiboot/src/qi.lds @@ -37,24 +37,19 @@ SECTIONS . = ALIGN(4); .text : { - src/start.o (.text .rodata* .data) - src/lowlevel_init.o(.text .rodata* .data) - src/start_kboot.o (.text .rodata* .data) - src/serial.o (.text .rodata* .data) + src/start.o (.text .rodata* .data) + src/lowlevel_init.o (.text .rodata* .data) + src/start_qi.o (.text .rodata* .data) src/blink_led.o (.text .rodata* .data) - * (.rodata* .data) + src/nand_read.o (.text .rodata* .data) + src/serial.o (.text .rodata* .data) } . = ALIGN(4); - .everything_else : { *(.text) } + .everything_else ADDR (.text) + SIZEOF (.text) + 0x33000000 : + AT ( ADDR (.text) + SIZEOF (.text) ) { *(.text .rodata* .data) } - . = ALIGN(4); - .got : - { - *(.got) - } - - . = 0x32000000 ; + . = 0x33800000 ; __bss_start = .; .bss (NOLOAD) : { diff --git a/qiboot/src/serial.c b/qiboot/src/serial.c index 19fb850..61b4762 100644 --- a/qiboot/src/serial.c +++ b/qiboot/src/serial.c @@ -23,55 +23,54 @@ #include #include "blink_led.h" -void serial_init (const int uart) +void serial_init (const int uart, const int ubrdiv_val) { - int ubrdiv_val = 0x11; - switch(uart) - { - case UART0: - rULCON0 = 0x3; - rUCON0 = 0x245; - rUFCON0 = 0x0; - rUMCON0 = 0x0; - rUBRDIV0 = ubrdiv_val; - break; - case UART1: - rULCON1 = 0x3; - rUCON1 = 0x245; - rUFCON1 = 0x0; - rUMCON1 = 0x0; - rUBRDIV1 = ubrdiv_val; - break; - case UART2: - rULCON2 = 0x3; - rUCON2 = 0x245; - rUFCON2 = 0x1; - rUBRDIV2 = ubrdiv_val; - break; - default: - break; - } + switch(uart) + { + case UART0: + rULCON0 = 0x3; + rUCON0 = 0x245; + rUFCON0 = 0x0; + rUMCON0 = 0x0; + rUBRDIV0 = ubrdiv_val; + break; + case UART1: + rULCON1 = 0x3; + rUCON1 = 0x245; + rUFCON1 = 0x0; + rUMCON1 = 0x0; + rUBRDIV1 = ubrdiv_val; + break; + case UART2: + rULCON2 = 0x3; + rUCON2 = 0x245; + rUFCON2 = 0x1; + rUBRDIV2 = ubrdiv_val; + break; + default: + break; + } } /* * Output a single byte to the serial port. */ -void serial_putc (const int uart,const char c) +void serial_putc (const int uart, const char c) { - switch(uart) - { - case UART0: - while ( !( rUTRSTAT0 & 0x2 ) ); - WrUTXH0(c); - break; - case UART1: - while ( !( rUTRSTAT1 & 0x2 ) ); - WrUTXH1(c); - break; - case UART2: - while ( !( rUTRSTAT2 & 0x2 ) ); - WrUTXH2(c); - break; - default: - break; - } + switch(uart) + { + case UART0: + while ( !( rUTRSTAT0 & 0x2 ) ); + WrUTXH0(c); + break; + case UART1: + while ( !( rUTRSTAT1 & 0x2 ) ); + WrUTXH1(c); + break; + case UART2: + while ( !( rUTRSTAT2 & 0x2 ) ); + WrUTXH2(c); + break; + default: + break; + } } diff --git a/qiboot/src/start.S b/qiboot/src/start.S index 1d2ee92..3a98bef 100644 --- a/qiboot/src/start.S +++ b/qiboot/src/start.S @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ + +#define __ASM_MODE__ #include .globl _start @@ -119,11 +121,39 @@ start_code: ldr r1, =0x7fff0 /* all clocks on */ str r1, [r0] - /* gpio UART0 init */ + /* gpio UART2 init, H port */ ldr r0, =0x56000070 - ldr r1, =0x2afaaa + ldr r1, =0x001AAAAA str r1, [r0] + /* enable KEEPACT(GPJ8) to make sure PMU keeps us alive */ + ldr r0, =0x56000000 /* GPJ base */ + ldr r1, [r0, #0xd0] /* GPJCON */ + orr r1, r1, #(1 << 16) + str r1, [r0, #0xd0] + + ldr r1, [r0, #0xd4] /* GPJDAT */ + orr r1, r1, #(1 << 8) + str r1, [r0, #0xd4] + + + /* init uart2 */ + ldr r0, =0x50008000 + mov r1, #0x03 + str r1, [r0] + ldr r1, =0x245 + str r1, [r0, #0x04] + mov r1, #0x00 + str r1, [r0, #0x08] + mov r1, #0x00 + str r1, [r0, #0x0c] + mov r1, #0x11 + str r1, [r0, #0x28] + + ldr r0, =0x50008000 + ldr r1, =0x54 + str r1, [r0, #0x20] + bl cpu_init_crit /* reset nand controller, or it is dead to us */ @@ -140,11 +170,12 @@ start_code: /* >> CFG_VIDEO_LOGO_MAX_SIZE */ #define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ sub sp, r0, #12 /* leave 3 words for abort-stack */ - +#if 0 clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ @@ -155,13 +186,14 @@ clbss_l: add r0, r0, #4 cmp r0, r1 ble clbss_l +#endif /* we are going to jump into the C part of the init now */ - +spin: ldr pc, _start_armboot _start_armboot: - .word start_kboot + .word start_qi /* ************************************************************************* @@ -175,6 +207,7 @@ _start_armboot: */ cpu_init_crit: + /* * flush v4 I/D caches */ diff --git a/qiboot/src/start_qi.c b/qiboot/src/start_qi.c new file mode 100644 index 0000000..f0cdeaf --- /dev/null +++ b/qiboot/src/start_qi.c @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: xiangfu liu + * Andy Green + * + * Configuation settings for the OPENMOKO Neo GTA02 Linux GSM phone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* NOTE this stuff runs in steppingstone context! */ + + +#include +#include "blink_led.h" +#include "nand_read.h" +#include + +#define stringify2(s) stringify1(s) +#define stringify1(s) #s + +extern void bootloader_second_phase(void); + +const struct board_api * boards[] = { + &board_api_gta02 +}; + +struct board_api const * this_board; + +void start_qi(void) +{ + int n = 0; + int board = 0; + const struct board_variant * board_variant; + /* + * We got the first 4KBytes of the bootloader pulled into the + * steppingstone SRAM for free. Now we pull the whole bootloader + * image into SDRAM. + * + * So this doesn't trash position-dependent code, we took care in the + * linker script to arrange all rodata* segment content to be in the + * first 4K region. + */ + + /* We randomly pull 24KBytes of bootloader */ + if (nand_read_ll((unsigned char *)TEXT_BASE, 0, 24 * 1024) < 0) + goto unhappy; + + /* ask all the boards we support in turn if they recognize this + * hardware we are running on, accept the first positive answer + */ + + this_board = boards[board]; + while (!n) { + if (board >= (sizeof(boards) / sizeof(boards[0]))) + /* can't put diagnostic on serial... too early */ + goto unhappy; + + if (this_board->is_this_board()) + n = 1; + else + this_board = boards[board++]; + } + + /* okay, do the critical port and serial init for our board */ + + this_board->port_init(); + + /* stick some hello messages on debug console */ + + puts("\n\n\nQi Bootloader "stringify2(BUILD_HOST)" " + stringify2(BUILD_VERSION)" " + stringify2(BUILD_DATE)"\n"); + + puts("Copyright (C) 2008 Openmoko, Inc.\n"); + puts("This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or " + "FITNESS FOR A PARTICULAR PURPOSE.\n\n Detected: "); + + puts(this_board->name); + puts(", "); + board_variant = (this_board->get_board_variant)(); + puts(board_variant->name); + puts("\n"); + + /* + * jump to bootloader_second_phase() running from DRAM copy + */ + bootloader_second_phase(); + +unhappy: + while(1) + blink_led(); + +} diff --git a/qiboot/src/utils.c b/qiboot/src/utils.c index 55fc3f1..45605af 100644 --- a/qiboot/src/utils.c +++ b/qiboot/src/utils.c @@ -23,8 +23,6 @@ #include #include -#define DEBUG_CONSOLE_UART UART2 - size_t strlen(const char *s) { size_t n = 0; @@ -41,6 +39,7 @@ char *strcpy(char *dest, const char *src) while (*src) *dest++ = *src++; + *dest = '\0'; return dest_orig; } @@ -53,8 +52,7 @@ unsigned int _ntohl(unsigned int n) { int puts(const char *string) { while (*string) - serial_putc(DEBUG_CONSOLE_UART, *string++); - serial_putc(DEBUG_CONSOLE_UART, '\n'); + serial_putc(this_board->debug_serial_port, *string++); return 1; } @@ -63,9 +61,9 @@ int puts(const char *string) void printnybble(unsigned char n) { if (n < 10) - serial_putc(DEBUG_CONSOLE_UART, '0' + n); + serial_putc(this_board->debug_serial_port, '0' + n); else - serial_putc(DEBUG_CONSOLE_UART, 'a' + n - 10); + serial_putc(this_board->debug_serial_port, 'a' + n - 10); } void printhex(unsigned char n) @@ -88,14 +86,100 @@ void hexdump(unsigned char *start, int len) while (len > 0) { print32((int)start); - serial_putc(DEBUG_CONSOLE_UART, ':'); - serial_putc(DEBUG_CONSOLE_UART, ' '); + serial_putc(this_board->debug_serial_port, ':'); + serial_putc(this_board->debug_serial_port, ' '); for (n = 0; n < 16; n++) { printhex(*start++); - serial_putc(DEBUG_CONSOLE_UART, ' '); + serial_putc(this_board->debug_serial_port, ' '); } - serial_putc(DEBUG_CONSOLE_UART, '\n'); + serial_putc(this_board->debug_serial_port, '\n'); len -= 16; } } +/* original copyright notice for this crc code (it is from U-Boot) --> */ +/* + * This file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const unsigned long crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +unsigned long crc32(unsigned long crc, const unsigned char *buf, + unsigned int len) +{ + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) + do { + DO1(buf); + } while (--len); + + return crc ^ 0xffffffffL; +}