[PATCH 4/7] add-per-board-init-change-qi.patch

xiangfu xiangfu at openmoko.org
Mon Aug 18 12:58:59 CEST 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


really nice code.


Andy Green wrote:
> 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 <andy at openmoko.com>
> ---
> 
>  Makefile                       |   22 ++--
>  dfu-kboot                      |    7 -
>  dfu-qi                         |    7 +
>  include/device_configuration.h |   32 -----
>  include/neo_gta02.h            |    4 +
>  include/qi-serial.h            |    5 -
>  include/qi.h                   |   47 ++++++++
>  src/gta02/gta02.c              |  236 +++++++++++++++++++++++++++++++++++++++
>  src/kboot-stage1.lds           |   64 -----------
>  src/lowlevel_init.S            |   17 +--
>  src/mmc.c                      |    2 
>  src/nand_read.c                |    6 +
>  src/phase2.c                   |  239 ++++++++++++++++++++++++----------------
>  src/qi.lds                     |   59 ++++++++++
>  src/serial.c                   |   89 +++++++--------
>  src/start.S                    |   43 ++++++-
>  src/start_kboot.c              |  186 -------------------------------
>  src/start_qi.c                 |  108 ++++++++++++++++++
>  src/utils.c                    |  104 ++++++++++++++++-
>  19 files changed, 801 insertions(+), 476 deletions(-)
>  delete mode 100755 dfu-kboot
>  create mode 100755 dfu-qi
>  delete mode 100644 include/device_configuration.h
>  create mode 100644 src/gta02/gta02.c
>  delete mode 100644 src/kboot-stage1.lds
>  create mode 100644 src/qi.lds
>  delete mode 100644 src/start_kboot.c
>  create mode 100644 src/start_qi.c
> 
> diff --git a/Makefile b/Makefile
> index 22851f2..794748c 100644
> --- a/Makefile
> +++ b/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/dfu-kboot b/dfu-kboot
> deleted file mode 100755
> index eb54a75..0000000
> --- a/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/dfu-qi b/dfu-qi
> new file mode 100755
> index 0000000..1a4e497
> --- /dev/null
> +++ b/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/include/device_configuration.h b/include/device_configuration.h
> deleted file mode 100644
> index deb7072..0000000
> --- a/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/include/neo_gta02.h b/include/neo_gta02.h
> index c126adb..7492630 100644
> --- a/include/neo_gta02.h
> +++ b/include/neo_gta02.h
> @@ -22,6 +22,10 @@
>  
>  #ifndef __CONFIG_H
>  #define __CONFIG_H
> +#ifndef __ASM_MODE__
> +#include <qi.h>
> +extern const struct board_api board_api_gta02;
> +#endif
>  
>  #define TEXT_BASE 0x33000000
>  
> diff --git a/include/qi-serial.h b/include/qi-serial.h
> index 732fe67..d674178 100644
> --- a/include/qi-serial.h
> +++ b/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/include/qi.h b/include/qi.h
> index 92d92ca..cc27c0c 100644
> --- a/include/qi.h
> +++ b/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/src/gta02/gta02.c b/src/gta02/gta02.c
> new file mode 100644
> index 0000000..066ed23
> --- /dev/null
> +++ b/src/gta02/gta02.c
> @@ -0,0 +1,236 @@
> +#include <qi.h>
> +#include <neo_gta02.h>
> +#include "nand_read.h"
> +
> +static const struct board_variant board_variants[] = {
> +	[0] = {
> +		.name = "A5 PCB",
> +		.machine_revision = 0x350,
> +	},
> +	[1] = {
> +		.name = "A6 PCB",
> +		.machine_revision = 0x360,
> +	}
> +};
> +
> +void port_init_gta02(void)
> +{
> +    //CAUTION:Follow the configuration order for setting the ports.
> +    // 1) setting value(GPnDAT)
> +    // 2) setting control register  (GPnCON)
> +    // 3) configure pull-up resistor(GPnUP)
> +
> +    /* 32bit data bus configuration   */
> +	/*
> +	 * === PORT A GROUP
> +	 *     Ports  : GPA22 GPA21  GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12
> +	 *     Signal : nFCE nRSTOUT nFRE   nFWE  ALE   CLE  nGCS5 nGCS4 nGCS3 nGCS2 nGCS1
> +	 *     Binary :  1     1      1  , 1   1   1    1   ,  1     1     1     1
> +	 *     Ports  : GPA11   GPA10  GPA9   GPA8   GPA7   GPA6   GPA5   GPA4   GPA3   GPA2   GPA1  GPA0
> +	 *     Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0
> +	 *     Binary :  1       1      1      1   , 1       1      1      1   ,  1       1     1      1
> +	 */
> +	rGPACON = 0x007E5FFF;
> +	rGPADAT |= (1 << 16);      /* Set GPA16 to high (nNAND_WP) */
> +	/*
> +	 * ===* PORT B GROUP
> +	 *      Ports  : GPB10    GPB9    GPB8    GPB7    GPB6     GPB5    GPB4   GPB3   GPB2     GPB1      GPB0
> +	 *      Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard
> +	 *      Setting: INPUT  OUTPUT   INPUT  OUTPUT   INPUT   OUTPUT   OUTPUT OUTPUT OUTPUT   OUTPUT    OUTPUT
> +	 *      Binary :   00  ,  01       00  ,   01      00   ,  01       01  ,   01     01   ,  01        01
> +	 */
> +	rGPBCON = 0x00155555;
> +	rGPBUP = 0x000007FF;
> +	/*
> +	 * === PORT C GROUP
> +	 *     Ports  : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8  GPC7   GPC6   GPC5 GPC4 GPC3  GPC2  GPC1 GPC0
> +	 *     Signal : VD7   VD6   VD5   VD4   VD3   VD2   VD1  VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND
> +	 *     Binary :  10   10  , 10    10  , 10    10  , 10   10  , 10     10  ,  10   10 , 10     10 , 10   10
> +	 */
> +	rGPCCON = 0x55555155;
> +	rGPCUP = 0x0000FFFF & ~(1 << 5);
> +	rGPCDAT |= (1 << 13) | (1 << 15); /* index detect -> hi */
> +	/*
> +	 * === PORT D GROUP
> +	 *     Ports  : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
> +	 *     Signal : VD23  VD22  VD21  VD20  VD19  VD18  VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9  VD8
> +	 *     Binary : 10    10  , 10    10  , 10    10  , 10   10 , 10   10 , 10   10 , 10   10 ,10   10
> +	 */
> +	rGPDCON = 0x55555555;
> +	rGPDUP = 0x0000FFFF;
> +	rGPDDAT |= (1 << 0) | (1 << 3) | (1 << 4); /* index detect -> hi */
> +	/*
> +	 * === PORT E GROUP
> +	 *     Ports  : GPE15  GPE14 GPE13   GPE12   GPE11   GPE10   GPE9    GPE8     GPE7  GPE6  GPE5   GPE4
> +	 *     Signal : IICSDA IICSCL SPICLK SPIMOSI SPIMISO SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK I2SSDO
> +	 *     Binary :  10     10  ,  10      10  ,  10      10   ,  10      10   ,   10    10  , 10     10  ,
> +	 *     -------------------------------------------------------------------------------------------------------
> +	 *     Ports  :  GPE3   GPE2  GPE1    GPE0
> +	 *     Signal : I2SSDI CDCLK I2SSCLK I2SLRCK
> +	 *     Binary :  10     10  ,  10      10
> +	 */
> +	rGPECON = 0xAAAAAAAA;
> +	rGPEUP = 0x0000FFFF & ~(1 << 11);
> +	/*
> +	 * === PORT F GROUP
> +	 *     Ports  : GPF7   GPF6   GPF5   GPF4      GPF3     GPF2  GPF1   GPF0
> +	 *     Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0
> +	 *     Setting: Output Output Output Output    EINT3    EINT2 EINT1  EINT0
> +	 *     Binary :  01      01 ,  01     01  ,     10       10  , 10     10
> +	 */
> +	/* pulldown on GPF03: TP-4705+debug - debug conn will float */
> +	rGPFCON = 0x0000AAAA;
> +	rGPFUP = 0x000000FF & ~(1 << 3);
> +
> +
> +	/*
> +	 * === PORT G GROUP
> +	 *     Ports  : GPG15 GPG14 GPG13 GPG12 GPG11    GPG10    GPG9     GPG8     GPG7      GPG6
> +	 *     Signal : nYPON  YMON nXPON XMON  EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI
> +	 *     Setting: nYPON  YMON nXPON XMON  EINT19  Output   Output   Output   SPICLK1    SPIMOSI1
> +	 *     Binary :   11    11 , 11    11  , 10      01    ,   01       01   ,    11         11
> +	 *     -----------------------------------------------------------------------------------------
> +	 *     Ports  :    GPG5       GPG4    GPG3    GPG2    GPG1    GPG0
> +	 *     Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA
> +	 *     Setting:  SPIMISO1  LCD_PWRDN EINT11   nSS0   EINT9    EINT8
> +	 *     Binary :     11         11   ,  10      11  ,  10        10
> +	 */
> +	rGPGCON = 0x01AAFE79;
> +	rGPGUP = 0x0000FFFF;
> +	/*
> +	 * === PORT H GROUP
> +	 *     Ports  :  GPH10    GPH9  GPH8 GPH7  GPH6  GPH5 GPH4 GPH3 GPH2 GPH1  GPH0
> +	 *     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!
> +	 * pulldown GPH0 -- nCTS0 / RTS_MODEM -- floats when GSM off
> +	 * pulldown GPH3 -- RXD[0] / TX_MODEM -- floats when GSM off
> +	 */
> +	rGPHCON = 0x001AAAAA;
> +	rGPHUP = 0x000007FF & ~(1 << 8) & ~(1 << 0) & ~(1 << 3);
> +
> +	/* pulldown on GPJ00: input, just floats! */
> +	/* pulldown on GPJ07: WLAN module WLAN_GPIO0, no ext pull */
> +	rGPJCON = 0x1551544;
> +	rGPJUP = 0x1ffff & ~(1 << 0) & ~(1 << 7);
> +	rGPJDAT |= (1 << 4) | (1 << 6);
> +					/* Set GPJ4 to high (nGSM_EN) */
> +					/* Set GPJ6 to high (nDL_GSM) */
> +	rGPJDAT &= ~(1 << 5);	/* Set GPJ5 to low 3D RST */
> +
> +	/* leaving Glamo forced to Reset# active here killed
> +	 * U-Boot when you touched the memory region
> +	 */
> +
> +	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
> + */
> +
> +int gta02_get_pcb_revision(void)
> +{
> +	int n;
> +	u32 u;
> +
> +	/* 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));
> +
> +	/* 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;
> +
> +	/*
> +	 * 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);
> +
> +	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/src/kboot-stage1.lds b/src/kboot-stage1.lds
> deleted file mode 100644
> index 5c8d50c..0000000
> --- a/src/kboot-stage1.lds
> +++ /dev/null
> @@ -1,64 +0,0 @@
> -/*
> - * (C) Copyright 2002
> - * Gary Jennejohn, DENX Software Engineering, <gj at denx.de>
> - *
> - * See file CREDITS for list of people who contributed to this
> - * project.
> - *
> - * 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
> - */
> -
> -OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
> -/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
> -OUTPUT_ARCH(arm)
> -ENTRY(_start)
> -SECTIONS
> -{
> -	. = 0x00000000;
> -
> -	/* this is intended to take the first 4KBytes of stuff initially.
> -	 * We have to make sure we have .rodata* in there for everything
> -	 * because we do not compile PIC.
> -	 */
> -
> -	. = 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/blink_led.o	(.text .rodata* .data)
> -	  * (.rodata* .data)
> -	}
> -
> -	. = ALIGN(4);
> -	.everything_else : { *(.text) }
> -
> -	. = ALIGN(4);
> -	.got : 
> -    { 
> -        *(.got) 
> -    }
> -
> -	. = 0x32000000 ;
> -	__bss_start = .;
> -	.bss (NOLOAD) : 
> -    { 
> -        *(.bss) 
> -    }
> -	_end = .;
> -}
> diff --git a/src/lowlevel_init.S b/src/lowlevel_init.S
> index 4f20d5e..2a1654c 100644
> --- a/src/lowlevel_init.S
> +++ b/src/lowlevel_init.S
> @@ -26,6 +26,7 @@
>   * #include <config.h>
>   * #include <version.h>
>   */
> +#define __ASM_MODE__
>  #include <neo_gta02.h>
>  
>  /*
> @@ -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/src/mmc.c b/src/mmc.c
> index 39f1720..b982657 100644
> --- a/src/mmc.c
> +++ b/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/src/nand_read.c b/src/nand_read.c
> index bdd1b6a..6351173 100644
> --- a/src/nand_read.c
> +++ b/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/src/phase2.c b/src/phase2.c
> index 59a18f0..826e90e 100644
> --- a/src/phase2.c
> +++ b/src/phase2.c
> @@ -31,111 +31,156 @@
>  #include <setup.h>
>  #include "nand_read.h"
>  
> -#include <device_configuration.h>
> -
> -#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);
> -
> -	puts("Checking kernel... ");
> -
> -	if (nand_read_ll(kernel_nand, CFG_NAND_OFFSET_FOR_KERNEL_PARTITION,
> -								    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, CFG_NAND_OFFSET_FOR_KERNEL_PARTITION,
> -		((32 * 1024) + (_ntohl(hdr->ih_size) + sizeof(hdr) + 2048)) &
> +	int kernel = 0;
> +	const struct board_variant * board_variant =
> +					      (this_board->get_board_variant)();
> +
> +	/* we try the possible kernels for this board in order */
> +
> +	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;
> +
> +		/* eat leading white space */
> +		for (p = cmdline; *p == ' '; p++);
> +
> +		puts("\nTrying kernel: ");
> +		puts(this_board->kernel_source[kernel].name);
> +		puts("\n");
> +
> +		/* 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;
> +			}
> +
> +		/* if there's a partition table implied, parse it, otherwise
> +		 * just use a fixed offset
> +		 */
> +		if (this_board->kernel_source[kernel].partition_index != -1) {
> +
> +			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");
> -
> -	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 */
> +	/* none of the kernels worked out */
>  
> -unhappy:
> +	puts("No usable kernel image found, we've had it  :-(\n");
>  	while (1)
>  		blue_on(1);
>  }
> diff --git a/src/qi.lds b/src/qi.lds
> new file mode 100644
> index 0000000..29ec63f
> --- /dev/null
> +++ b/src/qi.lds
> @@ -0,0 +1,59 @@
> +/*
> + * (C) Copyright 2002
> + * Gary Jennejohn, DENX Software Engineering, <gj at denx.de>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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
> + */
> +
> +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
> +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
> +OUTPUT_ARCH(arm)
> +ENTRY(_start)
> +SECTIONS
> +{
> +	. = 0x00000000;
> +
> +	/* this is intended to take the first 4KBytes of stuff initially.
> +	 * We have to make sure we have .rodata* in there for everything
> +	 * because we do not compile PIC.
> +	 */
> +
> +	. = ALIGN(4);
> +	.text      :
> +	{
> +	  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)
> +	  src/nand_read.o	(.text .rodata* .data)
> +	  src/serial.o		(.text .rodata* .data)
> +	}
> +
> +	. = ALIGN(4);
> +	.everything_else  ADDR (.text) + SIZEOF (.text) + 0x33000000 :
> +		AT ( ADDR (.text) + SIZEOF (.text) ) { *(.text .rodata* .data) }
> +
> +	. = 0x33800000 ;
> +	__bss_start = .;
> +	.bss (NOLOAD) : 
> +    { 
> +        *(.bss) 
> +    }
> +	_end = .;
> +}
> diff --git a/src/serial.c b/src/serial.c
> index 19fb850..61b4762 100644
> --- a/src/serial.c
> +++ b/src/serial.c
> @@ -23,55 +23,54 @@
>  #include <qi.h>
>  #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/src/start.S b/src/start.S
> index 1d2ee92..3a98bef 100644
> --- a/src/start.S
> +++ b/src/start.S
> @@ -18,6 +18,8 @@
>   * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
>   * MA 02111-1307 USA
>   */
> +
> +#define __ASM_MODE__
>  #include <neo_gta02.h>
>  
>  .globl _start
> @@ -119,10 +121,38 @@ 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
>  
> @@ -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/src/start_kboot.c b/src/start_kboot.c
> deleted file mode 100644
> index 8b5078c..0000000
> --- a/src/start_kboot.c
> +++ /dev/null
> @@ -1,186 +0,0 @@
> -/*
> - * (C) Copyright 2007 OpenMoko, Inc.
> - * Author: xiangfu liu <xiangfu at openmoko.org>
> - *         Andy Green <andy at openmoko.com>
> - *
> - * 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 <qi.h>
> -#include "blink_led.h"
> -#include "nand_read.h"
> -#include <neo_gta02.h>
> -
> -#define stringify2(s) stringify1(s)
> -#define stringify1(s) #s
> -
> -extern void bootloader_second_phase(void);
> -
> -void port_init(void)
> -{
> -    //CAUTION:Follow the configuration order for setting the ports.
> -    // 1) setting value(GPnDAT)
> -    // 2) setting control register  (GPnCON)
> -    // 3) configure pull-up resistor(GPnUP)
> -
> -    /* 32bit data bus configuration   */
> -	/*
> -	 * === PORT A GROUP
> -	 *     Ports  : GPA22 GPA21  GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12
> -	 *     Signal : nFCE nRSTOUT nFRE   nFWE  ALE   CLE  nGCS5 nGCS4 nGCS3 nGCS2 nGCS1
> -	 *     Binary :  1     1      1  , 1   1   1    1   ,  1     1     1     1
> -	 *     Ports  : GPA11   GPA10  GPA9   GPA8   GPA7   GPA6   GPA5   GPA4   GPA3   GPA2   GPA1  GPA0
> -	 *     Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0
> -	 *     Binary :  1       1      1      1   , 1       1      1      1   ,  1       1     1      1
> -	 */
> -	rGPACON = 0x007E5FFF;
> -	rGPADAT |= (1 << 16);      /* Set GPA16 to high (nNAND_WP) */
> -	/*
> -	 * ===* PORT B GROUP
> -	 *      Ports  : GPB10    GPB9    GPB8    GPB7    GPB6     GPB5    GPB4   GPB3   GPB2     GPB1      GPB0
> -	 *      Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard
> -	 *      Setting: INPUT  OUTPUT   INPUT  OUTPUT   INPUT   OUTPUT   OUTPUT OUTPUT OUTPUT   OUTPUT    OUTPUT
> -	 *      Binary :   00  ,  01       00  ,   01      00   ,  01       01  ,   01     01   ,  01        01
> -	 */
> -	rGPBCON = 0x00155555;
> -	rGPBUP = 0x000007FF;
> -	/*
> -	 * === PORT C GROUP
> -	 *     Ports  : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8  GPC7   GPC6   GPC5 GPC4 GPC3  GPC2  GPC1 GPC0
> -	 *     Signal : VD7   VD6   VD5   VD4   VD3   VD2   VD1  VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND
> -	 *     Binary :  10   10  , 10    10  , 10    10  , 10   10  , 10     10  ,  10   10 , 10     10 , 10   10
> -	 */
> -	rGPCCON = 0x55555155;
> -	rGPCUP = 0x0000FFFF & ~(1 << 5);
> -	rGPCDAT |= (1 << 13) | (1 << 15); /* index detect -> hi */
> -	/*
> -	 * === PORT D GROUP
> -	 *     Ports  : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
> -	 *     Signal : VD23  VD22  VD21  VD20  VD19  VD18  VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9  VD8
> -	 *     Binary : 10    10  , 10    10  , 10    10  , 10   10 , 10   10 , 10   10 , 10   10 ,10   10
> -	 */
> -	rGPDCON = 0x55555555;
> -	rGPDUP = 0x0000FFFF;
> -	rGPDDAT |= (1 << 0) | (1 << 3) | (1 << 4); /* index detect -> hi */
> -	/*
> -	 * === PORT E GROUP
> -	 *     Ports  : GPE15  GPE14 GPE13   GPE12   GPE11   GPE10   GPE9    GPE8     GPE7  GPE6  GPE5   GPE4
> -	 *     Signal : IICSDA IICSCL SPICLK SPIMOSI SPIMISO SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK I2SSDO
> -	 *     Binary :  10     10  ,  10      10  ,  10      10   ,  10      10   ,   10    10  , 10     10  ,
> -	 *     -------------------------------------------------------------------------------------------------------
> -	 *     Ports  :  GPE3   GPE2  GPE1    GPE0
> -	 *     Signal : I2SSDI CDCLK I2SSCLK I2SLRCK
> -	 *     Binary :  10     10  ,  10      10
> -	 */
> -	rGPECON = 0xAAAAAAAA;
> -	rGPEUP = 0x0000FFFF & ~(1 << 11);
> -	/*
> -	 * === PORT F GROUP
> -	 *     Ports  : GPF7   GPF6   GPF5   GPF4      GPF3     GPF2  GPF1   GPF0
> -	 *     Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0
> -	 *     Setting: Output Output Output Output    EINT3    EINT2 EINT1  EINT0
> -	 *     Binary :  01      01 ,  01     01  ,     10       10  , 10     10
> -	 */
> -	/* pulldown on GPF03: TP-4705+debug - debug conn will float */
> -	rGPFCON = 0x0000AAAA;
> -	rGPFUP = 0x000000FF & ~(1 << 3);
> -
> -
> -	/*
> -	 * === PORT G GROUP
> -	 *     Ports  : GPG15 GPG14 GPG13 GPG12 GPG11    GPG10    GPG9     GPG8     GPG7      GPG6
> -	 *     Signal : nYPON  YMON nXPON XMON  EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI
> -	 *     Setting: nYPON  YMON nXPON XMON  EINT19  Output   Output   Output   SPICLK1    SPIMOSI1
> -	 *     Binary :   11    11 , 11    11  , 10      01    ,   01       01   ,    11         11
> -	 *     -----------------------------------------------------------------------------------------
> -	 *     Ports  :    GPG5       GPG4    GPG3    GPG2    GPG1    GPG0
> -	 *     Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA
> -	 *     Setting:  SPIMISO1  LCD_PWRDN EINT11   nSS0   EINT9    EINT8
> -	 *     Binary :     11         11   ,  10      11  ,  10        10
> -	 */
> -	rGPGCON = 0x01AAFE79;
> -	rGPGUP = 0x0000FFFF;
> -	/*
> -	 * === 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
> -	 *     Binary :   10   ,  10     10 , 11    11  , 10   10 , 10   10 , 10    10
> -	 */
> -	/* pulldown on GPH08: UEXTCLK, just floats!
> -	 * pulldown GPH0 -- nCTS0 / RTS_MODEM -- floats when GSM off
> -	 * pulldown GPH3 -- RXD[0] / TX_MODEM -- floats when GSM off
> -	 */
> -	rGPHCON = 0x001AAAAA;
> -	rGPHUP = 0x000007FF & ~(1 << 8) & ~(1 << 0) & ~(1 << 3);
> -
> -	/* pulldown on GPJ00: input, just floats! */
> -	/* pulldown on GPJ07: WLAN module WLAN_GPIO0, no ext pull */
> -	rGPJCON = 0x1551544;
> -	rGPJUP = 0x1ffff & ~(1 << 0) & ~(1 << 7);
> -	rGPJDAT |= (1 << 4) | (1 << 6);
> -					/* Set GPJ4 to high (nGSM_EN) */
> -					/* Set GPJ6 to high (nDL_GSM) */
> -	rGPJDAT &= ~(1 << 5);	/* Set GPJ5 to low 3D RST */
> -
> -	/* leaving Glamo forced to Reset# active here killed
> -	 * U-Boot when you touched the memory region
> -	 */
> -
> -	rGPJDAT |= (1 << 5);	/* Set GPJ5 to high 3D RST */
> -}
> -
> -
> -
> -void start_kboot(void)
> -{
> -	void (*phase2)(void) = (void (*)(void))((int)bootloader_second_phase +
> -								     TEXT_BASE);
> -
> -	port_init();
> -	serial_init(UART2);
> -
> -	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");
> -
> -	/*
> -	 * 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)
> -		while(1)
> -			blink_led();
> -	/*
> -	 * jump to bootloader_second_phase() running from DRAM copy
> -	 */
> -	(phase2)();
> -}
> diff --git a/src/start_qi.c b/src/start_qi.c
> new file mode 100644
> index 0000000..f0cdeaf
> --- /dev/null
> +++ b/src/start_qi.c
> @@ -0,0 +1,108 @@
> +/*
> + * (C) Copyright 2007 OpenMoko, Inc.
> + * Author: xiangfu liu <xiangfu at openmoko.org>
> + *         Andy Green <andy at openmoko.com>
> + *
> + * 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 <qi.h>
> +#include "blink_led.h"
> +#include "nand_read.h"
> +#include <neo_gta02.h>
> +
> +#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/src/utils.c b/src/utils.c
> index 55fc3f1..45605af 100644
> --- a/src/utils.c
> +++ b/src/utils.c
> @@ -23,8 +23,6 @@
>  #include <qi.h>
>  #include <string.h>
>  
> -#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;
> +}
> 
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iQEVAwUBSKlV8hFuNemPXNFjAQK4rAf+IAAC/sQoJ31o8NG9ePmTnbofCvQDIdYn
FFnhIOtMrCAfp0rlFrMyJbdI3mrfwHRpRweJBdZ+NERVKXPL0n+B2GjWy8G5k63Q
bo6KElj217c4Q53XAhTp+JcxbDZmMNPH8igDLhBI7e861YMgUvy2XoV2qjko2EE2
z4b+EgNvwvUNPcwx2a8IzptCQV9KlzkX/610hcJRC0hCfdEj/niNlFLksK91O+XC
YHINjeQdRCc8MKlEkb76K5INkf3P5h03k0ZlziKt7A6A2rZRGUdXakj4DpcHKmhw
rusendAMtZWd9HEsOjU+Zug9rI48CThDgfMRnZhnhvIMN1QH0vEv8Q==
=QoKn
-----END PGP SIGNATURE-----



More information about the openmoko-kernel mailing list