????对于Jz它不仅支持2440开发板NOR Flash启动,也支持从NAND Flash启动。那么NOR Flash启动与NAND Flash启动有什么区别?NOR 启动,上电后NOR Flash被映射到0x00000000地址,然后CPU从0x00000000开始运行;NAND启动,上电后CPU自动将NAND Flash中的前4K代码拷贝到SRAM,SRAM被映射为0x00000000地址,CPU从0x00000000开始运行。uboot大小远大于4k,因此,需要在代码的前4位k完成代码的重定位,即NAND Flash代码复制到SDRAM中。关于代码重定位的知识,可以看到韦东山先生的博客S3c2440代码重定位详解。
4.1 去"-pie"、"checkarmreloc"选项????链接时添加了原始代码。-pie选项,使u-boot.bin里多了*(.rel*)段,程序很大,不利于从NAND启动(重定位前的启动代码应小于4K),所以我们需要去掉它"-pie"选项。(1) 在u-boot 搜索顶层目录"pie":grep "\\-pie" * -nR,搜索结果如下:
从上图可以发现,路由知识"pie"选项在arch/arm/config.mk第83行,然后我们进去注释如下图所示:
然后重新编译以下命令:
make distcleanmake jz2440_defconfigmake
最后发现以下错误:
checkarmreloc正如其名,它是检查arm相对位置的选项可能找不到arm,因此,错误对整个程序没有影响,注释不检查,编译可以通过;在uboot搜索顶层目录checkarmreloc:grep "checkarmreloc" * -nR,搜索结果如下:
从上图可以发现,"checkarmreloc"选项在arch/arm/config.mk第105行,我们进去注释一下,如下图所示:
然后重新编译成功编译。
4.2 添加init.c程序(1) 以前写的init.c文件放到board/samsung/jz2440目录,init.c文件代码如下:
/*所以如何判断是NOR启动还是NAND启动呢? 可以利用NOR的特点: *1.NOR可以像内存一样读,但不能像内存一样写; *2.可以通过向0地址写数据来区分NAND启动还是NOR启动; *(因为NAND启动时,0地址是RAM,可读可写;但是NOR启动时,0地址是NOR FLASH,可读不能写) *返回值:1:Nor启动; 0:NAND启动 */#define NFCONF (*((volatile unsigned long *)0x4E000000))#define NFCONT (*((volatile unsigned long *)0x4E000004))#define NFCMMD (*((volatile unsigned char *)0x4E000008))#define NFADDR (*((volatile unsigned char *)0x4E00000c))#define NFDATA (*((volatile unsigned char *)0x4E000010))#define NFSTAT (*((volatile unsigned long *)0x4E000020))/* GPIO */#define GPHCON (*(volatile unsigned long *)0x56000070)#define GPHUP (*(volatile unsigned long *)0x56000078)/* UART registers*/#define ULCON0 (*(volatile unsigned long *)0x50000000)#define UCON0 (*(volatile unsigned long *)0x50000004)#define UFCON0 (*(volatile unsigned long *)0x50000008)#define UMCON0 (*(volatile unsigned long *)0x5000000c)#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)#define UTXH0 (*(volatile unsigned char *)0x50000020)#define URXH0 (*(volatile unsigned char *)0x50000024)#define UBRDIV0 (*(volatile unsigned long *)0x50000028)#define TXD0READY (1<<2)/* NAND flash 设置时序(需要比较)s3c2440与NAND手册的NAND时序) * */void nand_init_ll(void){ /*设置NANDFlash时序*/#define TACLS 0#define TWRPH0 1#define TWRPH1 0 NFCONF &= ~((3<<12)|(7<<8)|(7<<4)); NFCONF |= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /*使能NANDflash 控制器, *禁止片选(开发板没有正式使用片选,避免操作错误) *初始化 ECC 编码器/译码器*/ NFCONT = (1<<0)|(1<<1)|(1<<4);}static void nand_cmd(unsigned char cmd){ volatile int i; NFCMMD = cmd; for(i = 0; i < 10; i );/*等待*/}static void nand_addr(unsigned int addr){ unsigned int col = addr % 2048; unsigned int page = addr / 2048; volatile int i; NFADDR = col & 0xff; for(i = 0; i < 10; i );/*等待*/ NFADDR = (col >> 8) & 0xff; for(i = 0; i < 10; i );/*等待*/ NFADDR = page & 0xff; for(i = 0; i < 10; i );/*等待*/ NFADDR = (page >> 8) & 0xff; for(i = 0; i < 10; i );/*等待*/ NFADDR = (page >> 16) & 0xff; for(i = 0; i < 10; i );/*等待*/}static void nand_wait_ready(void){ while(!(NFSTAT & 0x01));}static unsigned char nand_data(void){ return NFDATA;}static void nand_select(void){ NFCONT &= ~(1<<1);}static void nand_deselect(void){ NFCONT |= (1<<1);}void nand_read_ll(unsigned int addr, unsigned char *buf,unsigned int len){ int col = addr % 2048; int i = 0; /*1.片选*/ nand_select(); while(i < len){ /*2.发出00阅读命令h*/ nand_cmd(0x00); /*3.发出地址(分为5个地址周期)*/ nand_addr(addr); /*4.发出30个阅读命令h*/ nand_cmd(0x30); /*5.等待就绪(判断状态)*/ nand_wait_ready(); /*6.读数据*/ for(; (col < 2048) && (i < len); col ){ buf[i]= nand_data(); i ; addr ; }col = 0; }/*7.取消选中*/ nand_deselect();}static int isBootFromNorFlash(void){ volatile unsigned int *p = (volatile unsigned int*)0; unsigned int val; val = *p; *p = 0x12345678; if(*p == val) /*写前写后值一样,证明数据不能写0地址,是NOR启动*/{ return 1; }else /*否则是NAND启动*/{ *p = val; /*恢复数据*/ return 0; }}void copy_code_to_sdram(unsigned char *src, unsigned char *dest,unsigned int len){ unsigned int i=0; /*如果是NOR启动*/ if(isBootFromNorFlash()) /*所以如何判断是NOR启动还是NAND启动呢? */{ while(i < len){ dest[i]= src[i]; i ; }}else /*否则是NAND启动*/{ nand_init_ll();/*初始化NAND*/ nand_read_ll((unsigned int )src,dest,len); }}/*c如何引用连接脚本的语言? __bss_start、__bss_end等变量呢? * extern int __bs
s_