您的位置:首页 > 其它

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: