六、移植u-boot-2016.03到Jz2440之修改代码支持NAND Flash

6. 移植u-boot-2016.03修改代码支持NAND Flash

从前面串口的打印信息可知,uboot并没有识别出NAND Flash空间的大小,显示:NAND: 0 MiB,如下图所示:
在这里插入图片描述

6.1 分析u-boot-2016.03源码之NAND Flash

我们在uboot的顶层目录输入命令:grep -nR "NAND:",在common/board_r.c中的432行有如下代码:

#ifdef CONFIG_CMD_NAND
/* go init the NAND */
static int initr_nand(void)
{
    
    
    puts("NAND:  ");
    nand_init();
    return 0;
}
#endif

其中,CONFIG_CMD_NANDjz2440.h被定义,initr_nand函数在uboot进行第二阶段初始化时被board_init_r函数调用。nand_init函数被board_init_r函数调用,nand_init函数的代码如下:(该函数在drivers/mtd/nand/nand.c)

void nand_init(void)
{
    
    
#ifdef CONFIG_SYS_NAND_SELF_INIT  /*未定义*/
	board_nand_init();
#else
	int i;

	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
		nand_init_chip(i);
#endif

	printf("%lu MiB\n", total_nand_size / 1024);

#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
	/*
	 * Select the chip in the board/cpu specific driver
	 */
	board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}

关于上面代码#ifdef CONFIG_SYS_NAND_SELF_INIT中的CONFIG_SYS_NAND_SELF_INIT,在nand.h中的代码如下图所示:(source insight截图),从图可知CONFIG_SPL_BUILD是黑色的,说明没有定义;因此,上面的代码不会执行board_nand_init()函数。
在这里插入图片描述
跳过board_nand_init()函数,执行nand_init_chip()函数:

static void nand_init_chip(int i)
{
    
    
	struct mtd_info *mtd = &nand_info[i];
	struct nand_chip *nand = &nand_chip[i];
	ulong base_addr = base_address[i];
	int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;

	if (maxchips < 1)
		maxchips = 1;

	mtd->priv = nand;
	nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;

	if (board_nand_init(nand))
		return;

	if (nand_scan(mtd, maxchips))
		return;

	nand_register(i);
}

接下来看board_nand_init函数:(在drivers/mtd/nand/s3c2410_nand.c)

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 = 4;
	twrph0 = 8;
	twrph1 = 8;
#endif

	cfg = S3C2410_NFCONF_EN;
	cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
	cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
	cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
	writel(cfg, &nand_reg->nfconf);

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

	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;
}

通过分析上面的代码,发现设置时序的时候,与2440手册对比发现,发现时序设置不对,它是适用于2410的,并不适用于2440,设置时序的代码如下:

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

接下来是s3c24x0_hwcontrol函数,它的代码如下:

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

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

	if (ctrl & NAND_CTRL_CHANGE) {
    
    
		ulong IO_ADDR_W = (ulong)nand;

		if (!(ctrl & NAND_CLE))
			IO_ADDR_W |= S3C2410_ADDR_NCLE;
		if (!(ctrl & NAND_ALE))
			IO_ADDR_W |= S3C2410_ADDR_NALE;

		chip->IO_ADDR_W = (void *)IO_ADDR_W;

		if (ctrl & NAND_NCE) /*使能片选*/
			writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,
			       &nand->nfconf);
		else /*取消片选*/
			writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
			       &nand->nfconf);
	}

	if (cmd != NAND_CMD_NONE)
		writeb(cmd, chip->IO_ADDR_W);
}

上的代码是2410的配置,我们的Jz2440开发板是2440的,查看2440手册查看相关寄存器发现,对于2440的NAND 片选使能与取消是通过配置NFCONT寄存的**bit[1]**实现的,如下图所示:
在这里插入图片描述

6.2 修改代码NAND Flash

(1) 把drivers/mtd/nand/s3c2410_nand.c复制为s3c2440_nand.c
(2) 修改 drivers/mtd/nand/目录下的Makefile,在Makefile里搜索CONFIG_NAND_S3C2410,有如下代码:

obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o

在这行代码后面添加下面的代码,把s3c2440_nand.c编译进uboot;

obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

(3) 在include/configs/jz2440.h中添加支持s3c2440_nand,在jz2440.h中搜索CONFIG_NAND_S3C2410,有如下代码:
在这里插入图片描述
修改为:
在这里插入图片描述
(4) 把board_nand_init函数的设置NAND 时序部分的代码:

	cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
	cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
	cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
	writel(cfg, &nand_reg->nfconf);

改为:

    /* 初始化时序 */
    cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);
    writel(cfg, &nand_reg->nfconf);

(5) 修改s3c24x0_hwcontrol函数代码如下:

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

    if (ctrl & NAND_CLE)
    {
    
    
        /* 发命令 */   
        writeb(cmd, &nand->nfcmd);
    }

    if (ctrl & NAND_ALE)
    {
    
    
        /* 发地址 */
        writeb(cmd, &nand->nfaddr);
    }

}

(6) 同时还需要在board_nand_init函数里加上nand->select_chip = s3c2440_nand_select;所以,将

nand->select_chip = NULL;

修改为:

nand->select_chip = s3c2440_nand_select;

(7) 添加s3c2440_nand_select函数,代码如下:

static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
    
    
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

    switch (chipnr) {
    
    
    case -1:    /* 取消选中 */
        nand->nfcont |= (1<<1);
        break;

    case 0:     /* 选中 */
        nand->nfcont &= ~(1<<1);
        break;

    default:
        BUG();
    }
}

6.3 测试

(1) 把上面修改好的代码重新编译,然后把u-boot.bin 烧写到开发板的NOR Flash,设置为NOR启动,串口打印信息如下:
在这里插入图片描述
从上面打印的信息可知,uboot成功识别出NAND Flash空间的大小。
(2) 下面从NAND Flash启动看看能否识别,首先我们从NOR启动的uboot直接把uboot拷贝到NAND,输入以下命令:

nand erase 0 80000    //擦除NAND flash 的512kB空间
nand write 0 0 80000  //把NOR Flash的前512KB拷贝到 NAND Flash

然后测试烧写到NAND Flash中的uboot是否正常,输入以下命令:

nand read 30000000 0 80000  //把NAND Flash的前512kB读到SDRAM
cmp.b 0 30000000 80000     //比较拷贝的代码是否全部一样

在这里插入图片描述
从上图的最后比较结果可知,代码拷贝完全正确。

(3) 然后,设置为NAND Flash启动,并重启开发板,打印结果如下图,从图中可知,成功识别出NAND: 256 MiB
在这里插入图片描述
(4) 从上面的测试现象可知,此时的uboot成功支持NAND Flash。

猜你喜欢

转载自blog.csdn.net/qq_35031421/article/details/104461184