u-boot-2016.11移植nandfalsh(基于s5pv210)

一、移植nandflash

nand初始化的函数是在board_init_r中被调用

vim common/board_r.c

#ifdef CONFIG_CMD_NAND
        initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
        initr_onenand,          /* modied by Sourcelink */
#endif

u-boot一开始定义了CONFIG_CMD_ONENAND在smdkv210.h中

vim include/configs/smdkv210.h

#define CONFIG_CMD_NAND         /* modied by Sourcelink */
#define CONFIG_CMD_REGINFO
#undef  CONFIG_CMD_ONENAND      /* modied by Sourcelink */

进入init_nand函数中发现调用了nand_init函数,通过追踪发现CONFIG_SYS_NAND_DEVICE没有定义

vim drivers/mtd/nand/nand.c

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


在smdkv210.h中添加该宏CONFIG_SYS_NAND_DEVICE

/*
 * NAND Contoller driver
 */
#ifdef CONFIG_CMD_NAND                  /* add by Sourcelink */
#define CONFIG_SYS_MAX_NAND_DEVICE      1
#endif

编译发现没有定义宏CONFIG_SYS_NAND_BASE

#ifdef CONFIG_CMD_NAND                  /* add by Sourcelink */
#define CONFIG_SYS_MAX_NAND_DEVICE      1
#define CONFIG_SYS_NAND_BASE            0xB0E00000
#endif

再次编译,还是出错,onenand_mtd和board_nand_init又没有定义,查看common/Makefile
vim common/Makefile

obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
obj-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o
obj-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o

我们需要把环境变量保存到nand,所以屏蔽掉CONFIG_ENV_IS_IN_ONENAND,并定义宏CONFIG_ENV_IS_IN_NAND

vim include/configs/smdkv210.h 
#define CONFIG_ENV_IS_IN_NAND           1       /* add by Sourcelink */

#if 0
#define CONFIG_ENV_IS_IN_ONENAND        1
#endif


再次变编译,发现onenand_mtd的错误消失,只有board_nand_init没有定义了。搜索代码,发现只drivers/mtd/nand/s3c2410_nand.c中有定义,于是我们仿照s3c2410_nand.c修改一个s5pv210_nand.c 。

/* name:Sourcelink
 * (C) Copyright 2006 OpenMoko, Inc.
 * Author: Harald Welte 
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include 

#include 
#include 
#include 

#define MP0_1CON  (*(volatile unsigned long *)0xE02002E0)
#define	MP0_3CON  (*(volatile unsigned long *)0xE0200320)
#define	MP0_6CON  (*(volatile unsigned long *)0xE0200380)

/*  Nand Flash Configuration Register  */
#define AddrCycle 	1	/* 5 address cycle */
#define PageSize	0	/* 2KBytes/Page */
#define MLCFlash	0	/* SLC NAND Flash */
#define TWRPH1 		1	/* (0+1) * 7.5 > 5ns (tCLH/tALH) */
#define TWRPH0 		2	/* (1+1) * 7.5ns > 12ns (tWP) */
#define TACLS 		1	/* 7.5ns * 2 > 12ns tALS tCLS */

/* Control Register */
#define MODE		1	/* ENABLE NAND Flash Controller */
#define Reg_nCE0	1	/* Disable chip select */

/* modied by Sourcelink */
static void s5pv210_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
	struct nand_chip *chip = mtd->priv;
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
	ulong IO_ADDR_W = (ulong)nand;
	if (ctrl & NAND_CTRL_CHANGE) {
		
		if (ctrl & NAND_CLE)		
			IO_ADDR_W = IO_ADDR_W | 0x8;	/* Command Register  */
		else if (ctrl & NAND_ALE)
			IO_ADDR_W = IO_ADDR_W | 0xC;	/* Address Register */
			
		chip->IO_ADDR_W = (void *)IO_ADDR_W;

		if (ctrl & NAND_NCE)	/* select */
			writel(readl(&nand->nfcont) & ~(1 << 1), &nand->nfcont);
		else					/* deselect */
			writel(readl(&nand->nfcont) | (1 << 1), &nand->nfcont);
	}

	if (cmd != NAND_CMD_NONE)
		writeb(cmd, chip->IO_ADDR_W);	
	else
		chip->IO_ADDR_W = &nand->nfdata;

}

static int s5pv210_dev_ready(struct mtd_info *mtd)
{
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	debug("dev_ready\n");
	return readl(&nand->nfstat) & 0x01;
}

#ifdef CONFIG_S3C2410_NAND_HWECC
void s5pv210_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	debug("s5pv210_nand_enable_hwecc(%p, %d)\n", mtd, mode);
	writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
}

static int s5pv210_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
				      u_char *ecc_code)
{
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	ecc_code[0] = readb(&nand->nfecc);
	ecc_code[1] = readb(&nand->nfecc + 1);
	ecc_code[2] = readb(&nand->nfecc + 2);
	debug("s5pv210_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
	       mtd , ecc_code[0], ecc_code[1], ecc_code[2]);

	return 0;
}

static int s5pv210_nand_correct_data(struct mtd_info *mtd, u_char *dat,
				     u_char *read_ecc, u_char *calc_ecc)
{
	if (read_ecc[0] == calc_ecc[0] &&
	    read_ecc[1] == calc_ecc[1] &&
	    read_ecc[2] == calc_ecc[2])
		return 0;

	printf("s5pv210_nand_correct_data: not implemented\n");
	return -1;
}
#endif

/*
 * add by Sourcelink
 * nand_select_chip
 * @mtd: MTD device structure
 * @ctl: 0 to select, -1 for deselect
 *
 * Default select function for 1 chip devices.
 */
static void s5pv210_nand_select_chip(struct mtd_info *mtd, int ctl)
{
	struct nand_chip *chip = mtd->priv;

	switch (ctl) {
	case -1:	/* deselect the chip */
		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
		break;
	case 0:		/* Select the chip */
		chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
		break;

	default:
		BUG();
	}
}

/* modied by Sourcelink */
int board_nand_init(struct nand_chip *nand)
{
	u32 cfg;
	struct s5pv210_nand *nand_reg = (struct s5pv210_nand *)(struct s5pv210_nand *)samsung_get_base_nand();

	debug("board_nand_init()\n");

	/* initialize hardware */
	/* HCLK_PSYS=133MHz(7.5ns) */
	cfg =	((AddrCycle << 1) | (PageSize << 2) | (MLCFlash << 3) | (TWRPH1 << 4) | (TWRPH0 << 8) |  (TACLS << 12));
	
	writel(cfg, &nand_reg->nfconf);
	
	writel((Reg_nCE0 << 1) | (MODE << 0), &nand_reg->nfcont);
	/* Disable chip select and Enable NAND Flash Controller */
	
/*
 	* port map
 	* CE1-> Xm0CSn2 -> MP01_2
 	* CLE-> Xm0FCLE -> MP03_0
 	* ALE-> Xm0FALE -> MP03_1
 	* WE -> Xm0FWEn -> MP03_2
 	* RE -> Xm0FREn -> MP03_3
 	* R/B1->Xm0FRnB0-> MP03_4
 	* IO[7:0]->Xm0DATA[7:0]->MP0_6[7:0]
 	* */
	
	/* 设置片选引脚 CSN[0] */
	MP0_1CON &= ~(0x00000F00);
	MP0_1CON |= (3 << 8);
	
	/* CLE,ALE,WE,RE,R/B1 */
	MP0_3CON &= ~(0x000FFFFF);
	MP0_3CON |= 0x00022222;
	
	/* DATA */
	MP0_6CON = 0x22222222;
	
	/* initialize nand_chip data structure */
	nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
	nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

	nand->select_chip = s5pv210_nand_select_chip;

	/* read_buf and write_buf are default */
	/* read_byte and write_byte are default */

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

	nand->dev_ready = s5pv210_dev_ready;

#ifdef CONFIG_S3C2410_NAND_HWECC
	nand->ecc.hwctl = s5pv210_nand_enable_hwecc;
	nand->ecc.calculate = s5pv210_nand_calculate_ecc;
	nand->ecc.correct = s5pv210_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;
}

修改drivers/mtd/nand/Makefile,将s5pv210_nand.c编译进uboot。

vim drivers/mtd/nand/Makefile

obj-$(CONFIG_NAND_S5PV210) += s5pv210_nand.o    # add by Sourcelink 
vim include/configs/smdkv210.h 
#ifdef CONFIG_CMD_NAND                  /* add by Sourcelink */
#define CONFIG_SYS_MAX_NAND_DEVICE      1
#define CONFIG_SYS_NAND_BASE            0xB0E00000
#define CONFIG_NAND_S5PV210
#endif

首先我们需要用到nand相关的寄存器操作,在arch/arm/mach-s5pv210/include/mach/cpu.h中添加nand的基地址和宏
vim arch/arm/mach-s5pv210/include/mach/cpu.h
#define S5PV210_NAND_BASE       0xB0E00000
SAMSUNG_BASE(nand,NAND_BASE)

然后在arch/arm/mach-s5pv210/include/mach/下创建文件nand_reg.h,定义 NAND 的寄存器结构体

vim arch/arm/mach-s5pv210/include/mach/nand_reg.h

#ifndef __ASM_ARM_ARCH_NAND_REG_H_
#define __ASM_ARM_ARCH_NAND_REG_H_

#ifndef __ASSEMBLY__


struct s5pv210_nand {
        unsigned int    nfconf;
        unsigned int    nfcont;
        unsigned int    nfcmmd;
        unsigned int    nfaddr;
        unsigned int    nfdata;
        unsigned int    nfmeccd0;
        unsigned int    nfmeccd1;
        unsigned int    nfseccd;
        unsigned int    nfsblk;
        unsigned int    nfeblk;
        unsigned int    nfstat;
        unsigned int    nfeccerr0;
        unsigned int    nfeccerr1;
        unsigned int    nfmecc0;
        unsigned int    nfmecc1;
        unsigned int    nfsecc;
        unsigned int    nfmlcbitpt;
};

#endif

#endif

编译,发现产生u-boot.bin,烧录发现不能识别出nand的信息,参考u-boot2014版本在nand_init_chip函数中增加一条语句。

vim drivers/mtd/nand/nand.c

        if (maxchips < 1)
                maxchips = 1;

        mtd->priv = nand;               /* 仿照14版本u-boot添加  add by Sourcelink */
        nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;


二、nandflash分区

vim include/configs/smdkv210.h 

/* modied by Sourcelink */
#define MTDIDS_DEFAULT          "nand0=s5p-nand"
#define MTDPARTS_DEFAULT        "mtdparts=s5p-nand:256k(bootloader)"\
                                ",128k@0x40000(params)"\
                                ",3m@0x60000(kernel)"\
                                ",-(rootfs)"

256K给u-boot,128K给params,即环境变量,3M给内核,剩余的全部给根文件系统

如果上电后读取nand失败执行mtdparts default 重新初始化分区,然执行 saveenv 将其保持到 NAND

你可能感兴趣的:(u-boot)