加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

u-boot 的NAND启动方式

发布时间:2020-12-15 06:56:04 所属栏目:百科 来源:网络整理
导读:? ? u-boot-2010-06在mini2440上的移植 注意,这些代码有个问题就是要把!define (CONFIG_S3C2440)变成!defined (CONFIG_S3C2440) 4.1 支持u-boot从Nand flash启动 目前u-boot中还没有对2440上Nand Flash的支持,也就是说要想u-boot从Nand Flash上启动得自己
? ?

u-boot-2010-06在mini2440上的移植

注意,这些代码有个问题就是要把!define (CONFIG_S3C2440)变成!defined (CONFIG_S3C2440)

4.1 支持u-boot从Nand flash启动

目前u-boot中还没有对2440上Nand Flash的支持,也就是说要想u-boot从Nand Flash上启动得自己去实现了。

首先,在include/configs/mini2440.h头文件中定义Nand要用到的宏和寄存器,如下:

#gedit include/configs/my2440.h? //在文件末尾加入以下Nand Flash相关定义

/*

?* Nand flash register and envionment variables

?*/

#define CONFIG_S3C2440_NAND_BOOT? 1

#define NAND_CTL_BASE? 0x4E000000 ?//Nand Flash配置寄存器基地址,查2440手册可得知

#define bINT_CTL(Nb)?? __REG(INT_CTL_BASE+(Nb))

#define UBOOT_RAM_BASE? 0x33f80000

#define STACK_BASE? 0x33F00000???? //定义堆栈的地址

#define STACK_SIZE? 0x8000???????? //堆栈的长度大小

?

其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动,在上一节中提过,u-boot默认是从Nor Flash启动的。修改部分如下:

#gedit cpu/arm920t/start.S

/*注意:在上一篇Nor Flash启动中,我们为了把u-boot用supervivi下载到内存中运行而屏蔽掉这段有关CPU初始化的代码。而现在我们要把u-boot下载到Nand Flash中,从Nand Flash启动,所以现在要恢复这段代码。*/

?

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

??? bl cpu_init_crit

#endif

?

#if 0 //屏蔽掉u-boot中的从Nor Flash启动部分

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate:????????????? ?/* relocate U-Boot to RAM */

??? adr r0,_start???? ?/* r0 <- current position of code */

??? ldr r1,_TEXT_BASE? /* test if we run from flash or RAM */

??? cmp r0,r1??????? ??/* don't reloc during debug */

??? beq stack_setup

?

??? ldr r2,_armboot_start

??? ldr r3,_bss_start

??? sub r2,r3,r2???? ?/* r2 <- size of armboot */

??? add r2,r0,r2???? ?/* r2 <- source end address */

?

copy_loop:

??? ldmia r0!,{r3-r10} ??/* copy from source address [r0] */

??? stmia r1!,{r3-r10}? ?/* copy to?? target address [r1] */

??? cmp r0,r2??????? ??/* until source end addreee [r2] */

??? ble copy_loop

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

#endif

?

?

//下面添加2440中u-boot从Nand Flash启动

?

#ifdef CONFIG_S3C2440_NAND_BOOT

?

#define? oNFCONF? 0x00

#define? oNFCONT? 0x04

#define? oNFCMD?? 0x08

#define? oNFSTAT?? 0x20

#define? LENGTH_UBOOT? 0x60000

?

??? mov r1,#NAND_CTL_BASE?? //复位Nand Flash

??? ldr r2,=( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

??? str r2,[r1,#oNFCONF]?? //设置配置寄存器的初始值,参考s3c2440手册

??? ldr r2,#oNFCONF]

?

??? ldr r2,=( (1<<4)|(0<<1)|(1<<0) )

??? str r2,#oNFCONT]? ?//设置控制寄存器

??? ldr r2,#oNFCONT]

?

??? ldr r2,=(0x6)????????? ?//RnB Clear

??? str r2,#oNFSTAT]

ldr r2,#oNFSTAT]

?

??? mov r2,#0xff??????????? //复位command

??? strb r2,#oNFCMD]

??? mov r3,#0?????????? ????//等待

nand1:

??? add r3,#0x1

??? cmp r3,#0xa

??? blt nand1

?

nand2:

??? ldr r2,#oNFSTAT]? ?//等待就绪

??? tst r2,#0x4

??? beq nand2

?

??? ldr r2,#oNFCONT]

??? orr r2,r2,#0x2???????? //取消片选

??? str r2,#oNFCONT]

?

??? //get read to call C functions (for nand_read())

??? ldr sp,DW_STACK_START?? //为C代码准备堆栈,DW_STACK_START定义在下面

??? mov 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的长度大小(128k)

??? bl nand_read_ll? ?//此处调用C代码中读Nand的函数,现在还没有要自己编写实现

??? tst r0,#0x0

??? beq ok_nand_read

?

bad_nand_read:

??? loop2: b loop2??? //infinite loop

?

ok_nand_read: //检查搬移后的数据,如果前4k完全相同,表示搬移成功

??? 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,#4

??? beq stack_setup

??? bne go_next

?

notmatch:

??? loop3: b loop3?????????? //infinite loop

#endif ?????????????????????//CONFIG_S3C2440_NAND_BOOT

?

_start_armboot: .word start_armboot //在这一句的下面加上DW_STACK_START的定义

?

.align 2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

再次,在board/samsung/mini2440/目录下新建一个nand_read.c文件,在该文件中来实现上面汇编中要调用的nand_read_ll函数,代码如下:

#gedit board/samsung/mini2440/nand_read.c? //新建一个nand_read.c文件,记得保存

#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 (CONFIG_S3C2440)

#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;

};

?

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)&& !define (CONFIG_S3C2440)

????????????? 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 */

?????? ??? 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 == 0xecda || ?????????/* Samsung K9F2G08U0B */

????????????? 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/samsung/mini2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下:

COBJS??? := mini2440.o flash.o nand_read.o

还有一个重要的地方要修改,在cpu/arm920t/u-boot.lds中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的。如下:

.text :

{

??? cpu/arm920t/start.o??? (.text)

? ??board/samsung/mini2440/lowlevel_init.o (.text)

??? board/samsung/mini440/nand_read.o (.text)

??? *(.text)

}

最后编译u-boot,生成u-boot.bin文件。然后先将mini2440开发板调到Nor启动档,利用supervivi的a命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读