一、移植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
vim include/configs/smdkv210.h
#define CONFIG_CMD_NAND /* modied by Sourcelink */
#define CONFIG_CMD_REGINFO
#undef CONFIG_CMD_ONENAND /* modied by Sourcelink */
vim drivers/mtd/nand/nand.c
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
nand_init_chip(i);
/*
* NAND Contoller driver
*/
#ifdef CONFIG_CMD_NAND /* add by Sourcelink */
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#endif
#ifdef CONFIG_CMD_NAND /* add by Sourcelink */
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0xB0E00000
#endif
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
/* 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;
}
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
vim arch/arm/mach-s5pv210/include/mach/cpu.h
#define S5PV210_NAND_BASE 0xB0E00000
SAMSUNG_BASE(nand,NAND_BASE)
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
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;
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)"
如果上电后读取nand失败执行mtdparts default 重新初始化分区,然执行 saveenv 将其保持到 NAND