Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1208159
  • 博文数量: 322
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 3276
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-17 09:21
文章分类

全部博文(322)

文章存档

2010年(155)

2009年(167)

我的朋友

分类: 嵌入式

2009-12-24 17:14:08

在u-boot-1.1.6移植(二)http://blog.chinaunix.net/u2/74310/showart.php?id=1091929中提到:u-boot 运行至第二阶段进入 start_armboot()函数。其中 nand_init()函数是对 nand flash 的最初初始化函数。其调用与 CFG_NAND_LEGACY 宏有关,如果没定义 CFG_NAND_LEGACY 这个宏,就按照start_armboot()调用 drivers/nand/nand.c 中的 nand_init 函数(该函数在 1.1.6 已经被实现), 但还有个 board_nand_init()函数没实现,需自己添加;如果定义了CFG_NAND_LEGACY,就不使用默认的 nand_init,而调用自己写的 nand_init 函数了。u-boot-1.1.6中对NAND flash的支持有新旧两套代码,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录下,文档doc/README.nand对这两套代码有所说明:使用旧代码需要定义更多的宏,u-boot-1.1.6移植(二)中可以看到,比较复杂,而新代码移植自Linux 2.6.12,它更加智能,可以自动识别更多型号的NAND flash。本文使用新代码并移植在优龙FS2410成功。
    NAND flash 的支持以及下篇《u-boot烧写yaffs文件系统映象》参考《嵌入式Linux应用开发完全手册》,实验时得到该书作者南方兄的热情帮助,在此感谢!
 
移植过程:
 
一、代码搬运
 
    u-boot启动时,需要 copy u-boot to ram 的过程,通过自己定义的 nand_read.c实现,该步骤与u-boot-1.1.6移植(一)同,参考http://blog.chinaunix.net/u2/74310/showart.php?id=1091899,需要注意的是增加对nand flash支持后编译出来的bin文件将大于128KB,所以修改start.S即可:
@ copy UBOOT to RAM
    ldr    r0, _TEXT_BASE
    mov     r1, #0x0
    mov    r2, #0x20000 //改为mov r2,#0x40000,这是FS2410分配给u-boot的存储空间
    bl    nand_read_ll

二、修改配置文件 include/configs/fs2410.h 使支持NAND

   /***********************************************************
 * Command definition
 ***********************************************************/
#define CONFIG_COMMANDS \
            (CONFIG_CMD_DFL     | \
            CFG_CMD_CACHE     | \
            CFG_CMD_ENV         | \
            CFG_CMD_NET         | \
            CFG_CMD_PING     | \
            CFG_CMD_NAND     | \
            /*CFG_CMD_EEPROM |*/ \
            /*CFG_CMD_I2C     |*/ \
            /*CFG_CMD_USB     |*/ \
            CFG_CMD_REGINFO  | \
            CFG_CMD_DATE     | \
            CFG_CMD_ELF)

#define CFG_NAND_BASE        0x4E000000
#define CFG_MAX_NAND_DEVICE    1    /* Max number of NAND devices        */
#define NAND_MAX_CHIPS        1

/*保存环境变量用到的宏,否则不能 saveenv */
#define CFG_ENV_IS_IN_NAND    1
#define CFG_NAND_BASE        0x4E000000
#define CMD_SAVEENV
#define CFG_ENV_SIZE            0x10000 /* Total Size of Environment Sector */
#define CFG_ENV_OFFSET      0x30000 /*环境变量在NAND FLASH的0x30000处*/

/*修改默认配置参数以方便使用*/
#define CONFIG_BOOTDELAY    3
#define CONFIG_BOOTARGS        "noinitrd root=/dev/mtdblock2 init=/linuxrc devfs=mount console=ttySAC0,115200"
#define CONFIG_ETHADDR    08:00:3e:26:0a:5b
#define CONFIG_NETMASK          255.255.255.0
#define CONFIG_IPADDR        192.168.1.100
#define CONFIG_SERVERIP        192.168.1.2
/*#define CONFIG_BOOTFILE    "elinos-lart" */
#define CONFIG_BOOTCOMMAND    "nand read 0x30007fc0 0x40000 0x1c0000; bootm 0x30007fc0"

三、建立cpu/arm920t/s3c24x0/nand_flash.c,实现board_nand_init函数
    《嵌入式Linux应用开发完全手册》中介召的nand_flash.c包含对S3C2440的支持,在这里一并列出,供日后参考。

(1)针对S3C2410、S3C2440 NAND Flash控制器的不同来定义一些数据结构和函数,在include/s3c24x0.h 文件中增加S3C2440_NAND数据结构。

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

(2)在 include/s3c2410.h 文件中仿照 S3C2410_GetBase_NAND函数定义S3C2440_GetBase_NAND函数。

/* for s3c2440, */
static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
{
    return (S3C2440_NAND * const)S3C2410_NAND_BASE;
}

(3) cpu/arm920t/s3c24x0/nand_flash.c

/*
 * Nand flash interface of s3c2410/s3c2440, by
 * Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13
 */

#include

#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include
#include

DECLARE_GLOBAL_DATA_PTR;

#define S3C2410_NFSTAT_READY    (1<<0)
#define S3C2410_NFCONF_nFCE     (1<<11)

#define S3C2440_NFSTAT_READY    (1<<0)
#define S3C2440_NFCONT_nFCE     (1<<1)


/* select chip, for s3c2410 */
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
    S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

    if (chip == -1) {
        s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
    } else {
        s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
    }
}

/* command and control functions, for s3c2410
 *
 * Note, these all use tglx's method of changing the IO_ADDR_W field
 * to make the code simpler, and use the nand layer's code to issue the
 * command and address sequences via the proper IO ports.
 *
*/
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
    S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
    struct nand_chip *chip = mtd->priv;

    switch (cmd) {
    case NAND_CTL_SETNCE:
    case NAND_CTL_CLRNCE:
        printf("%s: called for NCE\n", __FUNCTION__);
        break;

    case NAND_CTL_SETCLE:
        chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
        break;

    case NAND_CTL_SETALE:
        chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
        break;

        /* NAND_CTL_CLRCLE: */
        /* NAND_CTL_CLRALE: */
    default:
        chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
        break;
    }
}

/* s3c2410_nand_devready()
 *
 * returns 0 if the nand is busy, 1 if it is ready
 */
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
    S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

    return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
}


/* select chip, for s3c2440 */
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

    if (chip == -1) {
        s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
    } else {
        s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
    }
}

/* command and control functions */
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
    struct nand_chip *chip = mtd->priv;

    switch (cmd) {
    case NAND_CTL_SETNCE:
    case NAND_CTL_CLRNCE:
        printf("%s: called for NCE\n", __FUNCTION__);
        break;

    case NAND_CTL_SETCLE:
        chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
        break;

    case NAND_CTL_SETALE:
        chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
        break;

        /* NAND_CTL_CLRCLE: */
        /* NAND_CTL_CLRALE: */
    default:
        chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
        break;
    }
}

/* s3c2440_nand_devready()
 *
 * returns 0 if the nand is busy, 1 if it is ready
 */
static int s3c2440_nand_devready(struct mtd_info *mtd)
{
    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

    return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
}

/*
 * Nand flash hardware initialization:
 * Set the timing, enable NAND flash controller
 */
static void s3c24x0_nand_inithw(void)
{
    S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

#define TACLS   0
#define TWRPH0  4
#define TWRPH1  2

    if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
    {
        /* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
    }
    else
    {
        /* Set flash memory timing */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* Initialize ECC, enable chip select, NAND flash controller enable */
        s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
    }
}

/*
 * Called by drivers/nand/nand.c, initialize the interface of nand flash
 */
void board_nand_init(struct nand_chip *chip)
{
    S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
    S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

    s3c24x0_nand_inithw();

    if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410) {
        chip->IO_ADDR_R    = (void *)&s3c2410nand->NFDATA;
        chip->IO_ADDR_W    = (void *)&s3c2410nand->NFDATA;
        chip->hwcontrol    = s3c2410_nand_hwcontrol;
        chip->dev_ready    = s3c2410_nand_devready;
        chip->select_chip  = s3c2410_nand_select_chip;
        chip->options      = 0;
    } else {
        chip->IO_ADDR_R    = (void *)&s3c2440nand->NFDATA;
        chip->IO_ADDR_W    = (void *)&s3c2440nand->NFDATA;
        chip->hwcontrol    = s3c2440_nand_hwcontrol;
        chip->dev_ready    = s3c2440_nand_devready;
        chip->select_chip  = s3c2440_nand_select_chip;
        chip->options      = 0;
    }

    chip->eccmode       = NAND_ECC_SOFT;
}

#endif

四、将nand_flash.c编入 u-boot,修改cpu/arm920t/s3c24x0/Makefile文件

COBJS    = i2c.o interrupts.o serial.o speed.o \
      usb_ohci.o nand_flash.o   
 
好了,make一下,看看结果,很不幸运,/env_nand.c:206 undefined reference to 'nand_info'等等问题,如图1所示,原来nand flash 真正的擦除和读写函数使用的是 drivers/nand_legacy/ 目录下面的读写、擦除函数
int nand_legacy_erase(struct nand_chip* nand, size_t ofs,size_t len, int clean);
int nand_legacy_rw(struct nand_chip* nand, int cmd,size_t start, size_t len,size_t * retlen, u_char * buf);

 

至此,编译生成 u-boot.bin 并烧入NAND Flash,启动,便可以引导内核了。
 
 
 
 

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