目标平台
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
至此,移植完成
U-Boot NAND启动移植

1447

被折叠的 条评论
为什么被折叠?



