目标平台
NANO2410A
CPU | S3C2410 (ARM920T) |
Nand FLASH | K9F1208 (64M*8bit) |
SRAM | HY57V561620 (4banks*4M+16Bit) |
准备工作
我的移植工作是基于1.3.2来进行的,因为在网上看到1.3.3之后的版本Makefile会有点小问题
自己插入的Nand Flash拷贝代码会被放入到前4K以外,导致不能执行
关于这个问题和解决办法请参照这里
下载好uboot源码之后,解压
tar zxvf u-boot-1.3.2.tar.gz
在board下建立自己板子对应的文件,以smdk2410为模板
cp -r smdk2410 xxx2410
修改Makefile,将smdk2410修改成对应的xxx2410
修改config.mk,因为我们的板子Nand Flash只有32M,所以需要将 TEXT_BASE 设置成0x31F80000
修改lowlevel_init.S,按照我们的需要(这里我参考的是一个工作良好的vivi的配置)修改 SMRDATA
换到uboot的根目录,make一下
原理
Nand Flash和Nor Flash不同,其中Nand Flash不能直接读写,需要通过驱动程序控制
但是在我们的板子上没有Nor Flash,也就是说我们需要把bootloader也放入Nand Flash中。
好在s3c2410在设计时考虑到了这样的问题,提供了这样的机制
在每次CPU上电之后,CPU会通过内置的Nand控制器将Bank0上面的前4K内容映射到一片叫做Steppingstone的buffer中
于是,我们需要将一段代码放在这前4K中,并且在这4K代码中实现将整个uboot载入内存并开始执行。
好在有vivi的代码可以参考,我们不难发现在跳转到C入口之前会先执行copy_myself
#ifdef CONFIG_S3C2410_NAND_BOOT /* CONFIG_S3C2410_NAND_BOOT=y */ @ @ copy_myself: copy vivi to ram @ copy_myself: mov r10, lr @ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =0xf830 @ initial value str r2, [r1, #oNFCONF] ldr r2, [r1, #oNFCONF] bic r2, r2, #0x800 @ enable chip str r2, [r1, #oNFCONF] mov r2, #0xff @ RESET command strb r2, [r1, #oNFCMD] mov r3, #0 @ wait 1: add r3, r3, #0x1 cmp r3, #0xa blt 1b 2: ldr r2, [r1, #oNFSTAT] @ wait ready tst r2, #0x1 beq 2b ldr r2, [r1, #oNFCONF] orr r2, r2, #0x800 @ disable chip str r2, [r1, #oNFCONF] @ get read to call C functions (for nand_read()) ldr sp, DW_STACK_START @ setup stack pointer mov fp, #0 @ no previous frame, so fp=0 @ copy vivi to RAM ldr r0, =VIVI_RAM_BASE mov r1, #0x0 mov r2, #0x20000 bl nand_read_ll tst r0, #0x0 beq ok_nand_read #ifdef CONFIG_DEBUG_LL /* is not set */ bad_nand_read: ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord 1: b 1b @ infinite loop @ 我认为应把这条指令放到#ifdef...#endif之外 #endif ok_nand_read: #ifdef CONFIG_DEBUG_LL /* is not set */ ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif @ verify mov r0, #0 ldr r1, =0x33f00000 @VIVI_RAM_BASE mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes go_next: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq done_nand_read bne go_next notmatch: #ifdef CONFIG_DEBUG_LL /* is not set */ sub r0, r0, #4 ldr r1, SerBase bl PrintHexWord ldr r0, STR_FAIL ldr r1, SerBase bl PrintWord #endif 1: b 1b done_nand_read: #ifdef CONFIG_DEBUG_LL /* is not set */ ldr r0, STR_OK ldr r1, SerBase bl PrintWord #endif mov pc, r10
这段程序非常简单,哪怕是完全不会arm汇编也基本能稍微看出一点眉目来
- 保存返回地址(参见APCS)
- 初始化Nand Flash(需要严格按照对应Nand Flash的datasheet)
- 建立C运行环境(建立栈帧)
- 跳转到nand_read_ll,其中参数1为vivi在ram中的起始地址,参数2为地址0(Nand Flash所对应的起始地址)
- 校验
- 如果校验成功,根据已经保存的返回地址返回
移植工作
有了以上原理性的东西,我们实际动手起来就方便多了
修改cpu/arm920t/start.S文件
在setup_stack上面加入(因为后面的代码是建立堆栈,清楚bss,跳转到uboot的C入口)
#ifdef CONFIG_S3C2410_NAND_BOOT bl copy_myself #endif /* CONFIG_S3C2410_NAND_BOOT */
我们需要在这之前先将整个uboot载入到内存当中
参照vivi中的代码,我们加入这样一段代码
#ifdef CONFIG_S3C2410_NAND_BOOT copy_myself: mov r10, lr @save return address to r10 ldr sp, DW_STACK_START mov fp, #0 bl NF_Init ldr r0, =UBOOT_RAM_BASE mov r1, #0x0 mov r2, #0x30000 @192K(size of uboot) bl nand_read_whole tst r0, #0x0 beq ok_nand_read 1: b 1b /* Verify */ ok_nand_read: mov r0, #0x00000000 ldr r1, =UBOOT_RAM_BASE mov r2, #0x400 go_next: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq done_nand_read bne go_next notmatch: 1: b 1b done_nand_read: mov pc, r10 #endif DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
代码结构和vivi中的完全一样,只不过我们将Nand Flash初始化部分改成了C语言实现
这段代码中调用了两个外部C函数,NF_Init和nand_read_whole
我们需要在board/xxx2410中加入对应的C实现
#include <common.h> #include <s3c2410.h> #include <config.h> /*s3c2410 datasheet P216*/ #define rNFCONF (*(volatile unsigned int *)0x4e000000) #define rNFCMD (*(volatile unsigned char *)0x4e000004) #define rNFADDR (*(volatile unsigned char *)0x4e000008) #define rNFDATA (*(volatile unsigned char *)0x4e00000c) #define rNFSTAT (*(volatile unsigned int *)0x4e000010) #define rNFECC (*(volatile unsigned int *)0x4e000014) #define rNFECC0 (*(volatile unsigned char *)0x4e000014) #define rNFECC1 (*(volatile unsigned char *)0x4e000015) #define rNFECC2 (*(volatile unsigned char *)0x4e000016) /* Nand Flash ops */ #define NF_CMD(cmd) {rNFCMD=cmd;} #define NF_ADDR(addr) {rNFADDR=addr;} #define NF_nFCE_L() {rNFCONF&=~(1<<11);} #define NF_nFCE_H() {rNFCONF|=(1<<11);} #define NF_RSTECC() {rNFCONF|=(1<<12);} #define NF_RDDATA() (rNFDATA) #define NF_WRDATA(data) {rNFDATA=data;} #define NF_WAITRB() {while(!(rNFSTAT&(1<<0)));} static void NF_Reset(void) { int i; NF_nFCE_L(); /* Enable */ NF_CMD(0xFF); /* Reset Command */ for(i=0;i<10;i++); /* Delay 100ns */ NF_WAITRB(); /* wait for busy */ NF_nFCE_H(); /* Disable */ } void NF_Init(void) { /* * initial value is 0xf830 * copy form vivi */ rNFCONF=0xF830; NF_Reset(); } int nand_read_whole(unsigned char *buf, unsigned long start_addr, int size) { int i, j; /* align with nand block */ if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return 1; } NF_nFCE_L(); for(i=0; i<10; i++); /* delay 100ns */ i = start_addr; while(i < start_addr + size) { /* Zone A */ rNFCMD = 0; /* Generate 4 cycle address */ rNFADDR = i & 0xff; rNFADDR = (i >> 9) & 0xff; rNFADDR = (i >> 17) & 0xff; rNFADDR = (i >> 25) & 0xff; NF_WAITRB(); /* Read a whole page */ for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { *buf = (rNFDATA & 0xff); buf++; } } NF_nFCE_H(); return 0; }
记得将对应的文件加入Makefile的依赖中。
后续
至此便完成了大部分的工作,我们还需要在相应的板卡配置中稍作修改
加入:
#define CONFIG_S3C2410_NAND_BOOT 1 #define STACK_BASE 0x31f00000 #define STACK_SIZE 0x8000 #define UBOOT_RAM_BASE 0x31f80000
#define CONFIG_CMD_NAND #define CONFIG_CMD_PING #define CONFIG_CMD_ENV
修改 CFG_PROMET 为"XXX2410: "
修改 PHYS_SDRAM_1_SIZE 为0x02000000 (根据自己板子情况)
在文件的最后加入
#define CFG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */ #define CFG_ENV_OFFSET (0x80000-0x4000) #define CONFIG_ARCH_SMDK2410 1 #define CFG_NAND_BASE 0x4E000000 /* Nand Flash控制器在SFR区中起始寄存器地址 */ #define CFG_MAX_NAND_DEVICE 1 /* 支持的最在Nand Flash数据 */ #define SECTORSIZE 512 /* 1页的大小 */ #define NAND_SECTOR_SIZE SECTORSIZE #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) /* 页掩码 */ #define ADDR_COLUMN 1 /* 一个字节的Column地址 */ #define ADDR_PAGE 2 /* 3字节的页块地址, A9A25*/ #define ADDR_COLUMN_PAGE 3 /* 总共4字节的页块地址 */ #define NAND_ChipID_UNKNOWN 0x00 /* 未知芯片的ID号 */ #define NAND_MAX_FLOORS 1 #define NAND_MAX_CHIPS 1 /* Nand Flash命令层底层接口函数 */ #define WRITE_NAND_COMMAND(d, adr) do {rNFCMD = d;} while(0) #define WRITE_NAND_ADDRESS(d, adr) do {rNFADDR = d;} while(0) #define WRITE_NAND(d, adr) do {rNFDATA = d;} while(0) #define READ_NAND(adr) (rNFDATA) #define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));} #define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);} #define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);} /* 下面一组操作对Nand Flash无效 */ #define NAND_CTL_CLRALE(nandptr) #define NAND_CTL_SETALE(nandptr) #define NAND_CTL_CLRCLE(nandptr) #define NAND_CTL_SETCLE(nandptr) /* 允许Nand Flash写校验 */ #define CONFIG_MTD_NAND_VERIFY_WRITE 1
至此,移植完成