U-Boot从NAND Flash启动的实现

合集下载

u-boot_2010.6nandflash驱动彻底分析

u-boot_2010.6nandflash驱动彻底分析

u-boot_2010.6nandflash驱动彻底分析2017年11⽉13⽇15:37:34最近公司⼤裁员,闹的⼈⼼惶惶,不管怎么样,武装好⾃⼰才是硬道理,坚持学习,学会那些还没学会的。

今天虚拟机突然打不开了,吓了我⼀跳,因为代码都还没备份,⼀定得养成备份代码的习惯!好了,下⾯开始进⼊正题吧,nandflash驱动彻底分析底层驱动移植完后,执⾏nand 命令:nand read 0x30000000 0 0x2000nand read 的命令格式是 nand read addr off | partition size ,总结起来就是读到哪去?从哪读?读多⼤?返回的结果是:NAND read: device 0 offset 0x0, size 0x2000file is nand_util.c,fun is nand_read_skip_bad,line is 599,NAND read from offset 2000 failed -740 bytes read: ERROR读失败,给出读失败错误码 -74要分析失败原因,先分析函数执⾏流程执⾏nand read 命令后,其实是执⾏了nand_read_skip_bad(nand, off, &size,(u_char *)addr);跳过坏块读函数的参数简单明了,从哪读,读到哪去,读多少,以及⼀个公共句柄(包含nand的信息,例如有多少个块,块⼤⼩等) 1int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,2 u_char *buffer)3 {4int rval;5 size_t left_to_read = *length;6 size_t len_incl_bad;7 u_char *p_buffer = buffer;89 len_incl_bad = get_len_incl_bad (nand, offset, *length); /* 函数分析见2017.11.14笔记(往下翻) */1011if ((offset + len_incl_bad) > nand->size) {12 printf ("Attempt to read outside the flash area\n");13return -EINVAL;14 }1516if (len_incl_bad == *length) {17 rval = nand_read (nand, offset, length, buffer);18if (!rval || rval == -EUCLEAN)19return0;20 printf ("NAND read from offset %llx failed %d\n",21 offset, rval);22return rval;23 }2425while (left_to_read > 0) {26 size_t block_offset = offset & (nand->erasesize - 1);27 size_t read_length;2829 WATCHDOG_RESET ();3031if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {32 printf ("Skipping bad block 0x%08llx\n",33 offset & ~(nand->erasesize - 1));34 offset += nand->erasesize - block_offset;35continue;36 }3738if (left_to_read < (nand->erasesize - block_offset))39 read_length = left_to_read;40else41 read_length = nand->erasesize - block_offset;42/* read_length 最⼤不会超过 nand->erasesize (128K) */43/* nand_read 函数是⼀个按块读函数 */44 rval = nand_read (nand, offset, &read_length, p_buffer);45if (rval && rval != -EUCLEAN) {46 printf ("NAND read from offset %llx failed %d\n",47 offset, rval);48 *length -= left_to_read;49return rval;50 }5152 left_to_read -= read_length;53 offset += read_length;54 p_buffer += read_length;55 }5657return0;58 }先看get_len_incl_bad1static size_t get_len_incl_bad (nand_info_t *nand, loff_t offset,2const size_t length)3 {4 size_t len_incl_bad = 0;5 size_t len_excl_bad = 0;6 size_t block_len;78while (len_excl_bad < length) {9 block_len = nand->erasesize - (offset & (nand->erasesize - 1));1011if (!nand_block_isbad (nand, offset & ~(nand->erasesize - 1)))12 len_excl_bad += block_len;1314 len_incl_bad += block_len;15 offset += block_len;1617if (offset >= nand->size)18break;19 }2021return len_incl_bad;22 }想要看懂这个函数,先要理解offset的构成2017年11⽉14⽇10:00:40每天进步⼀点点nand->erasesize = 128K = 0x20000nand->erasesize - 1 = 0x1FFFFoffset & (nand->erasesize - 1) 保留低17位,清⾼位,因为nand的特性,所以是按块来统计长度block_len = nand->erasesize - offset & (nand->erasesize - 1) 作⽤是统计当前块要读的长度然后判断当前块是不是坏块,如果不是坏块,则让len_excl_bad += block_len,判断是否循环的标准是len_excl_bad < length 不论当前块是不是坏块,都让len_incl_bad += block_len,len_incl_bad 得到的是包含坏块的长度总结get_len_incl_bad函数的作⽤为:①如果偏移offset是从整块开始的,返回的结果是块的整数倍(不⽤看length,⽐如length是0x20001,则读两块)②如果偏移offset不是从整块开始的,返回的结果是块的整数倍+第⼀块要读的长度总之,返回的结果是按块补齐的再继续分析nand_read_skip_bad1if (len_incl_bad == *length) {2 rval = nand_read (nand, offset, length, buffer);3if (!rval || rval == -EUCLEAN)4return0;56return rval;7 }什么情况下,len_incl_bad == *length ?要读的内容⾥,没有坏块,且长度最后按块对齐(例如,从0x400开始读,读的长度为0x40000-0x400)如果不满⾜,则进⼊while循环读,在while⾥,按块读,先判断当前块是不是坏块,如果是则跳过,不是则读下⾯分析nand_read函数1/* 1.从哪读 2.读多少 3.读到哪去 */2static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,3 size_t *retlen, uint8_t *buf)4 {5struct nand_chip *chip = mtd->priv;6int ret;78/* Do not allow reads past end of device */9if ((from + len) > mtd->size)10return -EINVAL;11if (!len)12return0;13/* 选中芯⽚ */14 nand_get_device(chip, mtd, FL_READING);1516 chip->ops.len = len;17 chip->ops.datbuf = buf;18 chip->ops.oobbuf = NULL;1920 ret = nand_do_read_ops(mtd, from, &chip->ops);2122 *retlen = chip->ops.retlen;23/* 取消选中芯⽚ */24 nand_release_device(mtd);2526return ret;27 }其实真正的读函数是nand_do_read_ops,从哪去,读多少,读到哪去都被装载在chip->ops结构体中再看nand_do_read_ops函数1/**2 * nand_do_read_ops - [Internal] Read data with ECC3 *4 * @mtd: MTD device structure5 * @from: offset to read from6 * @ops: oob ops structure7 *8 * Internal function. Called with chip held.9*/10static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,11struct mtd_oob_ops *ops)12 {13int chipnr, page, realpage, col, bytes, aligned;14struct nand_chip *chip = mtd->priv;15struct mtd_ecc_stats stats;16int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;17int sndcmd = 1;18int ret = 0;19 uint32_t readlen = ops->len;//128K 0x20000 根据输⼊的长度决定20 uint32_t oobreadlen = ops->ooblen; // oobreadlen = 021 uint8_t *bufpoi, *oob, *buf;2223 stats = mtd->ecc_stats;2425 chipnr = (int)(from >> chip->chip_shift);26 chip->select_chip(mtd, chipnr);27/* realpage 总页地址(⾼17位) */28 realpage = (int)(from >> chip->page_shift);//pageshift is 1129 page = realpage & chip->pagemask;//pagemask = 1ffff30/* col 低11位 */31 col = (int)(from & (mtd->writesize - 1));//writesize = 2048, 2047 = 0x7ff32/* 得到页地址和列地址 */33 buf = ops->datbuf;34 oob = ops->oobbuf;3536while(1) {37 bytes = min(mtd->writesize - col, readlen); //128K 0x20000 根据输⼊的长度决定38 aligned = (bytes == mtd->writesize); //aligned = 1;3940/* Is the current page in the buffer ? */41if (realpage != chip->pagebuf || oob) {42 bufpoi = aligned ? buf : chip->buffers->databuf;43/* 对齐与不对齐读到的缓冲是不⼀样的 */44if (likely(sndcmd)) {45 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);46 sndcmd = 0;47 }4849/* Now read the page into the buffer */50if (unlikely(ops->mode == MTD_OOB_RAW))51 ret = chip->ecc.read_page_raw(mtd, chip,//nand_read_page_raw52 bufpoi, page);//从哪⾥读,读到哪⾥去,读多少53else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)54 ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);55/* nand_read_subpage */56else57 ret = chip->ecc.read_page(mtd, chip, bufpoi,//整页读 bufpoi = buf58 page); //nand_read_page_swecc59if (ret < 0)60break;6162/* Transfer not aligned data */63if (!aligned) {64if (!NAND_SUBPAGE_READ(chip) && !oob)65 chip->pagebuf = realpage;66 memcpy(buf, chip->buffers->databuf + col, bytes);67 }6869 buf += bytes;7071if (unlikely(oob)) {72/* Raw mode does data:oob:data:oob */73if (ops->mode != MTD_OOB_RAW) {74int toread = min(oobreadlen,75 chip->yout->oobavail);76if (toread) {77 oob = nand_transfer_oob(chip,78 oob, ops, toread);79 oobreadlen -= toread;80 }81 } else82 buf = nand_transfer_oob(chip,83 buf, ops, mtd->oobsize);84 }8586if (!(chip->options & NAND_NO_READRDY)) {87/*88 * Apply delay or wait for ready/busy pin. Do89 * this before the AUTOINCR check, so no90 * problems arise if a chip which does auto91 * increment is marked as NOAUTOINCR by the92 * board driver.93*/94if (!chip->dev_ready)95 udelay(chip->chip_delay);96else97 nand_wait_ready(mtd);98 }99 } else {100 memcpy(buf, chip->buffers->databuf + col, bytes);101 buf += bytes;102 }103104 readlen -= bytes;105106if (!readlen)107break;108109/* For subsequent reads align to page boundary. */110 col = 0;111/* Increment page address */112 realpage++;113114 page = realpage & chip->pagemask;115/* Check, if we cross a chip boundary */116if (!page) {117 chipnr++;118 chip->select_chip(mtd, -1);119 chip->select_chip(mtd, chipnr);120 }121122/* Check, if the chip supports auto page increment123 * or if we have hit a block boundary.124*/125if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))126 sndcmd = 1;127 }128129 ops->retlen = ops->len - (size_t) readlen;130if (oob)131 ops->oobretlen = ops->ooblen - oobreadlen;132133if (ret)134return ret;135136if (mtd->ecc_stats.failed - stats.failed)137return -EBADMSG;138139return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 140 }。

U-BOOT启动过程

U-BOOT启动过程

U-Boot启动过程U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能Ø硬件设备初始化Ø加载U-Boot第二阶段代码到RAM空间Ø设臵好栈Ø跳转到第二阶段代码入口(2)第二阶段的功能Ø初始化本阶段使用的硬件设备Ø检测系统内存映射Ø将内核从Flash读取到RAM中Ø为内核设臵启动参数Ø调用内核1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。

U-Boot启动第一阶段流程如下:图 2.1 U-Boot启动第一阶段流程根据cpu/arm920t/u-boot.lds中指定的连接方式:ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)board/samsung/mini2440/lowlevel_init.o (.text)board/samsung/mini2440/nand_read.o (.text)*(.text)}……}第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。

下面我们来分析cpu/arm920t/start.S的执行。

1.硬件设备初始化(1)设臵异常向量cpu/arm920t/start.S开头有如下的代码:.globl _start_start: b start_code /* 复位*/ldr pc, _undefined_instruction /* 未定义指令向量 */ldr pc, _software_interrupt /* 软件中断向量*/ldr pc, _prefetch_abort /* 预取指令异常向量 */ldr pc, _data_abort /* 数据操作异常向量 */ldr pc, _not_used /* 未使用 */ldr pc, _irq /* irq中断向量 */ldr pc, _fiq /* fiq中断向量 *//* 中断向量表入口地址 */_undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq.balignl 16,0xdeadbeef以上代码设臵了ARM异常向量表,各个异常向量介绍如下:表 2.1 ARM异常向量表在cpu/arm920t/start.S中还有这些异常对应的异常处理程序。

U-boot烧内核到NandFlash步骤

U-boot烧内核到NandFlash步骤

U-boot烧内核到NandFlash步骤
1.把uImage内核镜象放到TFT服务器文件夹内。

2.配置Window下的IP地址:192.168.0.30 这个其实也是TFTP服务器的地址。

3.修改u-boot配置文件u-boot-1.3.4/include/configs/xyd2440.h
修改为:
4.保存文件,重新编译u-boot.把生成的u-boot文件烧录到Norflash中。

5.重新启动开发板,
6.内核的启动过程:(在2 的条件下)
#tftp 30000000 uImage ; 通过tftp 命令将uImage 文件下载到内存30000000 位置。

(#bootm 32000000 ; 跳到内存32000000 处运行)。

#nand erase
#nand write.jffs2 32000000 100000322b90 ; 将内存32000000 处的数据写到NAND 的0 地址处大小为322b90 322b90这个值是内核大小,是执行tftp 32000000 uImage ;命令后下载内核产生的值,根据实际情况修改。

100000这个值是内核在NandFlash起始地址,要和。

中#defind CONFIG_BOOTCOMMAND “nboot 0x32000000 0 100000; bootm 0x32000000”中的100000相同。

7.重启开发板,如果有以下信息表示已经成功烧录。

(启动linux的信息)。

uboot启动参数设置

uboot启动参数设置
tftp 30800000 uImage 获取uImage,存放到内存的30800000
nand erase 40000 1c0000 nand erase offset size
nand write 30800000 40000 1c0000 存放内存30800000位置上的uImge,烧写到nandflash的40000位置上
=========================================================================================
例如如下:
FS2410# setenv serverip 192.168.7.x (其中X是虚拟机中IP的最后的数字[用ifconfig可以获取])
farsight_N中的N用座位号来表示,比如座位4即为farsight_4 //设置uboot传给内核的参数
saveenv
自定义参数版本:
4.设置UBOOT参数
确保一下FS2410的核心班上的JP1跳线帽短接了,给板子上电,
查看板子启动信息,如果板子启动信息中,有U-Boot 1.3.1(Oct 25 2008 - 15:45:21)或者更新的版本,则直接设置下面的参数,否则根据文档烧录 u-boot131-for-farsight-shenzhen-advanced-drivers.bin(请参考文档"farsight-实验前的准备步骤-v2.3.doc")
setenv bootargs console=ttySAC0,115200 init=/linuxrc root=/dev/nfs nfsroot=192.168.7.113:/opt/filesystem ip=192.168.7.173:192.168.7.113:192.168.7.1:255.255.255.0:farsight_13:eth0:off //或者console=ttySAC0,115200 root=1f02 rootfstype=jffs2 rw init=/linuxrc mem=64M

移植笔记从Norflash启动的uboot

移植笔记从Norflash启动的uboot

移植笔记从Norflash启动的uboot uboot移植记录之一uboot整个移植过程我们可以分为三个阶段:一,移植可以从Nor flash启动的uboot这个阶段是移植一个最简单的uboot,可以烧在Nor flash内运行.二,移植支持Nand flash驱动的uboot加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行.三,移植可以从Nor flash启动的uboot可以烧录在Nand flash,并设置从Nand flash启动运行uboot.分三个阶段进行移植,可以对整个uboot的移植过程及原理更加清晰明了,同时降低了发现问题时解决问题的困难度和解决范围.首先介绍移植可以从Nor flash启动的uboot. 这个阶段相对简单一点,是移植一个最简单的uboot,可以烧在Nor flash内运行.不需要修改太多的东西。

步骤如下: 测试一下默认的smdk2410_config配置能否在你的板子上正常运行 1.编译uboot1.1.4#make smdk2410_config#make ARCH=arm注:编译针对arm的平台时,uboot默认使用arm-linux-gcc编译,若交叉编译器名字不一样,需要自行在Makefile里修改。

会出现两个错误.错误信息一:cc1: Invalid option `abi=apcs-gnu'make[1]: *** [hello_world.o] Error 1make[1]: Leaving directory `/root/u-boot-1.1.4/examples'make: *** [examples] Error 2解决办法:出错的文件是/cpu/arm920t/下的config.mk:将PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) 改成: PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,$(callcc-option,-mabi=apcs-gnu,))错误信息二:make[1]: *** No rule to make target `hello_world.srec', needed by`all'. Stop. make[1]: Leaving directory `/work/src/u-boot-1.1.4/examples' 解决方法:打开 examples/Makefile把example文件夹下的Makefile中的第126行%.srec: % 改成 %.srec: %.o第129行的%.bin: % 改成 %.bin: %.o2.若编译成功,则会在uboot源码下产生u-boot.bin文件。

Nandflashuboot命令详解

Nandflashuboot命令详解

Nandflashuboot命令详解(转⾃)nand info & nand device显⽰flash的信息:DM365 :>nand infoDevice 0: NAND 32MiB 3,3V 8-bit, sector size 16 KiBDM365 :>nand deviceDevice 0: NAND 32MiB 3,3V 8-bitnand read(.oob) addr off size不管是读取data, 使⽤nand read,还是读取oob,使⽤命令nand read.oob,后⾯跟的地址addr,都是ram的地址,off指的是nand flash的地址, size:指要读取nand flash的数据⼤⼩,但是如果是读取oob, size不能超过⼀个page 的oob size,如果page size为512个字节, oob size就是16个字节.DM365 :>nand read 86000000 58000 100NAND read: device 0 offset 0x58000, size 0x100256 bytes read: OKDM365 :>md 86000000 4086000000: ea000012 e59ff014 e59ff014 e59ff014 ................…………860000f0: e1a0000d eb00022e 00000000 00000000 ................DM365 :>nand read.oob 86000000 58000 10NAND read: device 0 offset 0x58000, size 0x1016 bytes read: OKDM365 :>md 86000000 4086000000: ffffffff 2707ffff 33e316ad 44b2e1a1 .......'...3...D如果⼀次想读取完整的⼀个page 的值,包含oob,使⽤下⾯将的命令, nand dump.nand dump [addr] [size]调⽤过程: nand dump addr size (common/cmd_nand.c)==> nand_dump() ==> nand_read_raw();nand dump 不管你的size有多⼤,⾄少会dump出⼀个page的⼤⼩:SMDK2440 # nand dump 0 100Page 00000000 dump:12 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e514 f0 9f e5 14 f0 9f e5 14 f0 9f e5 14 f0 9f e500 02 f8 33 60 02 f8 33 c0 02 f8 33 20 03 f8 3380 03 f8 33 e0 03 f8 33 40 04 f8 33 ef be ad de00 00 f8 33 00 00 f8 33 58 19 fa 33 34 6d fa 3300 00 0f e1 1f 00 c0 e3 d3 00 80 e3 00 f0 29 e1…………04 30 8c e5 fc 4d 00 eb 00 01 9f e5 f0 3c 00 eb02 0d 00 eb 41 42 00 eb f4 00 9f e5 00 40 98 e504 02 00 eb 0d 10 a0 e1 04 00 84 e5 40 20 a0 e3OOB:ff ff ff ff ff ff ff ffff ff ff ff ff ff ff ffff ff ff ff ff ff ff ffff ff ff ff ff ff ff ffff ff ff ff ff ff ff ff69 a6 ab 3c 33 cf 66 5aa7 cf f0 33 a6 96 97 3f0c c3 30 30 c3 cc 33 f3nand write - addr off size这个命令和nand read⼀样,只是⽅向是反的,是把ram的值写到 nand flash中,但是这个写只能将1改为0,不能将0写成1. 这个command 会⾃动skipping bad blocks。

UBOOT移植(NANDFLASH的支持)——初步移植(二)

UBOOT移植(NANDFLASH的支持)——初步移植(二)

UBOOT移植(NANDFLASH的支持)——初步移植(二)NAND FLASH初始化入口函数(arch/arm/lib/board.c)这里需要定义CONFIG_CMD_NAND这个宏才行,在配置头文件中已经包含进去了,没问题。

nand_init()函数(drivers/mtd/nand/nand.c)这个函数里面使用两个宏参数进行控制CONFIG_SYS_MAX_NAND_DEVICE和CONFIG_SYS_NAND_SELECT_DEVICE,前者已经在配置头文件中进行了描述,后者由于对应的是有多个NAND设备存在的情况,这里就忽略了。

nand_init_chip()函数(drivers/mtd/nand/nand.c)这个函数需要配置三个宏参数,除了CONFIG_RELOC_FIXUP_WORKS其余都定义了。

没有定义的那个宏给出的描述是“Relocation to SDRAM works on all XXX boards”意思是重置到SDRAM工作在所有XXX板子上。

UBOOT中大部分ARM板子上都没有定义这个宏,SMDK2410也没有定义这个宏,这里也就选择不定义。

这个函数函数还需要三个参数,这三个参数在开头进行了定义。

nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] =CONFIG_SYS_NAND_BASE_LIST;宏CONFIG_SYS_NAND_BASE_LIST采用默认的配置。

#ifndef CONFIG_SYS_NAND_BASE_LIST#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }#endif上述所有参数在配置头文件中都有定义。

uboot中NANDflash的MTD驱动移植

uboot中NANDflash的MTD驱动移植

u-boot中NAND flash的MTD驱动移植u-boot中移植了linux中的MTD驱动源码来支持NAND flash擦除、烧写及读的驱动。

MTD(memory technology device内存技术设备)是用于访问flash设备的Linux的子系统。

MTD的主要目的是为了使新的存储设备的驱动更加简单并有通用接口函数可用。

MTD驱动可支持CFI接口的norflash驱动、NAND flash驱动。

我们知道NAND flash 的访问接口并没有像norflash一样提供了一个标准的CFI访问接口,但是NAND flash生产厂家之间在各品牌、各型号NAND falsh芯片的访问接口方面做了一些约定俗成规定,如命令字、地址序列、命令序列、坏块标记位置、oob区格式等。

值得注意的是:在工艺制程方面分NAND flash有两种类型:MLC和SLC。

MLC和SLC属于两种不同类型的NAND FLASH存储器。

SLC全称是Single-Level Cell,即单层单元闪存,而MLC全称则是Multi-Level Cell,即为多层单元闪存。

它们之间的区别,在于SLC每一个单元,只能存储一位数据,MLC每一个单元可以存储两位数据,MLC的数据密度要比SLC 大一倍。

在页面容量方面分NAND也有两种类型:大页面NAND flash(如:HY27UF082G2B)和小页面NAND flash(如:K9F1G08U0A)。

这两种类型在页面容量,命令序列、地址序列、页内访问、坏块标识方面都有很大的不同,并遵循不同的约定所以在移植驱动时要特别注意。

下面以大页面的NAND flash:现代HY27UF082G2B为例介绍一下NAND flash一些基本情况,再来介绍MTD驱动的基本结构及流程分析,最后介绍u-boot中MTD驱动移植的详细步骤:3.4.1)NAND flash一些基本情况fl2400开发板上的nandflash芯片型号为:现代HY27UF082G2B,下面先介绍一下nandflash,及norflash与nandflash之间的区别:NOR和NAND是现在市场上两种主要的非易失闪存技术。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

U -Boot 从NAND Flash 启动的实现王磊(太原理工大学信息工程学院,山西太原030024)摘要:U -Boot 不能从NAND Flash 启动给应用带来些不便,因此修改U -Boot 使其支持从NAND Flash 启动。

分析了U -Boot 启动流程的两个阶段及实现从NAND Flash 启动的原理和思路,并根据NAND Flash 的物理结构和存储特点,增加U -Boot 对NAND Flash 的操作支持,从而完成把存储在NAND Flash 上的U -Boot 代码复制到SDRAM 中执行,实现从NAND Flash 的启动。

修改过后的U -Boot 可以直接从NAND Flash 启动,给应用带来便利。

关键词:U -Boot ;NAND Flash ;Bootloader ;S3C2440;移植中图分类号:TP316文献标识码:A文章编号:1674-6236(2010)05-0098-03Realization of U -Boot booting through NAND FlashWANG Lei(Department of Information Engineering ,Taiyuan University of Technology ,Taiyuan 030024,China )Abstract:It is not convenient that U -Boot can ’t boot through NAND Flash.In this paper ,the codes of U -Boot is modified to support that.This paper analyzes two steps of U -Boot and the method of supporting that the U -Boot boots from NAND Flash.Based on the memory characteristics and the physical structure of NAND Flash ,this paper adds the codes of NAND Flash in order to carry the codes to SDRAM that stored in the NAND Flash ,thus realizes U -Boot boots from NAND Flash.The modified U -Boot runs through NAND Flash straightly ,it is a great convenience to the application of U -Boot.Key words:U -Boot ;NAND Flash ;Bootloader ;S3C2440;porting电子设计工程Electronic Design Engineering第18卷Vol.18第5期No.52010年5月May.2010收稿日期:2009-10-11稿件编号:200910032作者简介:王磊(1985—),男,山西河津人,硕士研究生。

研究方向:嵌入式系统、DCS 、自动控制。

Bootloader 引导装载程序是系统上电后运行的第一段程序,其作用是完成基本的硬件初始化工作,所以引导装载程序跟硬件有着紧密的联系。

因此必须根据开发板的硬件配置对引导装载程序进行修改才可以使其运行起来。

随着嵌入式系统的复杂化,大容量数据存储的NAND Flash 的应用会越来越广泛,同时U -Boot 是功能最丰富的Bootloader ,但遗憾的是U -Boot 不支持从NAND Flash 启动。

所以如果能实现U -Boot 从NAND Flash 启动的话将会给应用带来很大的方便。

本文讨论修改U -Boot 使其支持从NAND Flash 启动,采用基于S3C2440的开发板。

1U -Boot 简介及流程分析U -Boot ,全称universal boot loader ,是遵循GPL 条款的开放源代码项目。

可以引导多种操作系统,支持多种架构的CPU 。

它支持如下操作系统:Linux 、NetBSD 、VxWorks 等,支持如下架构的CPU :PowerPC 、MIPS 、X86、ARM 、NIOS 、XScale 等,同时支持NFS 挂载,是一个功能丰富的BootLoader 。

它的整个程序框架清晰,易于移植,许多设计人员将自己的移植代码上传到网站(http :///projects/u-boot/)上,更新速度很快。

目前的版本是1.1.6,本论文正是采用此版本进行说明,U -Boot 的目录结构参见U -Boot 源代码。

要进行U -Boot 的修改移植必须了解U -Boot 的程序运行流程,这是必要的一步。

U -Boot 属于两阶段的BootLoader ,其启动流程如图1所示。

第一阶段的文件为cpu/arm920t/start.S 和board/smdk2410/lowlevel_init.S ,用ARM 汇编语言编写,前者是平台相关的,后者是开发板相关的[1]。

第一阶段主要是关于基本硬件的初始化,包括关闭MMU 、CACHE 、设置PLL 时钟比例、关闭看门狗;初始化SDRAM ,为复制第二阶段代码做准备,最后复制第二阶段代码到SDRAM 中,然后跳到图1U -Boot 启动流程-98-SDRAM中运行第二阶段。

第二阶段代码都是用C语言编写的,功能更加复杂,主要是进一步初始化硬件设备、检测内存映射、复制内核镜像和根文件系统到SDRAM以及设置启动参数从而启动内核。

2支持NAND启动的代码修改2.1添加NAND Flash的初始化函数U-Boot中关于NAND Flash的初始化流程如下:在上电后最先运行的汇编程序cpu\arm920t\start.S中调用start_arm-boot函数,而start_armboot该函数则调用了一系列的关于设备的初始化函数。

这一系列的函数中包含一个名为nand_init 的函数,nand_init就是完成NAND Flash的初始化工作。

在1.1.6版本的U-Boot的include\linux\mtd\nand.h中定义了nand_chip结构体,该结构体中定义了关于NAND Flash 操作的所有函数,包括读、写、ECC校验等,而这些函数在U-Boot中都有完整编写,只是有些个别函数需要根据自己的要求重新编写。

而实现NAND Flash初始化的nand_init函数主要任务就是完成这些需要重新编写的函数和用这些函数连同U-Boot中其他默认函数来初始化nand_chip结构体。

NAND_init中的board_nand_init函数在U-Boot中并未实现,显然需要重新编写的函数就在其内添加[2]。

先在cpu\arm920t\s3c24x0中添加nand.c文件,然后在该文件中实现所需要的初始化函数。

一般只需要重新编写nand_chip结构体中相对应的hwcontrol、dev_ready和se-lect_chip函数。

这些函数的构建可参照linux内核2.6版本里的drivers\mtd\nand\s3c2410.c文件来进行编写,如内核文件中的s3c2440_nand_hwcontrol,s3c2440_nand_devready,s3c2410_ nand_select_chip函数,然后将其赋值给nand_chip结构体中对应的函数[3-4]。

static int s3c2440_nand_devready(struct mtd_info*mtd){S3C2440_NAND*const s3c2440nand=S3C2440_Get-Base_NAND();return(s3c2440nand->NFSTAT&S3C2440_NFSTAT_ READY);}void board_nand_init(struct nand_chip*chip){chip->dev_ready=s3c2440_nand_devready;...}接着在/include/configs/SMDK2410.h中的CONFIG_COM-MANDS内添加CFG_CMD_NAND同时在最后添加#define CFG_NAND_BASE0#define CFG_MAX_NAND_DEVICE1#define NAND_MAX_CHIPS1初始化函数工作基本完成。

最后修改Makefile,把nand.c 文件添加进工程。

2.2实现NAND启动由于NAND的自身特点,对NAND Flash的操作不能像对NOR Flash那样方便地直接对地址进行操作,而是通过读写NAND Flash控制器的寄存器来完成。

三星公司的S3C2440自带NAND Flash控制器,寄存器的地址是从nGCS4的地址开始。

S3C2440处理器有NOR和NAND两种启动模式,当选择从NAND模式启动时,S3C2440会把NAND Flash的前4K数据搬运到内部称为Steppingstone的硬件中,同时把Steppingstone映射到地址0X00处,从而启动,启动完成后处理器会把Steppingstone释放掉以作为他用。

U-Boot的一般大小都上100K,远大于4K,所以实现从NAND启动的原理就是让前4K代码完成基本初始化,重要的是把NAND Flash中的U-Boot代码复制到SDRAM中,从而跳到SDRAM中去执行[5]。

分析可知,S3C2440的该特点为U-Boot从NAND Flash启动提供了可能。

本文讨论的实现思路就是依据此原理。

源代码中有/board/smdk2410/u-boot/lds,该文件是U-Boot代码的链接脚本,有如下代码:SECTIONS{.=0x00000000;.=ALIGN(4);.text:{cpu/arm920t/start.o(.text)*(.text)}可以看到Text段也就是程序代码段,被编译链接到0X00地址处,同时start.S编译后的目标文件start.o被放到text段的第一个文件处,所以start.S就是程序上电运行的第一段代码,而/cpu/arm920t/start.S这个汇编文件正是U-Boot 的程序代码入口。

因此代码修改和添加主要在start.S中完成,以此来保证NAND启动代码可以在最终程序编译链接所生成的文件的前4K内。

NAND Flash读写操作比较复杂,汇编实现较为麻烦,没有C语言简单容易,因此用C语言实现对NAND的操作复制工作,最后在start.s中调用编写的C程序即可。

相关文档
最新文档