JZ2440平台移植uboot 2016.11(七)

本节中实现uboot对Nand flash的操作

1. 复制文件

对比了S3C2410和S3C2440的Nand控制寄存器,他们之间的差别还是比较大,uboot源代码中支持2410 nand,我们需要复制文件drivers/mtd/nand/s3c2410_nand.cs3c2440_nand.c

2. 修改Makefile

修改drivers/mtd/nand/Makefile
加入obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
CONFIG_NAND_S3C2410定义在include/configs/smdk2410.h
接下来修改include/configs/smdk2440.h

#ifdef CONFIG_CMD_NAND
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE  1
#define CONFIG_SYS_NAND_BASE        0x4E000000
#endif

修改为

#ifdef CONFIG_CMD_NAND
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE  1
#define CONFIG_SYS_NAND_BASE        0x4E000000
#endif

之后编译uboot,发现可以正常编译出u-boot.bin,但是在最后报错
原因时在uboot编译时,检查有关Kconfig中是否有关新定义的宏是否有对应的配置项。
打开drivers/mtd/nand/Kconfig,看到并没有CONFIG_NAND_S3C2410的配置。
使用grep命令查找uboot源代码,可以看到在scripts/config_whitelist.txt中有这个宏,从文件名可以推断出如果宏定义在此文件中,Kconfig中不定义对应项,也能正常编译通过。因此在此文件中哦你工加入

CONFIG_NAND_S3C2440
CONFIG_SYS_S3C2440_NAND_HWECC

3. 修改drivers/mtd/nand/s3c2440_nand.c

修改寄存器的配置项

#define S3C2440_NFCONT_EN          (1<<0)
#define S3C2440_NFCONT_INITECC     (1<<4)
#define S3C2440_NFCONT_nFCE        (1<<1)
#define S3C2440_NFCONF_TACLS(x)    ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<4)

#define S3C2440_ADDR_NALE 0x0C
#define S3C2440_ADDR_NCLE 0x08

修改s3c24x0_hwcontrol

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

    if (ctrl & NAND_CTRL_CHANGE) {
        if (ctrl & NAND_NCE)
        {
            writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
        }
        else
        {
            writel(readl(&nand->nfcont) | S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
        }
    }

    if (ctrl & NAND_CLE)
    {
        writeb(cmd,&nand->nfcmd);
    }
    else if (ctrl & NAND_ALE)
    {
        writeb(cmd,&nand->nfaddr);
    }
}

这个函数里面已经有了对nand控制器使能引脚的操作,修改下地址和命令之间的区分就可以了

修改board_nand_init

int board_nand_init(struct nand_chip *nand)
{
    u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
    struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();

    debug("board_nand_init()\n");

    writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);

    /* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
    tacls  = CONFIG_S3C24XX_TACLS;
    twrph0 = CONFIG_S3C24XX_TWRPH0;
    twrph1 =  CONFIG_S3C24XX_TWRPH1;
#else
    tacls = 0;
    twrph0 = 1;
    twrph1 = 0;
#endif

    cfg = 0;
    cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
    writel(cfg, &nand_reg->nfconf);

    //enable NAND controller
    cfg = S3C2440_NFCONT_EN | S3C2440_NFCONT_INITECC | S3C2440_NFCONT_nFCE;
    writel(cfg, &nand_reg->nfcont);

    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
    nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

    //nand->select_chip = s3c24x0_select_chip;
    nand->select_chip = NULL;

    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
    nand->read_buf = nand_read_buf;
#endif

    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c24x0_hwcontrol;

    nand->dev_ready = s3c24x0_dev_ready;

#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl = s3c24x0_nand_enable_hwecc;
    nand->ecc.calculate = s3c24x0_nand_calculate_ecc;
    nand->ecc.correct = s3c24x0_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
    nand->ecc.strength = 1;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_S3C2410_NAND_BBT
    nand->bbt_options |= NAND_BBT_USE_FLASH;
#endif

    debug("end of nand_init\n");

    return 0;
}

之后,nand flash就可以正常操作了

4. 关于nand控制器cs引脚控制的说明

在uboot自带的源代码中,s3c24x0_hwcontrol函数的以下代码块实现对其的控制

if (ctrl & NAND_CTRL_CHANGE) {
        if (ctrl & NAND_NCE)
        {
            writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
        }
        else
        {
            writel(readl(&nand->nfcont) | S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
        }
    }

也可以不用这部分代码,删掉后加入自己写的控制函数

void s3c24x0_select_chip(struct mtd_info *mtd, int chip)
{
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
    if(chip == 0)
    {
        writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
    }
    else if(chip == -1)
    {
        writel(readl(&nand->nfcont) | S3C2440_NFCONT_nFCE,
                   &nand->nfcont);
    }
}

board_nand_init中对其注册

nand->select_chip = s3c24x0_select_chip;

这样也可以正常使用

5. nand flash测试

烧写新编译的uboot.bin后,可以用如下方式进行测试

md.b 30000000
nand erase 0 4
nand write 30000000 0 4
nand read 30008000 0 4
md.b 30008000

查看新读出的数据前四个字节是否与之前读出30000000地址的数据相同

你可能感兴趣的:(uboot)