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

TX2440 ARM开发板Uboot移植(二、让u-boot从nandFlash动起来)

发布时间:2020-12-15 17:40:06 所属栏目:百科 来源:网络整理
导读:接上: 让u-boot从norFlash动起来 完成上面工作后,u-boot中还没有对2440上Nand Flash的支持,以及u-boot从Nand Flash上启动,这些得我们一步步去实现了。 1、修改配置文件 include/configs/smdk2440.h : 1.1、新增宏 CONFIG_CMD_NAND (大概在95行) #define

接上:让u-boot从norFlash动起来


完成上面工作后,u-boot中还没有对2440上Nand Flash的支持,以及u-boot从Nand Flash上启动,这些得我们一步步去实现了。

1、修改配置文件 include/configs/smdk2440.h :

1.1、新增宏 CONFIG_CMD_NAND (大概在95行)
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_NAND
#define CONFIG_CMD_ENV

1.2、在文件的最后面增加3个宏:

//NAND flash settings
#define?NAND_CTL_BASE???? 0x4E000000? //NAND Flash的地址
#define CFG_MAX_NAND_DEVICE? 1?????????//NAND Flash设备数目为1
#define NAND_MAX_CHIPS? ??? 1?? ??? ???????? ?//每个NAND设备由1个NADN芯片组成

2、? 修改 include/s3c24x0.h 文件,增加S3C2440_NAND数据结构(168行)

/* NAND FLASH (see S3C2440 manual chapter 6) */
typedef struct {
??? S3C24X0_REG32 NFCONF;
??? S3C24X0_REG32 NFCONT;
??? S3C24X0_REG32 NFCMD;
??? S3C24X0_REG32 NFADDR;
??? S3C24X0_REG32 NFDATA;
??? S3C24X0_REG32 NFMECCD0;
??? S3C24X0_REG32 NFMECCD1;
??? S3C24X0_REG32 NFSECCD;
??? S3C24X0_REG32 NFSTAT;
??? S3C24X0_REG32 NFESTAT0;
??? S3C24X0_REG32 NFESTAT1;
??? S3C24X0_REG32 NFMECC0;
??? S3C24X0_REG32 NFMECC1;
??? S3C24X0_REG32 NFSECC;
??? S3C24X0_REG32 NFSBLK;
??? S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;

3、u-boot默认是从Nor Flash启动的。修改文件 cpu/arm920t/start.S ,使u-boot可以从Nand Flash启动:

对文件改动较大,仔细对比源代码,主要的修改是将栈的初始化放到前面,用于后面调用C函数的需要;
判断u-boot不是从内存启动后,调用CopyCode2Ram函数,实现把启动代码拷贝到内存

/*
? * we do sys-critical inits only at reboot,
? * not when booting from ram!
? */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
?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???????? */
?blne?cpu_init_crit
#endif

stack_setup:??????//将栈的初始化放到前面
?ldr?r0,_TEXT_BASE?????/* upper 128 KiB: relocated uboot?? */
?sub?r0,r0,#CFG_MALLOC_LEN??/* malloc area? ???????????????? */
?sub?r0,#CFG_GBL_DATA_SIZE ?/* bdinfo??????????????*/
#ifdef CONFIG_USE_IRQ
?sub?r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
?sub?sp,#12??/* leave 3 words for abort-stack??? */

relocate:??????/* relocate U-Boot to RAM???? */
?adr?r0,_start??/* r0 <- current position of code?? */
?ldr?r1,r1????????????????? /* don't reloc during debug???????? */
?beq???? clear_bss

?ldr?r2,_armboot_start
?ldr?r3,_bss_start
?sub?r2,r3,r2??/* r2 <- size of armboot??????????? */
?bl CopyCode2Ram???
// 调用board/smdk2440/boot_Init.c里的CopyCode2Ram函数,把启动代码拷贝到内存

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,#4
?cmp?r0,r1
?ble?clbss_l

?ldr?pc,_start_armboot

_start_armboot:?.word start_armboot

4、新建 board/smdk2440/boot_Init.c 文件,实现从NandFlsh读取字节;判断启动方式,并拷贝启动代码到内存。代码如下:

#include <common.h>
#include <s3c2440.h>

#define BUSY??????????? 1

#ifdef?NAND_LARGEPAGE
#define NAND_SECTOR_SIZE 2048
#else
#define NAND_SECTOR_SIZE 512
#endif
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

/* 供外部调用的函数 */
void nand_init_ll(void);
void nand_read_ll(unsigned char *buf,unsigned long start_addr,int size);

/* S3C2440的NAND Flash处理函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);
/* S3C2440的NAND Flash操作函数 */
/* 复位 */

static void nand_reset(void)
{
??? nand_select_chip();
??? write_cmd(0xff);? // 复位命令
??? wait_idle();
??? nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void wait_idle(void)
{
? int i;
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
?volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

?while(!(*p & BUSY))
?for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void nand_select_chip(void)
{
?int i;
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

?s3c2440nand->NFCONT &= ~(1<<1);
?for(i=0; i<10; i++);????
}

/* 取消片选信号 */
static void nand_deselect_chip(void)
{
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
??? s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void write_cmd(int cmd)
{
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
??? volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
??? *p = cmd;
}

/* 发出地址 Nand进行寻址的部分*/
static void write_addr(unsigned int addr)
{
? int i;
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
?volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
#ifndef?NAND_LARGEPAGE????
?*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++);
#else
?int col,page;
?col = addr & NAND_BLOCK_MASK;
?page = addr / NAND_SECTOR_SIZE;
?*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++);
?*p = (page >> 16) & 0x03;?/* Row Address A28~A29 */
?for(i=0; i<10; i++);
#endif
}

/* 读取数据 */
static unsigned char read_data(void)
{
?S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
?volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
?return *p;
}

/* 初始化NAND Flash */
void nand_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();
}

/* 读函数 */
void nand_read_ll(unsigned char *buf,int size)
{
??? int i,j;
??? if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
??????? return ;????/* 地址或长度不对齐 */
??? }
????/* 选中芯片 */
??? nand_select_chip();
??? for(i=start_addr; i < (start_addr + size);) {
??????/* 发出READ0命令 */
????? write_cmd(0);
??????/* Write Address */
????? write_addr(i);
#ifdef NAND_LARGEPAGE
?write_cmd(0x30);
#endif
????? wait_idle();
????? for(j=0; j < NAND_SECTOR_SIZE; j++,i++) {
????????? *buf = read_data();
????????? buf++;
????? }
??? }
????/* 取消片选信号 */
??? nand_deselect_chip();
??? return ;
}

int bBootFrmNORFlash(void)???/* 取OM0、1的值,判断开发板是从NorFlash还是NandFlash启动 */
{
??volatile unsigned int *bwsCON = (volatile unsigned int *)0x48000000;
??unsigned int bwsVal;
??bwsVal = *bwsCON;
??bwsVal &= 0x06;
??if (bwsVal==0){
???return 0;
??}
??else?{
???return 1;
??}
}

int CopyCode2Ram(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];
????? }
??? }
??? else
??? {
????? /* 初始化NAND Flash */
???nand_init_ll();
????? /* 从 NAND Flash启动 */
????? nand_read_ll(buf,start_addr,(size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
??? }
?return 0;
}

注意:上面这段代码中对Nand进行寻址的部分,这跟具体的Nand Flash的寻址方式有关。根据开发板上的Nand Flash(K9F1208U0C)数据手册得知,片内寻址是采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行传送,并进行片内寻址。具体含义和结构图如下(相关概念参考Nand数据手册):

5、在 board/smdk2440/Makefile 中添加 boot_Init.c 的编译选项,使他编译到u-boot中:

COBJS????:= my2440.o flash.o?boot_Init.o

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

.text :
{
????? cpu/arm920t/start.o??? (.text)
??????board/smdk2440/boot_Init.o (.text) ????? board/smdk2440/lowlevel_init.o (.text)???? ????? *(.text) }

(编辑:李大同)

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

    推荐文章
      热点阅读