bootloader---23.u-boot-2010.06-rc1移植之3nand flash移植
2016-08-30 11:13
253 查看
增加nand flash 特性
当可以正常启动serial可以显示之后,接下来移植nand flash
1. nand flash的初始化是在 arch/arm/lib/board.c中
arch/arm/lib/board.c
start_armboot
{
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go
init the NAND */
#endif
}
所以需要在include/configs/smdk2410.h中添加: #define CONFIG_CMD_NAND 1
2.nand的初始化
#ifndef CONFIG_SYS_NAND_BASE_LIST
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
#endif
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
//base_address初始化为CONFIG_SYS_NAND_BASE
所以需要在include/configs/smdk2410.h中添加: #define
CONFIG_SYS_NAND_BASE 0x4E000000
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
{
//CONFIG_SYS_MAX_NAND_DEVICE=1所以只需要进行一次nand_init_chip
//初始化nand的
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", size / 1024);
}
3. driver/mtd/nand/nand.c L42
static void nand_init_chip(struct mtd_info *mtd, struct
nand_chip *nand,
ulong base_addr)
{
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
int __attribute__((unused)) i = 0;
if (maxchips < 1)
maxchips = 1;
mtd->priv = nand;
//以后要用到nand来控制底层寄存器,这儿先保存起nand来,这个非常重要
nand->IO_ADDR_R = nand->IO_ADDR_W = (void
__iomem *)base_addr;//初始化读写指针为0x4E000000,以后真正读写时指针要改变
if (board_nand_init(nand) == 0) {
//board_nand_init寄存器纸别的初始化
if (nand_scan(mtd, maxchips) == 0) {
//
if (!mtd->name)
mtd->name = (char *)default_nand_name;
} else
mtd->name = NULL;
} else {
mtd->name = NULL;
mtd->size = 0;
}
}
4. drivers/mtd/nand/s3c2410_nand.c
//
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int32_t cnt;
u_int8_t tacls, twrph0, twrph1;
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debugX(1, "board_nand_init()\n");
/* initialize hardware */
tacls = 0;
twrph0 = 4;
twrph1 = 2;
cfg |= S3C2440_NFCONF_TACLS(tacls);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
writel(cfg, &nand_reg->NFCONF);
//NAND Flash control register
//bit6: Lock spare ECC
//bit4: Initialize ECC decoder/encoder
//bit1: enable chip_select
//bit0: nand_enable
cnt =(1<<6)| (1<<4)|(0<<1)|(1<<0);
writel(cnt, &nand_reg->NFCONT);
//不仅需要配寄存器NFCONF,而且需要配寄存器NFCONT
//以下初始化函数指针
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
nand->select_chip = s3c2440_nand_select_chip;
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
nand->ecc.mode = NAND_ECC_SOFT;
//进行软件的ECC校验
nand->options = 0;
//BUS_WIDTH 8位
debugX(1, "end of nand_init\n");
return 0;
}
这儿调用了s3c2440_get_base_nand,需要在include/asm/arch-s3c24x0/s3c2410.h中添加这个函数
#define S3C24X0_NAND_BASE 0x4E000000
static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
{
return (struct s3c2440_nand *)S3C24X0_NAND_BASE;
}
同时S3C2440_NFCONF_TACLS等这几个宏跟手册上的位置不匹配,所以修改一下
#define S3C2440_NFCONF_TACLS(x)
((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x)
((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x)
((x)<<4)
#define S3C2440_NFCONT_nCE
(1<<1)
#define S3C2440_NFCONT_MODE_DISABLE
(0<<0)
#define S3C2440_NFCONT_MODE_ENABLE
(1<<0)
#define S3C2440_NFSTAT_READY
(1<<0)
#define S3C2440_ADDR_NALE
0x0C
#define S3C2440_ADDR_NCLE
0x08
5. driver/mtd/nand/nand_base.c
L3061
start_armboot-> nand_init->nand_init_chip
int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;
ret = nand_scan_ident(mtd, maxchips);
if (!ret)
ret = nand_scan_tail(mtd);
return ret;
}
6. driver/mtd/nand/nand_base.c L2770
start_armboot-> nand_init->nand_init_chip->nand_scan
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
int i, busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
//函数nand_init_chip中保存的nand_chip结构体
struct nand_flash_dev *type;
/* Get buswidth to select the
correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
/* Set the default functions */
nand_set_defaults(chip, busw);
//对nand_chip结构体进一步初始化
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
if (IS_ERR(type)) {
#ifndef CONFIG_SYS_NAND_QUIET_TEST
printk(KERN_WARNING "No NAND device found!!!\n");
#endif
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
type->id != chip->read_byte(mtd))
break;
}
#ifdef DEBUG
if (i > 1)
printk(KERN_INFO "%d NAND chips detected\n", i);
#endif
/* Store the number of chips and calc total size for mtd */
chip->numchips = i;
mtd->size = i * chip->chipsize;
return 0;
}
6. driver/mtd/nand/nand_base.c L2555
start_armboot-> nand_init->nand_init_chip->nand_scan-->nand_scan_ident
//设置默认的函数指针
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
//设置延时=20
/* check, if a
user supplied command function given */
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
//cmd_func=nand_command,以后就靠它发命令了
/* check, if a
user supplied wait function given */
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
//nand_wait
if (!chip->select_chip)
chip->select_chip = nand_select_chip;
//不进入
if (!chip->read_byte)
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
//read_byte=nand_read_byte
if (!chip->read_word)
chip->read_word = nand_read_word;
//read_word=nand_read_word
if (!chip->block_bad)
chip->block_bad = nand_block_bad;
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
/* XXX U-BOOT XXX */
#if 0
spin_lock_init(&chip->controller->lock);
init_waitqueue_head(&chip->controller->wq);
#endif
}
}
7. driver/mtd/nand/nand_base.c L2603
/*
* Get the flash and manufacturer id and lookup if the
type is supported
*/
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip, int busw, int *maf_id)
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
int tmp_id, tmp_manf;
//以下是读取设备ID的过程:参见K9F2G08U0B的datasheet
//1. 发送命令0x90 2.发送地址0x00 3.读取第一个字节为manufacturer 第二个字节为DEV_ID
/* Select the device: 设置NFCONT D1=0 */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron
MT29FxGxxxxx)
* after power-up
*/
//调用nand_command-->s3c2440_hwcontrol向nandflash的NFCMMD寄存器发送0xFF(RESET指令)
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
//1. 发送命令0x90 2.发送地址0x00
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
//返回的第一个字节为0xEC 第二个字节为0xDA
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/* Try again to make sure, as
some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the
two results do
* not match, ignore the device completely.
*/
//重新读取,验证第一次读取的结果是正确的
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
if (tmp_manf != *maf_id || tmp_id != dev_id) {
printk(KERN_INFO "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
*maf_id, dev_id, tmp_manf, tmp_id);
return ERR_PTR(-ENODEV);
}
//从nand_flash_ids表中查找 id=0xDA的项
// name id pagesize chipsize erasesize options
//
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
}
if (!type)
return ERR_PTR(-ENODEV);
if (!mtd->name)
mtd->name = type->name;
//设定chipsize=256M=256<<20
chip->chipsize = (uint64_t)type->chipsize << 20;
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
//根据K9F2G08U0B的datasheet P29
int extid;
/* The 3rd id byte holds MLC / multichip data */
chip->cellinfo = chip->read_byte(mtd);
//cellinfo=0x10
/* The 4th id byte is the important one */
extid = chip->read_byte(mtd);
//extid=0x95
/* Calc pagesize ,extid的D0-D1是pagesize*/
mtd->writesize = 1024 << (extid & 0x3);
extid >>= 2;
/* Calc oobsize extid的D2位的单位是byte/512byte,所以求oob,需要乘pagesize/512 */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB, 求block_size, exit的D4-D5位是1的话对应128K的block_size*/
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information: extid的D6位是buswidth 0--8位的buswidth */
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
} else {
/*
* Old devices have chip data hardcoded in the device id table
*/
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
}
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
/*
* Check, if buswidth is correct. Hardware
drivers should set
* chip correct !
*/
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
}
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
/* Convert chipsize to number of pages per chip -1. */
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
/* Get chip options, preserve
non chip based options */
chip->options &= ~NAND_CHIPOPTIONS_MSK;
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
/*
* Set chip as a default. Board drivers can override it, if necessary
*/
chip->options |= NAND_NO_AUTOINCR;
/* Check if chip is a not a
samsung device. Do not clear the
* options for chips which are not having an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
/* Check for AND chips
with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
else
chip->erase_cmd = single_erase_cmd;
/* Do not replace user
supplied command function ! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
nand_manuf_ids[maf_idx].name, type->name);
return type;
}
2. 在include/configs/smdk2410.h中添加
#define CONFIG_CMD_NAND
1
#define CONFIG_SYS_MAX_NAND_DEVICE
1
#define CONFIG_SYS_NAND_BASE
0x4E000000
3.start_armboot--> nand_init 在driver/mtd/nand/nand.c中
nand_init-->nand_init_chip-->board_nand_init
4. board_nand_init函数在driver/mtd/nand/s3c2410_nand.c中
不过这需要在 include/configs/smdk2410.h中添加
#define CONFIG_NAND_S3C2410
1
5.删除多余的文件
root@ubuntu:~/u-boot-2010.06-rc1/drivers/mtd/nand# rm atmel_nand.c bfin_nand.c davinci_nand.c fsl_elbc_nand.c fsl_upm.c kb9202_nand.c kirkwood_nand.c kmeter1_nand.c mpc5121_nfc.c mxc_nand.c ndfc.c nomadik.c s3c64xx.c spr_nand.c
omap_gpmc.c nand_plat.c
同时在driver/mtd/nand/Makefile中删除多余的东东,不删也没有关系。
root@ubuntu:~/uboot/u-boot-2010.06-rc1# vi drivers/mtd/nand/Makefile
6. 这里候就可以编译通过了,不过打印的是
DRAM: 64 MiB
Flash: 512 KiB
NAND: No NAND device found!!!
0 MiB
*** Warning - bad CRC, using default environment
7. 修改一下driver/mtd/nand/s3c2410_nand.c中的board_nand_init函数
a.将driver/mtd/nand/s3c2410_nand.c中所有的2410替换为2440
8. 在include/asm/arch-s3c24x0/s3c2410.h中添加
#define S3C24X0_NAND_BASE
0x4E000000
static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
{
return (struct s3c2440_nand *)S3C24X0_NAND_BASE;
}
9. 在driver/mtd/nand/s3c2410_nand.c中
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int32_t cnt;
u_int8_t tacls, twrph0, twrph1;
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debugX(1, "board_nand_init()\n");
//writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
/* initialize hardware */
tacls = 0;
twrph0 = 4;
twrph1 = 2;
cfg |= S3C2440_NFCONF_TACLS(tacls);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
writel(cfg, &nand_reg->NFCONF);
//NAND Flash control register
//bit6: Lock spare ECC
//bit4: Initialize ECC decoder/encoder
//bit1: enable chip_select
//bit0: nand_enable
cnt =(1<<6)| (1<<4)|(0<<1)|(1<<0);
writel(cnt, &nand_reg->NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
nand->select_chip = s3c2440_nand_select_chip;
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
nand->ecc.mode = NAND_ECC_SOFT;
nand->options = 0;
debugX(1, "end of nand_init\n");
return 0;
}
当可以正常启动serial可以显示之后,接下来移植nand flash
1. nand flash的初始化是在 arch/arm/lib/board.c中
arch/arm/lib/board.c
start_armboot
{
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go
init the NAND */
#endif
}
所以需要在include/configs/smdk2410.h中添加: #define CONFIG_CMD_NAND 1
2.nand的初始化
#ifndef CONFIG_SYS_NAND_BASE_LIST
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
#endif
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
//base_address初始化为CONFIG_SYS_NAND_BASE
所以需要在include/configs/smdk2410.h中添加: #define
CONFIG_SYS_NAND_BASE 0x4E000000
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
{
//CONFIG_SYS_MAX_NAND_DEVICE=1所以只需要进行一次nand_init_chip
//初始化nand的
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", size / 1024);
}
3. driver/mtd/nand/nand.c L42
static void nand_init_chip(struct mtd_info *mtd, struct
nand_chip *nand,
ulong base_addr)
{
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
int __attribute__((unused)) i = 0;
if (maxchips < 1)
maxchips = 1;
mtd->priv = nand;
//以后要用到nand来控制底层寄存器,这儿先保存起nand来,这个非常重要
nand->IO_ADDR_R = nand->IO_ADDR_W = (void
__iomem *)base_addr;//初始化读写指针为0x4E000000,以后真正读写时指针要改变
if (board_nand_init(nand) == 0) {
//board_nand_init寄存器纸别的初始化
if (nand_scan(mtd, maxchips) == 0) {
//
if (!mtd->name)
mtd->name = (char *)default_nand_name;
} else
mtd->name = NULL;
} else {
mtd->name = NULL;
mtd->size = 0;
}
}
4. drivers/mtd/nand/s3c2410_nand.c
//
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int32_t cnt;
u_int8_t tacls, twrph0, twrph1;
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debugX(1, "board_nand_init()\n");
/* initialize hardware */
tacls = 0;
twrph0 = 4;
twrph1 = 2;
cfg |= S3C2440_NFCONF_TACLS(tacls);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
writel(cfg, &nand_reg->NFCONF);
//NAND Flash control register
//bit6: Lock spare ECC
//bit4: Initialize ECC decoder/encoder
//bit1: enable chip_select
//bit0: nand_enable
cnt =(1<<6)| (1<<4)|(0<<1)|(1<<0);
writel(cnt, &nand_reg->NFCONT);
//不仅需要配寄存器NFCONF,而且需要配寄存器NFCONT
//以下初始化函数指针
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
nand->select_chip = s3c2440_nand_select_chip;
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
nand->ecc.mode = NAND_ECC_SOFT;
//进行软件的ECC校验
nand->options = 0;
//BUS_WIDTH 8位
debugX(1, "end of nand_init\n");
return 0;
}
这儿调用了s3c2440_get_base_nand,需要在include/asm/arch-s3c24x0/s3c2410.h中添加这个函数
#define S3C24X0_NAND_BASE 0x4E000000
static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
{
return (struct s3c2440_nand *)S3C24X0_NAND_BASE;
}
同时S3C2440_NFCONF_TACLS等这几个宏跟手册上的位置不匹配,所以修改一下
#define S3C2440_NFCONF_TACLS(x)
((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x)
((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x)
((x)<<4)
#define S3C2440_NFCONT_nCE
(1<<1)
#define S3C2440_NFCONT_MODE_DISABLE
(0<<0)
#define S3C2440_NFCONT_MODE_ENABLE
(1<<0)
#define S3C2440_NFSTAT_READY
(1<<0)
#define S3C2440_ADDR_NALE
0x0C
#define S3C2440_ADDR_NCLE
0x08
5. driver/mtd/nand/nand_base.c
L3061
start_armboot-> nand_init->nand_init_chip
int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;
ret = nand_scan_ident(mtd, maxchips);
if (!ret)
ret = nand_scan_tail(mtd);
return ret;
}
6. driver/mtd/nand/nand_base.c L2770
start_armboot-> nand_init->nand_init_chip->nand_scan
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
int i, busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
//函数nand_init_chip中保存的nand_chip结构体
struct nand_flash_dev *type;
/* Get buswidth to select the
correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
/* Set the default functions */
nand_set_defaults(chip, busw);
//对nand_chip结构体进一步初始化
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
if (IS_ERR(type)) {
#ifndef CONFIG_SYS_NAND_QUIET_TEST
printk(KERN_WARNING "No NAND device found!!!\n");
#endif
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
type->id != chip->read_byte(mtd))
break;
}
#ifdef DEBUG
if (i > 1)
printk(KERN_INFO "%d NAND chips detected\n", i);
#endif
/* Store the number of chips and calc total size for mtd */
chip->numchips = i;
mtd->size = i * chip->chipsize;
return 0;
}
6. driver/mtd/nand/nand_base.c L2555
start_armboot-> nand_init->nand_init_chip->nand_scan-->nand_scan_ident
//设置默认的函数指针
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
//设置延时=20
/* check, if a
user supplied command function given */
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
//cmd_func=nand_command,以后就靠它发命令了
/* check, if a
user supplied wait function given */
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
//nand_wait
if (!chip->select_chip)
chip->select_chip = nand_select_chip;
//不进入
if (!chip->read_byte)
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
//read_byte=nand_read_byte
if (!chip->read_word)
chip->read_word = nand_read_word;
//read_word=nand_read_word
if (!chip->block_bad)
chip->block_bad = nand_block_bad;
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
/* XXX U-BOOT XXX */
#if 0
spin_lock_init(&chip->controller->lock);
init_waitqueue_head(&chip->controller->wq);
#endif
}
}
7. driver/mtd/nand/nand_base.c L2603
/*
* Get the flash and manufacturer id and lookup if the
type is supported
*/
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip, int busw, int *maf_id)
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
int tmp_id, tmp_manf;
//以下是读取设备ID的过程:参见K9F2G08U0B的datasheet
//1. 发送命令0x90 2.发送地址0x00 3.读取第一个字节为manufacturer 第二个字节为DEV_ID
/* Select the device: 设置NFCONT D1=0 */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron
MT29FxGxxxxx)
* after power-up
*/
//调用nand_command-->s3c2440_hwcontrol向nandflash的NFCMMD寄存器发送0xFF(RESET指令)
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
//1. 发送命令0x90 2.发送地址0x00
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
//返回的第一个字节为0xEC 第二个字节为0xDA
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/* Try again to make sure, as
some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the
two results do
* not match, ignore the device completely.
*/
//重新读取,验证第一次读取的结果是正确的
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
if (tmp_manf != *maf_id || tmp_id != dev_id) {
printk(KERN_INFO "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
*maf_id, dev_id, tmp_manf, tmp_id);
return ERR_PTR(-ENODEV);
}
//从nand_flash_ids表中查找 id=0xDA的项
// name id pagesize chipsize erasesize options
//
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
}
if (!type)
return ERR_PTR(-ENODEV);
if (!mtd->name)
mtd->name = type->name;
//设定chipsize=256M=256<<20
chip->chipsize = (uint64_t)type->chipsize << 20;
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
//根据K9F2G08U0B的datasheet P29
int extid;
/* The 3rd id byte holds MLC / multichip data */
chip->cellinfo = chip->read_byte(mtd);
//cellinfo=0x10
/* The 4th id byte is the important one */
extid = chip->read_byte(mtd);
//extid=0x95
/* Calc pagesize ,extid的D0-D1是pagesize*/
mtd->writesize = 1024 << (extid & 0x3);
extid >>= 2;
/* Calc oobsize extid的D2位的单位是byte/512byte,所以求oob,需要乘pagesize/512 */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB, 求block_size, exit的D4-D5位是1的话对应128K的block_size*/
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information: extid的D6位是buswidth 0--8位的buswidth */
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
} else {
/*
* Old devices have chip data hardcoded in the device id table
*/
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
}
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
/*
* Check, if buswidth is correct. Hardware
drivers should set
* chip correct !
*/
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
}
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
/* Convert chipsize to number of pages per chip -1. */
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
/* Get chip options, preserve
non chip based options */
chip->options &= ~NAND_CHIPOPTIONS_MSK;
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
/*
* Set chip as a default. Board drivers can override it, if necessary
*/
chip->options |= NAND_NO_AUTOINCR;
/* Check if chip is a not a
samsung device. Do not clear the
* options for chips which are not having an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
/* Check for AND chips
with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
else
chip->erase_cmd = single_erase_cmd;
/* Do not replace user
supplied command function ! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
nand_manuf_ids[maf_idx].name, type->name);
return type;
}
2. 在include/configs/smdk2410.h中添加
#define CONFIG_CMD_NAND
1
#define CONFIG_SYS_MAX_NAND_DEVICE
1
#define CONFIG_SYS_NAND_BASE
0x4E000000
3.start_armboot--> nand_init 在driver/mtd/nand/nand.c中
nand_init-->nand_init_chip-->board_nand_init
4. board_nand_init函数在driver/mtd/nand/s3c2410_nand.c中
不过这需要在 include/configs/smdk2410.h中添加
#define CONFIG_NAND_S3C2410
1
5.删除多余的文件
root@ubuntu:~/u-boot-2010.06-rc1/drivers/mtd/nand# rm atmel_nand.c bfin_nand.c davinci_nand.c fsl_elbc_nand.c fsl_upm.c kb9202_nand.c kirkwood_nand.c kmeter1_nand.c mpc5121_nfc.c mxc_nand.c ndfc.c nomadik.c s3c64xx.c spr_nand.c
omap_gpmc.c nand_plat.c
同时在driver/mtd/nand/Makefile中删除多余的东东,不删也没有关系。
root@ubuntu:~/uboot/u-boot-2010.06-rc1# vi drivers/mtd/nand/Makefile
6. 这里候就可以编译通过了,不过打印的是
DRAM: 64 MiB
Flash: 512 KiB
NAND: No NAND device found!!!
0 MiB
*** Warning - bad CRC, using default environment
7. 修改一下driver/mtd/nand/s3c2410_nand.c中的board_nand_init函数
a.将driver/mtd/nand/s3c2410_nand.c中所有的2410替换为2440
8. 在include/asm/arch-s3c24x0/s3c2410.h中添加
#define S3C24X0_NAND_BASE
0x4E000000
static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
{
return (struct s3c2440_nand *)S3C24X0_NAND_BASE;
}
9. 在driver/mtd/nand/s3c2410_nand.c中
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int32_t cnt;
u_int8_t tacls, twrph0, twrph1;
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debugX(1, "board_nand_init()\n");
//writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
/* initialize hardware */
tacls = 0;
twrph0 = 4;
twrph1 = 2;
cfg |= S3C2440_NFCONF_TACLS(tacls);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1);
writel(cfg, &nand_reg->NFCONF);
//NAND Flash control register
//bit6: Lock spare ECC
//bit4: Initialize ECC decoder/encoder
//bit1: enable chip_select
//bit0: nand_enable
cnt =(1<<6)| (1<<4)|(0<<1)|(1<<0);
writel(cnt, &nand_reg->NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
nand->select_chip = s3c2440_nand_select_chip;
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
nand->ecc.mode = NAND_ECC_SOFT;
nand->options = 0;
debugX(1, "end of nand_init\n");
return 0;
}
相关文章推荐
- bootloader---21.u-boot-2010.06-rc1移植之调试的思路
- bootloader---22.u-boot-2010.06-rc1移植之2搭建框架
- bootloader---24.u-boot-2010.06-rc1移植之4saveenv
- bootloader---25.u-boot-2010.06-rc1移植之5usb下载
- u-boot-2009.08在mini2440上的移植(三)---增加nand flash功能——调试心得
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (一)
- TX2440 ARM开发板Uboot移植(三、添加Nand Flash的有关操作支持)
- DAVINCI DM3730开发攻略——U-BOOT-2010.06的移植 推荐
- Davinci DM6446开发攻略-UBOOT-2009.03移植2 nand flash的烧写
- 用mini2440开发板学习韦东山毕业班移植最新的u-boot支持nand flash
- uImage在内存中无法正常启动——UBoot-2010.06在TQ2440上的移植--机器码配对
- <2012 12 02> FL2440开发板的U-boot-2010.09版本移植(三) 如何利用JLINK烧写U-boot到NAND Flash中
- u-boot 2013.04-rc1移植(1)
- u-boot-2012.04.01移植到TQ2440(六):支持NAND FLASH启动
- u-boot 2013.04-rc1移植(4)
- uImage在内存中无法正常启动——UBoot-2010.06在TQ2440上的移植--机器码配对
- u-boot在s3c2410开发板上移植(NAND Flash Boot)过程
- U-Boot移植——Nand Flash
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (二)
- u-boot-2009.08在mini2440上的移植(三)---增加nand flash功能