Chinaunix首页 | 论坛 | 博客
  • 博客访问: 144619
  • 博文数量: 51
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 625
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:40
文章分类
文章存档

2011年(1)

2009年(50)

我的朋友

分类: LINUX

2009-06-15 14:42:23

u-boot移植QT2410E开发板

能够支持多种体系结构的处理器,支持的开发板也越来越多。以S3C2410处理器的开发板为例,我们可以基于SMDK2410移植。

开始移植之前,需要先分析一下U-Boot已经支持的开发板,比较出硬件配置最接近的开发板。选择的原则是,首先处理器相同,其次处理器体系结构相同,然后是以太网接口等外围接口。推荐使用官方FTP下载UBOOT源码。http://www.icdev.com.cn/batch.viewlink.php?itemid=1694

移植U-Boot的基本步骤如下:

1创建开发板目录

(1) 在board目录下创建自己的工作目录,将smdk2410目录下的内容全部拷贝到qt2410e目录下

(2) cd u-boot-1.2.0/board

(3) mkdir qt2410e

(4) cd qt2410e

(5) cp  ../smdk2410/* .

(6) mv smdk2410.c qt2410e.c

(7) vi Makefile并把COBJS更改为:COBJS := qt2410e.o flash.o nand_read.o

(8) cd ../..

(9) cp include/configs/smdk2410.h include/configs/qt2410e.h

(10) vi Makefile顶层Makefile1924行填加如下两行:

qt2410e_config    :    unconfig
        @$(MKCONFIG) $(@:_config=) arm arm920t qt2410e null s3c24x0

2添加nand_read_ll读写函数

start.S文件中需要使用nand_read_ll读写函数,用来将uboot拷贝到内存里去。在/board/qt2410e目录下需要添加nand_read.c文件,主要实现了nand_read_ll读写函数。

(1) cd board/qt2410e

(2) vi nand_read.c创建此文件

(3) 阅读并分析nand_read_ll函数,将其添加到nand_read.c中,代码如下:

(1) #include 

(2) 

(3) #define __REGb(x)    (*(volatile unsigned char *)(x))

(4) #define __REGi(x)    (*(volatile unsigned int *)(x))

(5) #define NF_BASE        0x4e000000

(6) #define NFCONF        __REGi(NF_BASE + 0x0)

(7) #define NFCMD         __REGb(NF_BASE + 0x4)

(8) #define NFADDR        __REGb(NF_BASE + 0x8)

(9) #define NFDATA        __REGb(NF_BASE + 0xc)

(10) #define NFSTAT        __REGb(NF_BASE + 0x10)

(11) 

(12) #define BUSY 1

(13) inline void wait_idle(void) {

(14)     int i;

(15) 

(16)     while(!(NFSTAT & BUSY))

(17)       for(i=0; i<10; i++);    

(18) }

(19) 

(20) #define NAND_SECTOR_SIZE    512

(21) #define NAND_BLOCK_MASK        (NAND_SECTOR_SIZE - 1)

(22) 

(23) 

(24) int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

(25) {

(26)     int i, j;

(27) 

(28)     if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

(29)         return -1;   

(30) }

(31) 

(32)   

(33)     NFCONF &= ~0x800;

(34)     for(i=0; i<10; i++);

(35) 

(36)     for(i=start_addr; i < (start_addr + size);) {

(37)      

(38)       NFCMD = 0; 

(39) 

(40)       

(41)       NFADDR = i & 0xff; 

(42)       NFADDR = (i >> 9) & 0xff;   

(43)       NFADDR = (i >> 17) & 0xff;

(44)       NFADDR = (i >> 25) & 0xff;

(45) 

(46)       wait_idle();

(47) 

(48)       for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

(49)     *buf = (NFDATA & 0xff);

(50)     buf++;

(51)       }

(52)     }

(53)     NFCONF |= 0x800;   

(54)     return 0;

(55) }

修改start.S

(1) vi ../../cpu/arm920t/start.S

(2) 在vi编辑器的命令模式下输入如下命令找到选择FLASH启动部分代码,命令如下:

(3) /RELOCATE

(4) 这时将看到如下代码为NOR的重定向代码:

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

(5) 可以将上述代码注释掉或删除,或者直接不予以理会,我们这里将光标移至#ifndef CONFIG_SKIP_RELOCATE_UBOOT并执行18dd命令直接将其删除。

(6) 删除部分将替换为NAND FLASH的初始化代码,并由此代码最终调用nand_read.c的函数。代码如下:

#ifdef CONFIG_S3C2410_NAND_BOOT   

@ reset NAND
  mov r1, #NAND_CTL_BASE
  ldr   r2, =0xf830           @ initial value
  str   r2, [r1, #oNFCONF]
  ldr   r2, [r1, #oNFCONF]
  bic  r2, r2, #0x800              @ enable chip
  str   r2, [r1, #oNFCONF]
  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, #0x1
  beq  nand2

  ldr   r2, [r1, #oNFCONF]
  orr  r2, r2, #0x800              @ disable chip
  str   r2, [r1, #oNFCONF]

@ 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
  mov     r1, #0x0
  mov r2, #0x20000
  bl    nand_read_ll 这个函数在nand_read.c中实现
  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,这句话的意思在start.S中已注释。
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 @ CONFIG_S3C2410_NAND_BOOT 

注:实现比较简单,同学要仔细推敲NAND工作原理,如看不懂,老师会在同学完成实验后给予讲解。其中@为注释部分,可不必写入。

(7) 用命令行模式找到_start_armboot:    .word start_armboot后加入:
   .align     2(前面用TAB键空出)
DW_STACK_START:  .word  STACK_BASE+STACK_SIZE-4

添加头文件信息

include/configs/qt2410e.h头文件中添加nandflash的初始化信息:

(1) 找到#define CFG_ENV_IS_IN_FLASH 1并将其用//注释掉。

//#define CFG_ENV_IS_IN_FLASH 1

(2) 后面添加如下宏定义:

#define CFG_ENV_IS_IN_NAND 1 

#define CFG_ENV_OFFSET 0x020000 

#define CFG_NAND_BASE 0x4E000000 

#define CMD_SAVEENV 

#define CFG_NAND_LEGACY 

#define CFG_MONITOR_BASE PHYS_SDRAM_1 

#if (CONFIG_COMMANDS & CFG_CMD_NAND) 

#define CFG_NAND_BASE 0x4E000000 

/* NandFlash控制器在SFR区起始寄存器地址 */ 

#define CFG_MAX_NAND_DEVICE 1 

/* 支持的最在Nand Flash数据 */ 

#define SECTORSIZE 512 

/* 1页的大小 */ 

#define NAND_SECTOR_SIZE SECTORSIZE 

#define NAND_BLOCK_MASK 511 

/* 页掩码 */ 

#define ADDR_COLUMN 1 

/* 一个字节的Column地址 */ 

#define ADDR_PAGE 3 

/* 3字节的页块地址!!!!!*/ 

#define ADDR_COLUMN_PAGE 4 

/* 总共4字节的页块地址!!!!! */ 

#define NAND_ChipID_UNKNOWN 0x00 

/* 未知芯片的ID号 */ 

#define NAND_MAX_FLOORS 1 

#define NAND_MAX_CHIPS 1 

/* Nand Flash命令层底层接口函数 */ 

#define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;} 

#define WRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;} 

#define WRITE_NAND(d, adr) {rNFDATA = d;} 

#define READ_NAND(adr) (rNFDATA) 

#define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));} 

#define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);} 

#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);} 

/* the following functions are NOP's because S3C24X0 handles this in hardware 一定要加上 */ 

#define NAND_CTL_CLRALE(nandptr) 

#define NAND_CTL_SETALE(nandptr) 

#define NAND_CTL_CLRCLE(nandptr) 

#define NAND_CTL_SETCLE(nandptr) 

/* 允许Nand Flash写校验 */ 

#define CONFIG_MTD_NAND_VERIFY_WRITE 1 

/* 

* Nandflash Boot 

*/ 

#define CONFIG_S3C2410_NAND_BOOT 1 

#define STACK_BASE 0x33f00000 

#define STACK_SIZE 0x8000 

#define UBOOT_RAM_BASE 0x33f80000 

/* NAND Flash Controller */ 

#define NAND_CTL_BASE 0x4E000000 

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

/* Offset */ 

#define oNFCONF 0x00 

#define oNFCMD 0x04 

#define oNFADDR 0x08 

#define oNFDATA 0x0c 

#define oNFSTAT 0x10 

#define oNFECC 0x14 

#define rNFCONF (*(volatile unsigned int *)0x4e000000) 

#define rNFCMD (*(volatile unsigned char *)0x4e000004) 

#define rNFADDR (*(volatile unsigned char *)0x4e000008) 

#define rNFDATA (*(volatile unsigned char *)0x4e00000c) 

#define rNFSTAT (*(volatile unsigned int *)0x4e000010) 

#define rNFECC (*(volatile unsigned int *)0x4e000014) 

#define rNFECC0 (*(volatile unsigned char *)0x4e000014) 

#define rNFECC1 (*(volatile unsigned char *)0x4e000015) 

#define rNFECC2 (*(volatile unsigned char *)0x4e000016) 

#endif /* CONFIG_COMMANDS & CFG_CMD_NAND*/ 

(3) 85行后添加CFG_CMD_ENV | \CFG_CMD_NAND | \

修改qt2410e.c文件

u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用 drivers/nnd/nand.c中的nand_init();否则调用board/smdk2410/smdk2410.c中的nand_init()函数。这里我选择第二种方式。

/board/qt2410e/qt2410e.c文件的末尾添加对Nand Flash 的初始化函数:

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
typedef enum {
NFCE_LOW,
NFCE_HIGH
} NFCE_STATE;

static inline void NF_Conf(u16 conf)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF = conf;
}

static inline void NF_Cmd(u8 cmd)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCMD = cmd;
}

static inline void NF_CmdW(u8 cmd)
{
NF_Cmd(cmd);
udelay(1);
}

static inline void NF_Addr(u8 addr)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFADDR = addr;
}

static inline void NF_SetCE(NFCE_STATE s)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

switch (s) {
case NFCE_LOW:
nand->NFCONF &= ~(1<<11);
break;

case NFCE_HIGH:
nand->NFCONF |= (1<<11);
break;
}
}

static inline void NF_WaitRB(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

while (!(nand->NFSTAT & (1<<0)));
}

static inline void NF_Write(u8 data)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFDATA = data;
}

static inline u8 NF_Read(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFDATA);
}

static inline void NF_Init_ECC(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

nand->NFCONF |= (1<<12);
}

static inline u32 NF_Read_ECC(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

return(nand->NFECC);
}

#endif

/*

* NAND flash initialization.
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe(ulong physadr);


static inline void NF_Reset(void)
{
int i;

NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF); /* reset command */
for(i = 0; i < 10; i++); /* tWB = 100ns. */
NF_WaitRB(); /* wait 200~500us; */
NF_SetCE(NFCE_HIGH);
}


static inline void NF_Init(void)
{
#if 0 /* a little bit too optimistic */
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#else
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
#endif

NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
/*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */
/* 1 1 1 1, 1 xxx, r xxx, r xxx */
/* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */

NF_Reset();
}

void
nand_init(void)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

NF_Init();
#ifdef DEBUG
printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
#endif
printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
}
#endif

修改common/env_nand.c文件

(1) 59int nand_legacy_rw (struct nand_chip* nand, int cmd,
        size_t start, size_t len,
        size_t * retlen, u_char * buf);

后添加:

extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_t len, int clean);

并将下面的extern nand_info_t nand_info[];改为

extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];

(2) 搜索saveenv找到(190行左右第二个saveenv函数):

#else /* ! CFG_ENV_OFFSET_REDUND */
int saveenv(void)

将saveenv函数中puts ("Erasing Nand...");if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))注释并添加

//if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

if (nand_legacy_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))

将saveenv函数中total = CFG_ENV_SIZE; 后的//ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);注释并添加:

ret = nand_legacy_rw(nand_dev_desc + 0,0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE,&total, (u_char*)env_ptr);

(3) 搜索env_relocate_spec找到第二个env_relocate_spec函数(270行左右)

找到函数中total = CFG_ENV_SIZE;
    将后面的ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);注释并添加:
    ret = nand_legacy_rw(nand_dev_desc + 0, 0x01 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);

编译uboot

(1) make distclean

(2) make qt2410e_config

(3) make all ARCH=arm

将生成u-boot.bin镜像,可将其下载到板子运行。

阅读(1156) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~