從nandflash啟動最關鍵的部分是rellocated,即代碼重定位。s3c2440數據手冊有這么一段,所以代碼重定位是由nandflash控制器自動完成的,而不是一些人說的由CPU完成的。 在include/configs/TE2440II.h中添加nandflash控制器的定義: /* * NAND flash setting */ #if defined(CONFIG_CMD_NAND) #define CONFIG_SYS_NAND_BASE 0x4e000000 #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_MTD_NAND_VERIFY_WRITE 1 #define NAND_SAMSUNG_LP_OPTIONS 1 //大頁要添加這個 #define CONFIG_NAND_S3C2440 1 #define CONFIG_S3C2440_NAND_BOOT 1 #define NAND_CTL_BASE 0x4E000000 #define oNFCONF 0x00 #define oNFCONT 0x04 #define oNFADDR 0x0c #define oNFDATA 0x10 #define oNFCMD 0x08 #define oNFSTAT 0x20 #define oNFECC 0x2c #endif 在 /* * Command line configuration. */ 下添加 #define CONFIG_CMD_NAND 修改環境變量那部分 //#undef CONFIG_ENV_IS_IN_FLASH 1 #define CONFIG_ENV_IS_IN_NAND 1 其次,修改cpu/arm920t/start.S這個文件,使u-boot從Nand Flash啟動 為了讓他自動識別是從norflash還是從nandflash啟動添加,BWSCON的第2,1為即OM1,OM0。為00時是從nandflash啟動,其他為從norflash啟動,判斷OM1和OM0,就可以讓uboot自動識別啟動方式。 #define BWSCON 0x48000000 ldr r0, =BWSCON ldr r1,[r0] ands r1, r1, #0x6 beq nand_boot nor_boot: #ifndef CONFIG_SKIP_RELOCATE_UBOOT 添加nandflash的啟動代碼,核心是relocated部分。首先設置nandflash控制器,然后將nandflash中從0開始的uboot復制到SDRAM中的TEXT_BASE處,TEXT_BASE在config.mk中定義,值為0x33f80000。復制好后,比較nandflash和SDRAM中的數據,如果前4K相同,表示搬移成功。下面的匯編代碼注意ATPC標準規定r0"r3,用于參數傳遞和返回值。 /********************************************************/ //#define CONFIG_S3C2440_NAND_BOOT 1 nand_boot: #define CONFIG_S3C2440_NAND_BOOT 1 #define NAND_CTL_BASE 0x4E000000 /* Offset */ #define oNFCONF 0x00 #define oNFCONT 0x04 #define oNFCMD 0x08 #define oNFSTAT 0x20 #define LENGTH_UBOOT 0x40000 @ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) str r2, [r1, #oNFCONF] ldr r2, [r1, #oNFCONF] ldr r2, =((1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control str r2, [r1, #oNFCONT] ldr r2, [r1, #oNFCONT] ldr r2, =(0x6) @ RnB Clear str r2, [r1, #oNFSTAT] ldr r2, [r1, #oNFSTAT] mov r2, #0xff @ RESET command strb r2, [r1, #oNFCMD] mov r3, #0 @ wait nand1: add r3, r3, #0x1 cmp r3, #0xa blt nand1 nand2: ldr r2, [r1, #oNFSTAT] @ wait ready tst r2, #0x4 beq nand2 ldr r2, [r1, #oNFCONT] orr r2, r2, #0x2 @ Flash Memory Chip Disable str r2, [r1, #oNFCONT] @ 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 U-Boot to RAM ldr r0, =TEXT_BASE //傳遞給C代碼的第一個參數:u-boot在RAM中的起始地址 mov r1, #0x0 //傳遞給C代碼的第二個參數:Nand Flash的起始地址 mov r2, #LENGTH_UBOOT //傳遞給C代碼的第三個參數:u-boot的長度大小 /**********************************************************/ /************************************************************/ bl nand_read_ll tst r0, #0x0 beq ok_nand_read bad_nand_read: loop2: b loop2 @ infinite loop ok_nand_read: @ verify mov r0, #0 ldr r1, =TEXT_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 stack_setup bne go_next notmatch: loop3: b loop3 @ infinite loop #endif /* Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */ #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* leave 3 words for abort-stack */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l ldr pc, _start_armboot _start_armboot: .word start_armboot #define STACK_BASE 0x33ff8000 #define STACK_SIZE 0x10000 .align 2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 在board/samsung/TE2440II/目錄下添加nand_read.c文件,內容如下,在K9F2G08的datasheet中有這么一段 所以地址由5個周期傳完。前兩個周期用來尋頁內地址。后三個周期是頁間尋址。1device=2048block=2048*64page=2048*64*(2k+64)Bytes #include <config.h> #include <linux/mtd/nand.h> #define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGw(x) (*(volatile unsigned short *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x)) #define NF_BASE 0x4e000000 #define NFCONF __REGi(NF_BASE + 0x0) #define NFCONT __REGi(NF_BASE + 0x4) #define NFCMD __REGb(NF_BASE + 0x8) #define NFADDR __REGb(NF_BASE + 0xc) #define NFDATA __REGb(NF_BASE + 0x10) #define NFDATA16 __REGw(NF_BASE + 0x10) #define NFSTAT __REGb(NF_BASE + 0x20) #define NFSTAT_BUSY (1 << 2) #define nand_select() (NFCONT &= "(1 << 1)) #define nand_deselect() (NFCONT |= (1 << 1)) #define nand_clear_RnB() (NFSTAT |= NFSTAT_BUSY) static inline void nand_wait(void) { int i; while (!(NFSTAT & NFSTAT_BUSY)) for (i=0; i<10; i++); } /* configuration for 2440 with 2048byte sized flash */ #define NAND_5_ADDR_CYCLE #define NAND_PAGE_SIZE 2048 #define BAD_BLOCK_OFFSET NAND_PAGE_SIZE #define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1) #define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64) static int nand_read_page_ll(unsigned char *buf, unsigned long addr) { unsigned int i, page_num; nand_clear_RnB(); NFCMD = NAND_CMD_READ0; page_num = addr >> 11; /* addr / 2048 */ /* Write Address */ NFADDR = 0; NFADDR = 0; NFADDR = page_num & 0xff; NFADDR = (page_num >> 8) & 0xff; NFADDR = (page_num >> 16) & 0xff; NFCMD = NAND_CMD_READSTART; nand_wait(); for (i = 0; i < NAND_PAGE_SIZE; i++) { *buf = (NFDATA & 0xff); buf++; } return NAND_PAGE_SIZE; } /* low level nand read function */ int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { int i, j; if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */ } /* chip Enable */ nand_select(); nand_clear_RnB(); for (i=0; i<10; i++); for (i=start_addr; i < (start_addr + size);) { j = nand_read_page_ll(buf, i); i += j; buf += j; } /* chip Disable */ nand_deselect(); return 0; } 然后在Makefile中添加 COBJS:=my2440.o flash.onand_read.o 修改TE2440II下的鏈接腳本u-boot.lds,使初始化和重定位代碼被鏈接到前4KB。 .text: { cpu/arm920t/start.o(.text) board/samsung/my2440/lowlevel_init.o(.text) board/samsung/my2440/nand_read.o(.text) *(.text) } 李萬鵬 |