增加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
- }
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);
- }
-
-
-
- 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;
- }
-
- }
- //
- 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;
- }
- #define S3C24X0_NAND_BASE 0x4E000000
- static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
- {
- return (struct s3c2440_nand *)S3C24X0_NAND_BASE;
- }
- #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
- 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;
- }
- 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;
- }
- 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
- }
-
- }
- /*
- * 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;
- }