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

接上:让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, r0, #CFG_GBL_DATA_SIZE  /* bdinfo              */
#ifdef CONFIG_USE_IRQ
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */

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     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, 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, unsigned long start_addr, 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)
}

你可能感兴趣的:(移植,u-boot,fl2440)