fl2440 移植u-boot-2010.09全纪录4---------u-boot支持从nandfla
之前我们的u-boot虽然能够运行,但是是在sdram中,并没有烧写到flash中,因此,如果我们重启开发板,之前的u-boot就丢失了。如果我们想要让u-boot上电就启动,那么我们必须要把u-boot烧写到flash中保存起来。 这里我将u-boot固化到nandflash,使u-boot支持从nandflash启动。 一、添加NOR Flash启动和NAND Flash启动的识别 识别u-boot是从nandflash启动还是norflash启动,这里我总结了两种方法: 1 是通过nandflash的datasheet中的记载,其OM[1:0]规定了启动的地点,当OM的低两位为:00时,从nandflash启动,01或者10都为norflash启动,因此可以通过判断这两位的值来判断 代码如下: ?/*OM[1:0]?!=?0,?跳转到NOR?FLASH?启动处,OM[1:0]?=?0,向下执行代码,从nandflash启动 */?? #define?BWSCON?0x48000000 ?? ldr?????r0,?=BWSCON?? ldr?????r0,?[r0]?? ands????r0,?r0,?#0x6?? tst?????r0,?#0x0 bne?????norflash_boot???????????? ? 2是将地址4000003C置为0,如果在地址0000003C中读出的值为0,则代表u-boot从nandflash启动,如果读出的值是0xdeadbeaf,则代表u-boot从norflash启动(原理如下:s3c24x0在上电后,会把内部的sram映射到0x40000000地址上,如果从nandflash启动,sram还将映射到0x00000000地址上。因为0x3c之前的地址空间都被使用,在程序开始的时候做中断向量跳转去了,而且这个地址的值是确定的,也不属于程序,所以我们选择0x0000003c这个地址空间作为检测。如果我们往0x4000003c这个地址上写0,检测到0x0000003c是0,代表是从nandflash启动,如果检测到0xdeadbeaf,代表从norflash启动) 代码如下: ??? ldr r1,=( (4<<28)|(3<<4)|(3<<2) )?????/*载入地址0x4000003C*/ ??? mov r0,#0????? /* r0 = 0 */???? ??? str r0,[r1]????????????????????? /*将R1所代表的地址(0x4000003C)写0*/ ? ??? mov r1,#0x3c?????? /*载入地址 0x0000003C*/ ??? ldr r0,[r1] ??? cmp r0,#0??? ??/*将0x0000003C中的值和0做比较,然后跳转*/ bne NORFLASH_BOOT? ? 二,添加nandflash拷贝代码: #define LENGTH_UBOOT???0x60000 ??? /*Get ready to call C functions for nand_read_ll()*/ ??? ldr sp,DW_STACK_START? @ setup stack pointer ??? mov fp,#0? @ no previous frame,so fp=0 ? ??? /* Read u-boot from Nandflash to SDRAM address $TEXT_BASE */ ??? ldr r0,=TEXT_BASE???? /*nand_read_ll() 1st argument*/ ??? mov r1,#0x0?????????? /*nand_read_ll() 2nd argument*/ ??? mov r2,#LENGTH_UBOOT? /*nand_read_ll() 3rd argument*/ ??? bl? nand_read_ll? ? /*跳转到nand_read_ll函数中,完成相应的操作,注意:nand_read_ll函数需要三个参数,这三个参数分别放在R0,R1,R2中*/ ??? tst r0,#0x0?????????? /*Check nand_read_ll() return value*/ ??? bne infinite_loop???? /*nand_read_ll() not return 0,then goto dead loop*/ ? nand_read_ok:??????? ??? /*Then verify the read data validation, 读取前4K代码,和sram中的代码做比较,确认读取的代码有效,*/ ??? mov r0,#0???????????? /*The first 4K data in internal SRAM*/ ??? ldr r1,=TEXT_BASE???? /*The first 4K data read from Nandflash in SDRAM*/ ??? mov r2,#0x400???????? /*The compare data length*/ ? compare_next_byte: ??? ldr r3,[r0],#4 ??? ldr r4,[r1],#4 ??? teq r3,r4 ??? bne infinite_loop???? ??/*如果出现数据不一样,跳转到infinite_loop,死循环*/ ? ? ??? subs??? r2,r2,#4 ??? beq stack_setup ??? bne compare_next_byte ? infinite_loop: ??? b?? infinite_loop 三,添加C语言从NAND Flash搬移代码部分,刚刚我们看到了汇编部分会调用一个C函数nand_read_ll,这个函数就在nand_read.c文件中 首先在board/fl2440目录下新建一个名为nand_read.c的文件,内容如下 /* ?* nand_read.c: Simple NAND read functions for booting from NAND ?* ?* This is used by cpu/arm920/start.S assembler code, ?* and the board-specific linker script must make sure this ?* file is linked within the first 4kB of NAND flash. ?* ?* Taken from GPLv2 licensed vivi bootloader, ?* Copyright (C) 2002 MIZI Research,Inc. ?* ?* Author: Hwang,Chideok <hwang@mizi.com> ?* Date? : $Date: 2004/02/04 10:37:37 $ ?* ?* u-boot integration and bad-block skipping (C) 2006 by OpenMoko,Inc. ?* Author: Harald Welte <laforge@openmoko.org> ?* ?*Author: hurryliu<hurryliu@126.com> ? ?*/ ? #include <common.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 #if defined(CONFIG_S3C2410) #define NFCONF????????????????__REGi(NF_BASE + 0x0) #define NFCMD?????????__REGb(NF_BASE + 0x4) #define NFADDR????????????????__REGb(NF_BASE + 0x8) #define NFDATA????????????????__REGb(NF_BASE + 0xc) #define NFSTAT?????????????????__REGb(NF_BASE + 0x10) #define NFSTAT_BUSY?????1 #define nand_select()????????(NFCONF &= ~0x800) #define nand_deselect()???(NFCONF |= 0x800) #define nand_clear_RnB()do {} while (0) #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) #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 #define nand_select()????????(NFCONT &= ~(1 << 1)) #define nand_deselect()???(NFCONT |= (1 << 1)) #define nand_clear_RnB()(NFSTAT |= (1 << 2)) #endif ? static inline void nand_wait(void) { ???????? int i; ? ???????? while (!(NFSTAT & NFSTAT_BUSY)) ??????????????????for (i=0; i<10; i++); } ? struct boot_nand_t { ???????? int page_size; ???????? int block_size; ???????? int bad_block_offset; //?????? unsigned long size; }; ? #if 0 #if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440) /* configuration for 2410 with 512byte sized flash */ #define NAND_PAGE_SIZE?????????????????512 #define BAD_BLOCK_OFFSET?5 #define NAND_BLOCK_MASK????????????(NAND_PAGE_SIZE - 1) #define NAND_BLOCK_SIZE??????????????0x4000 #else /* 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) #endif ? /* compile time failure in case of an invalid configuration */ #if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512) #error "S3C2410 does not support nand page size != 512" #endif #endif ? static int is_bad_block(struct boot_nand_t * nand,unsigned long i) { ???????? unsigned char data; ???????? unsigned long page_num; ? ???????? nand_clear_RnB(); ???????? if (nand->page_size == 512) { ??????????????????NFCMD = NAND_CMD_READOOB; /* 0x50 */ ??????????????????NFADDR = nand->bad_block_offset & 0xf; ??????????????????NFADDR = (i >> 9) & 0xff; ??????????????????NFADDR = (i >> 17) & 0xff; ??????????????????NFADDR = (i >> 25) & 0xff; ???????? } else if (nand->page_size == 2048) { ??????????????????page_num = i >> 11; /* addr / 2048 */ ??????????????????NFCMD = NAND_CMD_READ0; ??????????????????NFADDR = nand->bad_block_offset & 0xff; ??????????????????NFADDR = (nand->bad_block_offset >> 8) & 0xff; ??????????????????NFADDR = page_num & 0xff; ??????????????????NFADDR = (page_num >> 8) & 0xff; ??????????????????NFADDR = (page_num >> 16) & 0xff; ??????????????????NFCMD = NAND_CMD_READSTART; ???????? } else { ??????????????????return -1; ???????? } ???????? nand_wait(); ???????? data = (NFDATA & 0xff); ???????? if (data != 0xff) ??????????????????return 1; ? ???????? return 0; } ? static int nand_read_page_ll(struct boot_nand_t * nand,unsigned char *buf,unsigned long addr) { ???????? unsigned short *ptr16 = (unsigned short *)buf; ???????? unsigned int i,page_num; ? ???????? nand_clear_RnB(); ? ???????? NFCMD = NAND_CMD_READ0; ? ???????? if (nand->page_size == 512) { ??????????????????/* Write Address */ ??????????????????NFADDR = addr & 0xff; ??????????????????NFADDR = (addr >> 9) & 0xff; ??????????????????NFADDR = (addr >> 17) & 0xff; ??????????????????NFADDR = (addr >> 25) & 0xff; ???????? } else if (nand->page_size == 2048) { ??????????????????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; ???????? } else { ??????????????????return -1; ???????? } ???????? nand_wait(); ? #if defined(CONFIG_S3C2410) ???????? for (i = 0; i < nand->page_size; i++) { ??????????????????*buf = (NFDATA & 0xff); ??????????????????buf++; ???????? } #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) ???????? for (i = 0; i < (nand->page_size>>1); i++) { ??????????????????*ptr16 = NFDATA16; ??????????????????ptr16++; ???????? } #endif ? ???????? return nand->page_size; } ? static unsigned short nand_read_id() { ???????? unsigned short res = 0; ???????? NFCMD = NAND_CMD_READID; ???????? NFADDR = 0; ???????? res = NFDATA; ???????? res = (res << 8) | NFDATA; ???????? return res; } ? extern unsigned int dynpart_size[]; ? /* low level nand read function */ int nand_read_ll(unsigned char *buf,unsigned long start_addr,int size) { ???????? int i,j; ???????? unsigned short nand_id; ???????? struct boot_nand_t nand; ? ???????? /* chip Enable */ ???????? nand_select(); ???????? nand_clear_RnB(); ???????? ???????? for (i = 0; i < 10; i++) ??????????????????; ???????? nand_id = nand_read_id(); ???????? if (0) { /* dirty little hack to detect if nand id is misread */ ??????????????????unsigned short * nid = (unsigned short *)0x31fffff0; ??????????????????*nid = nand_id; ???????? }??????? ? ?????? if (nand_id == 0xec76 ||?????????? /* Samsung K91208 on SD2410 board */ ?????????? nand_id == 0xad76 ) {????? /*Hynix HY27US08121A*/ ??????????????????nand.page_size = 512; ??????????????????nand.block_size = 16 * 1024; ??????????????????nand.bad_block_offset = 5; ???????? //?????? nand.size = 0x4000000; ???????? } else if (nand_id == 0xecf1 ||????? /* Samsung K9F1G08U0B */ ?????????? nand_id == 0xadda || /*? Hynix HY27UF082G2B on FL2440 board */ ???????????????????? nand_id == 0xecda ||???? /* Samsung K9F2G08U0B on FL2440 board */ ???????????????????? nand_id == 0xecd3 )????? { /* Samsung K9K8G08 */ ??????????????????nand.page_size = 2048; ??????????????????nand.block_size = 128 * 1024; ??????????????????nand.bad_block_offset = nand.page_size; ???????? //?????? nand.size = 0x8000000; ???????? } else { ??????????????????return -1; // hang ???????? } ???????? if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1)))) ??????????????????return -1;? /* invalid alignment */ ? ???????? for (i=start_addr; i < (start_addr + size);) { #ifdef CONFIG_S3C2410_NAND_SKIP_BAD ??????????????????if (i & (nand.block_size-1)== 0) { ???????????????????????????if (is_bad_block(&nand,i) || ?????????????????????????????? is_bad_block(&nand,i + nand.page_size)) { ????????????????????????????????????/* Bad block */ ????????????????????????????????????i += nand.block_size; ????????????????????????????????????size += nand.block_size; ????????????????????????????????????continue; ???????????????????????????} ??????????????????} #endif ??????????????????j = nand_read_page_ll(&nand,buf,i); ??????????????????i += j; ??????????????????buf += j; ???????? } ? ???????? /* chip Disable */ ???????? nand_deselect(); ? ???????? return 0; } 四,修改board/fl2440/Makefile文件,使得nand_read.c能被编译到u-boot.bin中(28行) COBJS?? := fl2440.onand_read.o flash.o 五,修改文件arch/arm/cpu/arm920t/u-boot.lds,将u-boot从nandflash搬运的代码链接到前4K的u-boot.bin中(40行左右) ??? .text : ??? { ??????? arch/arm/cpu/arm920t/start.o??? (.text) ??????? board/fl2440/lowlevel_init.o (.text) ??????? board/fl2440/nand_read.o (.text) ??????? *(.text) } 六,修改include/configs/fl2440.h文件,让u-boot支持nandflash串口操作 ? /*----------------------------------------------------------------------- ?* NAND flash settings ?*/ #if defined(CONFIG_CMD_NAND) #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_MAX_NAND_DEVICE?1?? /* Max number of NAND devices?????? */ #define CONFIG_SYS_NAND_BASE 0x4E000000 #define SECTORSIZE 512 #define SECTORSIZE_2K 2048 #define NAND_SECTOR_SIZE SECTORSIZE #define NAND_SECTOR_SIZE_2K SECTORSIZE_2K #define NAND_BLOCK_MASK 511 #define NAND_BLOCK_MASK_2K 2047 #define NAND_MAX_CHIPS 1 #define CONFIG_MTD_NAND_VERIFY_WRITE #define CONFIG_SYS_64BIT_VSPRINTF??????/* needed for nand_util.c */ #endif? /* CONFIG_CMD_NAND */ 七,修改drivers/mtd/nand/s3c2410_nand.c文件,支持nandflash的读写(27行左右) 修改宏定义如下 #define NF_BASE????????0x4e000000 #if defined(CONFIG_S3C2410)?? #define S3C2410_NFCONF_EN?????????(1<<15) #define S3C2410_NFCONF_512BYTE????(1<<14) #define S3C2410_NFCONF_4STEP??????(1<<13) #define S3C2410_NFCONF_INITECC????(1<<12) #define S3C2410_NFCONF_nFCE???????(1<<11) #define S3C2410_NFCONF_TACLS(x)???((x)<<8) #define S3C2410_NFCONF_TWRPH0(x)??((x)<<4) #define S3C2410_NFCONF_TWRPH1(x)??((x)<<0) ? #define S3C2410_ADDR_NALE 4 #define S3C2410_ADDR_NCLE 8 #endif ? #if defined(CONFIG_S3C2440)?? #define S3C2410_NFCONT_EN?????????(1<<0)?? #define S3C2410_NFCONT_INITECC????(1<<4)?? #define S3C2410_NFCONT_nFCE???????(1<<1)?? #define S3C2410_NFCONT_MAINECCLOCK (1<<5)?? #define S3C2410_NFCONF_TACLS(x)???((x)<<12)?? #define S3C2410_NFCONF_TWRPH0(x)??((x)<<8)?? #define S3C2410_NFCONF_TWRPH1(x)??((x)<<4)?? ? #define S3C2410_ADDR_NALE 0x08?? #define S3C2410_ADDR_NCLE 0x0c?? #endif ulong IO_ADDR_W = NF_BASE; ? #ifdef CONFIG_NAND_SPL 修改s3c2410_hwcontrol函数为如下 ? static void s3c2410_hwcontrol(struct mtd_info *mtd,int cmd,unsigned int ctrl) { //? struct nand_chip *chip = mtd->priv; ??? struct s3c2410_nand *nand = s3c2410_get_base_nand(); ? ??? debugX(1,"hwcontrol(): 0x%02x 0x%02xn",cmd,ctrl); ? ??? if (ctrl & NAND_CTRL_CHANGE) { ??????? //ulong IO_ADDR_W = (ulong)nand; ??????? IO_ADDR_W = (ulong)nand; ? ??????? if (!(ctrl & NAND_CLE)) ??????????? IO_ADDR_W |= S3C2410_ADDR_NCLE; ??????? if (!(ctrl & NAND_ALE)) ??????????? IO_ADDR_W |= S3C2410_ADDR_NALE; ? //????? chip->IO_ADDR_W = (void *)IO_ADDR_W; ? ??????? if (ctrl & NAND_NCE) #if defined(CONFIG_S3C2410)??/* modify by hurryliu */ ??????????? writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,&nand->NFCONF); #elif defined(CONFIG_S3C2440) ??????????? writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE,&nand->NFCONT); #endif ??????? else #if defined(CONFIG_S3C2410)?? ??????????? writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,&nand->NFCONF); #elif defined(CONFIG_S3C2440) ??????????? writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE,&nand->NFCONT); #endif ??? } ? ??? if (cmd != NAND_CMD_NONE) ??????? //writeb(cmd,chip->IO_ADDR_W); ??????? writeb(cmd,(void *)IO_ADDR_W); } 修改s3c2410_nand_enable_hwecc函数如下: void s3c2410_nand_enable_hwecc(struct mtd_info *mtd,int mode) { ??? struct s3c2410_nand *nand = s3c2410_get_base_nand(); ??? debugX(1,"s3c2410_nand_enable_hwecc(%p,%d)n",mtd,mode); #if defined(CONFIG_S3C2410) ??? writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC,&nand->NFCONF); #elif defined(CONFIG_S3C2440)??????????????/*add by hurryliu*/ ??? writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC,&nand->NFCONT); #endif } 修改board_nand_init函数如下: int board_nand_init(struct nand_chip *nand) { ??? u_int32_t cfg; ??? u_int8_t tacls,twrph0,twrph1; ??? struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); ??? struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); ? ??? debugX(1,"board_nand_init()n"); ? ??? writel(readl(&clk_power->CLKCON) | (1 << 4),&clk_power->CLKCON); ? #if defined(CONFIG_S3C2410)? ??? /* initialize hardware */ ??? twrph0 = 3; ??? twrph1 = 0; ??? tacls = 0; ? ??? cfg = S3C2410_NFCONF_EN; ??? cfg |= S3C2410_NFCONF_TACLS(tacls - 1); ??? cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); ??? cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); ??? writel(cfg,&nand_reg->NFCONF); ? ??? /* initialize nand_chip data structure */ ??? nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; #elif defined(CONFIG_S3C2440)?? ?? /*? initialize hardware */ ??? tacls = 0; ??? twrph0 = 4; ??? twrph1 = 2; ? ? ??????? cfg = 0; ??????? cfg |= S3C2410_NFCONF_TACLS(tacls - 1); ??????? cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); ??????? cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); ??????? writel(cfg,&nand_reg->NFCONF); ? ??????? cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0); ??????? writel(cfg,&nand_reg->NFCONT); ??????? /*? initialize nand_chip data structure */ ??????? nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; #endif ? ??? nand->select_chip = NULL; ? ??? /* read_buf and write_buf are default */ ??? /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL ??? nand->read_buf = nand_read_buf; #endif ? ??? /* hwcontrol always must be implemented */ ??? nand->cmd_ctrl = s3c2410_hwcontrol; ? ??? nand->dev_ready = s3c2410_dev_ready; ? #ifdef CONFIG_S3C2410_NAND_HWECC ??? nand->ecc.hwctl = s3c2410_nand_enable_hwecc; ??? nand->ecc.calculate = s3c2410_nand_calculate_ecc; ??? nand->ecc.correct = s3c2410_nand_correct_data; ??? nand->ecc.mode = NAND_ECC_HW; ??? nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; ??? nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #else ??? nand->ecc.mode = NAND_ECC_SOFT; #endif ? #ifdef CONFIG_S3C2410_NAND_BBT ??? nand->options = NAND_USE_FLASH_BBT; #else ??? nand->options = 0; #endif ? ??? debugX(1,"end of nand_initn"); ? ??? return 0; } 添加nandflash寄存器的定义board/fl2440/lowlevel_init.S #define S3C24X0_INTERRUPT_BASE????? 0x4A000000 #define INTMSK_OFFSET?????????????? 0x08 #define MDIV_405??????????????????? 0x7f << 12 #define PSDIV_405?????????????????? 0x21 #define MDIV_200??????????????????? 0xa1 << 12 #define PSDIV_200?????????????????? 0x31 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |