移植Uboot-2010.06到TQ2440开发板详解之三
七、支持从NAND启动 1、修改start.S文件 1)???????设置好C语言要用的栈 修改arch/arm/cpu/arm920t/start.S,将stack_setup 子程序搬到relocate 子程序之前(在调用C函数之前设置好栈),并修改之前调用设置栈的函数为清除BSS段,这是因为之前的源码程序调用beq stack_setup之后接着执行了清除BSS段的子程序clear_bss,把stack_setup搬移到上面之后,应该确保会执行clear_bss子函数,跟之前的效果一样。修改后的代码如下: ? 209stack_setup: 210???????? ldr????r0,_TEXT_BASE????????? /* upper128 KiB: relocated uboot?? */ 211???????? sub????r0,r0,#CONFIG_SYS_MALLOC_LEN? /*malloc area????????????? */ 212???????? sub????r0,#CONFIG_SYS_GBL_DATA_SIZE /* bdinfo???????????????? */ 213 #ifdefCONFIG_USE_IRQ 214???????? sub????r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) 215#endif? 216???????? sub????sp,#12???????????? /* leave 3words for abort-stack??? */ 217???????? bic????sp,sp,#7????????????? /* 8-bytealignment for ABI compliance */ 218???????? 219 #ifndefCONFIG_SKIP_RELOCATE_UBOOT 220relocate:??????????????????????????????/* relocate U-Boot to RAM??????????*/ 221???????? adr????r0,_start????????????? /* r0<- current position of code?? */ 222???????? ldr????r1,_TEXT_BASE????????? /* test ifwe run from flash or RAM */ 223???????? cmp????r0,r1????????????????? /* don'treloc during debug???????? */ 224???????? /*beq??stack_setup */????????? 225???????? beq????clear_bss 226???????? 227???????? ldr????r2,_armboot_start 228???????? ldr????r3,_bss_start 229???????? sub????r2,r3,r2 ?????????????/* r2<- size of armboot??????????? */ 230???????? add????r2,r2????????????? /* r2<- source end address???????? */ 2)???????修改代码搬移程序 在relocate子程序中屏蔽掉原来的拷贝函数,增加自己用C语言实现的拷贝函数: ? 219 #ifndefCONFIG_SKIP_RELOCATE_UBOOT 220 relocate:????????????????? ?????????????/* relocate U-Boot to RAM?????????? */ 221???????? adr????r0,_start????????????? /* r0<- current position of code?? */ 222???????? ldr????r1,_TEXT_BASE????????? /* test ifwe run from flash or RAM */ 223???????? cmp????r0,r1??????????? ??????/* don't reloc during debug???????? */ 224???????? /*beq??stack_setup */????????? 225???????? beq????clear_bss 226???????? 227???????? ldr????r2,_armboot_start 228???????? ldr????r3,_bss_start 229???????? sub????r2,r2????????????? /* r2<- size of armboot??????????? */ 230 #if1?? 231???????? bl CopyCode2Ram 232#else 233???????? add????r2,r2????????????? /* r2<- source end address???????? */ 234???????? 235 copy_loop: 236???????? ldmia??r0!,{r3-r10}?????????? /* copyfrom source address [r0]??? */ 237???????? stmia??r1!,{r3-r10}?????????? /* copyto?? target address [r1]??? */ 238???????? cmp????r0,r2????????????????? /* untilsource end addreee [r2]??? */ 239???????? ble????copy_loop 240#endif 241 #endif? /* CONFIG_SKIP_RELOCATE_UBOOT */ 2、实现代码拷贝函数 ?? 在board/samsung/tq2440/目录下增加一个文件nand_start.c,实现Nand的操作: ? #include<common.h> //#include<s3c2410.h> #include<asm/arch/s3c24x0_cpu.h> ? #defineGSTATUS1??????? (*(volatile unsigned int*)0x560000B0) #defineBUSY??????????? 1 ? #defineNAND_SECTOR_SIZE?? 512 #defineNAND_BLOCK_MASK?? (NAND_SECTOR_SIZE - 1) ? #defineNAND_SECTOR_SIZE_LP?? 2048 #defineNAND_BLOCK_MASK_LP?? (NAND_SECTOR_SIZE_LP- 1) ? charbLARGEBLOCK;???????? //HJ_add 20090807 charb128MB;??????????? //HJ_add 20090807 ? /* 供外部调用的函数 */ voidnand_init_ll(void); intnand_read_ll(unsigned char *buf,unsigned long start_addr,int size); intnand_read_ll_lp(unsigned char *buf,int size); ? /* NAND Flash操作的总入口,它们将调用S3C2410或S3C2440的相应函数 */ static voidnand_reset(void); static voidwait_idle(void); static voidnand_select_chip(void); static voidnand_deselect_chip(void); static voidwrite_cmd(int cmd); static voidwrite_addr(unsigned int addr); static voidwrite_addr_lp(unsigned int addr); static unsignedchar read_data(void); intNF_ReadID(void);??????????? //HJ_add20090807 ? /* S3C2440的NAND Flash处理函数 */ static voids3c2440_nand_reset(void); static voids3c2440_wait_idle(void); static voids3c2440_nand_select_chip(void); static voids3c2440_nand_deselect_chip(void); static voids3c2440_write_cmd(int cmd); static voids3c2440_write_addr(unsigned int addr); static voids3c2440_write_addr_lp(unsigned int addr); static unsignedchar s3c2440_read_data(void); ? /* S3C2440的NAND Flash操作函数 */ ? /* 复位 */ static voids3c2440_nand_reset(void) { ?? s3c2440_nand_select_chip(); ?? s3c2440_write_cmd(0xff);? // 复位命令 ?? s3c2440_wait_idle(); ?? s3c2440_nand_deselect_chip(); } ? /* 等待NAND Flash就绪 */ static voids3c2440_wait_idle(void) { ?? int i; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFSTAT; ? ?? while(!(*p & BUSY)) ??????? for(i=0; i<10; i++); } ? /* 发出片选信号 */ static voids3c2440_nand_select_chip(void) { ?? int i; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ? ?? s3c2440nand->NFCONT &= ~(1<<1); ?? for(i=0; i<10; i++);??? } ? /* 取消片选信号 */ static voids3c2440_nand_deselect_chip(void) { ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ? ??s3c2440nand->NFCONT |= (1<<1); } ? /* 发出命令 */ static voids3c2440_write_cmd(int cmd) { ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ? ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFCMD; ?? *p = cmd; } ? /* 发出地址 */ static voids3c2440_write_addr(unsigned int addr) { ?? int i; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFADDR; ??? ?? *p = addr & 0xff; ?? for(i=0; i<10; i++); ?? *p = (addr >> 9) & 0xff; ?? for(i=0; i<10; i++); ?? *p = (addr >> 17) & 0xff; ?? for(i=0; i<10; i++); ?? *p = (addr >> 25) & 0xff; ?? for(i=0; i<10; i++); } ? ? /* 发出地址 */ static voids3c2440_write_addr_lp(unsigned int addr) { ?? int i; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFADDR; ?? int col,page; ? ?? col = addr & NAND_BLOCK_MASK_LP; ?? page = addr / NAND_SECTOR_SIZE_LP; ?? ?? *p = col & 0xff; ????????/* Column Address A0~A7 */ ?? for(i=0; i<10; i++);????? ?? *p = (col >> 8) & 0x0f;????? /* Column Address A8~A11 */ ?? for(i=0; i<10; i++); ?? *p = page & 0xff;???????? /* Row Address A12~A19 */ ?? for(i=0; i<10; i++); ?? *p = (page >> 8) & 0xff; ??/* Row Address A20~A27 */ ?? for(i=0; i<10; i++); if (b128MB ==0) ?? *p = (page >> 16) & 0x03;?? /* Row Address A28~A29 */ ?? for(i=0; i<10; i++); } ? /* 读取数据 */ static unsignedchar s3c2440_read_data(void) { ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFDATA; ?? return *p; } ? ? /* 在第一次使用NAND Flash前,复位一下NAND Flash */ static voidnand_reset(void) { ?? s3c2440_nand_reset(); } ? static voidwait_idle(void) { ?? s3c2440_wait_idle(); } ? static voidnand_select_chip(void) { ?? int i; ?? ?? s3c2440_nand_select_chip(); ?? ?? for(i=0; i<10; i++); } ? static voidnand_deselect_chip(void) { ?? s3c2440_nand_deselect_chip(); } ? static voidwrite_cmd(int cmd) { ?? s3c2440_write_cmd(cmd); } static voidwrite_addr(unsigned int addr) { ?? s3c2440_write_addr(addr); } ? static voidwrite_addr_lp(unsigned int addr) { ?? s3c2440_write_addr_lp(addr); } ? static unsignedchar read_data(void) { ?? return s3c2440_read_data(); } ? /* 初始化NAND Flash */ voidnand_init_ll(void) { ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ? ?? #define TACLS?? 0 ?? #define TWRPH0? 3 ?? #define TWRPH1? 0 ? ?? /* 设置时序 */ ?? s3c2440nand->NFCONF =(TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); ?? /* 使能NAND Flash控制器,初始化ECC,禁止片选 */ ?? s3c2440nand->NFCONT =(1<<4)|(1<<1)|(1<<0); ? ?? /* 复位NAND Flash */ ?? nand_reset(); } #if 1 intNF_ReadID(void) { ?? char pMID; ?? char pDID; ?? int?nBuff; ?? char??n4thcycle; ?? int i; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFADDR; ? ?? b128MB = 1; ?? n4thcycle = nBuff = 0; ? ?? nand_init_ll(); ?? nand_select_chip(); ?? write_cmd(0x90);?? // read id command ?? *p=0x00 & 0xff; ?? for ( i = 0; i < 100; i++ ); ? ?? pMID = read_data(); ?? pDID =?read_data(); ?? nBuff =?read_data(); ?? n4thcycle = read_data(); ? ?? nand_deselect_chip(); ?? ?? if (pDID >= 0xA0) ?? { ????? b128MB = 0; ?? } ? ?? return (pDID); } #endif ? /* 读函数 */ intnand_read_ll(unsigned char *buf,int size) { ?? int i,j; ?? char dat; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFADDR; ? ??? ?? if ((start_addr & NAND_BLOCK_MASK) ||(size & NAND_BLOCK_MASK)) ?? { ????? return -1;??? /* 地址或长度不对齐 */ ?? } ? ?? /* 选中芯片 */ ?? nand_select_chip(); ? ?? for(i=start_addr; i < (start_addr +size);) ?? { /* Check BadBlock */ if(1){ ????? /* 发出READ0命令 */ ????? write_cmd(0x50); ? ????? *p = 5; ????? for(j=0; j<10; j++); ????? *p = (i >> 9) & 0xff; ????? for(j=0; j<10; j++); ????? *p = (i >> 17) & 0xff; ????? for(j=0; j<10; j++); ????? *p = (i >> 25) & 0xff; ????? for(j=0; j<10; j++); ????? wait_idle(); ????? dat = read_data(); ????? write_cmd(0); ????? ????? /* 取消片选信号 */ ????? nand_deselect_chip(); ????? if(dat != 0xff) ???????? i += 16384;????? // 1 Block = 512*32= 16384 /* Read Page */ ????? /* 选中芯片 */ ????? nand_select_chip(); } ????? /* 发出READ0命令 */ ????? write_cmd(0); ? ????? /* Write Address */ ????? write_addr(i); ????? wait_idle(); ? ????? for(j=0; j < NAND_SECTOR_SIZE; j++,i++) ????? { ???????? *buf = read_data(); ???????? buf++; ????? } ?? } ? ?? /* 取消片选信号 */ ?? nand_deselect_chip(); ? ?? return 0; } ? /* 读函数 ?* Large Page ?*/ intnand_read_ll_lp(unsigned char *buf,j; ?? char dat; ?? S3C2440_NAND * s3c2440nand = (S3C2440_NAND*)0x4e000000; ?? volatile unsigned char *p = (volatileunsigned char *)&s3c2440nand->NFADDR; ? ?? if ((start_addr & NAND_BLOCK_MASK_LP) ||(size & NAND_BLOCK_MASK_LP)) ?? { ????? return -1;??? /* 地址或长度不对齐 */ ?? } ? ?? /* 选中芯片 */ ?? nand_select_chip(); ? ?? for(i=start_addr; i < (start_addr +size);) ?? { /* Check BadBlock */ if(1){ ????? int col,page; ? ????? col = i & NAND_BLOCK_MASK_LP; ????? page = i / NAND_SECTOR_SIZE_LP; ????? /* 发出READ0命令 */ ????? write_cmd(0x00); ? ????? *p = 5; ????? for(j=0; j<10; j++); ????? *p = 8; ????? for(j=0; j<10; j++); ????? *p = page & 0xff;????? /* Row Address A12~A19 */ ????? for(j=0; j<10; j++); ????? *p = (page >> 8) & 0xff;????? /* Row Address A20~A27 */ ????? for(j=0; j<10; j++); if (b128MB ==0) ????? *p = (page >> 16) & 0x03;????? /* Row Address A28~A29 */ ????? for(j=0; j<10; j++); ? ????? write_cmd(0x30); ????? wait_idle(); ????? dat = read_data(); ????? ????? /* 取消片选信号 */ ????? nand_deselect_chip(); ????? if(dat != 0xff) ???????? i += 131072;????? // 1 Block = 2048*64= 131072 /* Read Page */ ????? /* 选中芯片 */ ????? nand_select_chip(); } ????? /* 发出READ0命令 */ ????? write_cmd(0); ? ????? /* Write Address */ ????? write_addr_lp(i); ????? write_cmd(0x30); ????? wait_idle(); ? ????? for(j=0; j < NAND_SECTOR_SIZE_LP; j++,i++) ????? { ???????? *buf = read_data(); ???????? buf++; ????? } ?? } ? ?? /* 取消片选信号 */ ?? nand_deselect_chip(); ? ?? return 0; } ? intbBootFrmNORFlash(void) { ?? volatile unsigned int *pdw = (volatileunsigned int *)0; ?? unsigned int dwVal; ? ?? /* ??? * 无论是从NOR Flash还是从NAND Flash启动, ??? * 地址0处为指令"b?? Reset",机器码为0xEA00000B, ??? * 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中, ??? * 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。 ??? * 对于NOR Flash,必须通过一定的命令序列才能写数据, ??? * 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动: ??? * 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash ??? */ ? ?? dwVal = *pdw;?????? ?? *pdw = 0x12345678; ?? if (*pdw != 0x12345678) ?? { ????? return 1; ?? } ?? else ?? { ????? *pdw = dwVal; ????? return 0; ?? } } ? intCopyCode2Ram(unsigned long start_addr,unsigned char *buf,int size) { ?? unsigned int *pdwDest; ?? unsigned int *pdwSrc; ?? int i; ? ?? if (bBootFrmNORFlash()) ?? { ????? pdwDest = (unsigned int *)buf; ????? pdwSrc?= (unsigned int *)start_addr; ????? /* 从 NOR Flash启动 */ ????? for (i = 0; i < size / 4; i++) ????? { ???????? pdwDest[i] = pdwSrc[i]; ????? } ????? return 0; ?? } ?? else ?? { ? ????/* 初始化NAND Flash */ ????? nand_init_ll(); ? ????? /* 从 NAND Flash启动 */ ????? if (NF_ReadID() == 0x76 ) ???????? nand_read_ll(buf,start_addr,(size +NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK)); ????? else ???????? nand_read_ll_lp(buf,(size+ NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP)); ????? return 0; ?? } } 3、修改board/samsung/tq2440/config.mk ????? 代码段 25 TEXT_BASE =0x33000000 26 //TEXT_BASE= 0x33F80000 ? ? ? 4、修改Makefile 28 COBJS?? := tq2440.o flash.o nand_start.o 5、修改连接脚本 ??? 修改arch/arm/cpu/arm920t/u-boot.lds (由于这个函数是被第一阶段的汇编程序所调用)。 40???????? .text : 41???????? { 42????????????????arch/arm/cpu/arm920t/start.o???(.text) 43????????????????board/samsung/tq2440/nand_start.o (.text) 44???????????????? *(.text) 45???? ????} 6、将之前注释掉的初始化CPU的函数取消注释 ??? 修改arch/arm/cpu/arm920t/start.S? 第206行: 206???????? bl?????cpu_init_crit ??? 它会调用lowlevel_init子函数(载lowlevel_init.S文件定义)进行CPU的初始化,包括总线宽度,时序响应等。 7、最重要的修改Makefile ?????? 参见我的另一篇博文,u-boot-2010.06 移植到TQ2440从NAND启动不了以及lowlevel_init运行不过去的解决办法。 编译烧写到Nand Flash,从Nand启动,可以看到启动信息。 八、修改uboot使得支持Linux内核启动 1、修改板子头文件include/configs/tq2440.h 43 /* for tag(s) to transfermessage to kernel */ 44 #define CONFIG_SETUP_MEMORY_TAGS1 45 #define CONFIG_CMDLINE_TAG 1 46 #define CONFIG_INITRD_TAG 1 …… 123 /*#define CONFIG_BOOTARGS?????? "root=ramfs devfs=mountconsole=ttySA0,9600" */ 124 #define CONFIG_BOOTARGS"noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0" …… 131 /*#define CONFIG_BOOTCOMMAND??? "tftp; bootm" */ 132 #define CONFIG_BOOTCOMMAND"nand read 0x32000000 0x200000 0x300000; bootm 0x32000000" ? 2、修改机器码 ?? 由于内核机器吗被改成了168,所以这里要改成跟内核一样,不然内核无法启动。在文件arch/arm/include/asm/mach-types.h中修改之前tq2440.c中赋值过的机器码: (gd->bd->bi_arch_number = MACH_TYPE_S3C2440;) ? 375 //#defineMACH_TYPE_S3C2440????????????? 362 376 #defineMACH_TYPE_S3C2440????????????? 168 3、连接mkimage工具 ?? 该工具在生成uImage的时候需要用到,它在编译好uboot之后就在tools文件夹下产生了,把他连接到PATH路径去(注意需要使用完整路径): ? [root@arm 16:50 /home/zhang/uboot]# ln -sf/home/zhang/uboot-2010.06/tools/mkimage /usr/local/bin/mkimage ? 4、编译内核和根文件系统并下载 注意,如果出现文件系统启动之后,隔几秒系统就会自动重启的话,是因为应用层没有喂狗的程序。在文件系统中添加喂狗程序,重新生成文件系统之后就可以了。 Hit any key to stop autoboot:? 0 TQ2440 # TQ2440 # tftp 0x30000000 uImage …… TQ2440 # bootm 0x30000000 …… 这样就会看到内核启动,要是Nand中已经烧录好了根文件系统,就会正常启动。但是掉电之后就没了。 可以通过nand命令将其固化在Nand中,在运行bootm 0x30000000之前: ? 1)???????下载uImage ? TQ2440 # tftp0x30000000 uImage dm9000 i/o: 0x20000000,id: 0x90000a46 DM9000: running in 16 bit mode MAC: 10:23:45:67:89:ab could not establish link Using dm9000 device TFTP from server 192.168.10.96; our IPaddress is 192.168.10.66 Filename 'uImage'. Load address: 0x30000000 Loading:################################################################# ?????? ?################################################################# ?????? ?############################ done Bytes transferred = 2314780 (23521c hex) ? 2)???????擦除NANDFLASH,擦除地址为0x200000,大小为0x300000 的NAND FLASH: ? TQ2440 # nand erase0x200000 0x300000 ? NAND erase: device 0 offset 0x200000,size0x300000 Erasing at 0x4e0000 -- 100% complete. OK ? 3)???????写入NANDFLASH,将地址0x30000000 的SDRAM的数据写入到地址0x200000,大小0x300000 的NAND FLASH ? TQ2440 # nand write0x30000000 0x200000 0x300000 ? NAND write: device 0 offset 0x200000,size0x300000 ?3145728 bytes written: OK TQ2440 # ? ?? 重新启动开发板就可以看到正常引导信息。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |