📄 smc_core.c
字号:
__FUNCTION__"(): to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Shift to get page */ page = ((int)to) >> this->page_shift; /* Mask to get column */ offset = to & 0x1f; /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ if ((offset + len) > mtd->oobsize) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Attempt to write past end of page\n"); return -EINVAL; } /* Select the NAND device */ nand_select(); /* Check the WP bit */ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); ret = -EPERM; goto nand_write_oob_err; } /* Write out desired data */ this->cmdfunc(mtd, NAND_CMD_SEQIN, offset + mtd->oobblock, page); this->hwcontrol(NAND_CTL_DAT_OUT); for (i = 0; i < len; i++) this->write_data(buf[i]); this->hwcontrol(NAND_CTL_DAT_IN); /* Send command to program the OOB data */ this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 3000us (3ms) on some devices, so we try * and exit as quickly as possible. */ status = 0; for (i = 0; i < 24; i++) { /* Delay for 125us */ udelay(125); /* Check the status */ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if device thinks it succeeded */ if (status & SMC_STAT_WRITE_ERR) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write, page 0x%08x\n", page); ret = -EIO; goto nand_write_oob_err; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ this->cmdfunc(mtd, NAND_CMD_READOOB, offset, page); this->wait_for_ready(); /* Loop through and verify the data */ for (i = 0; i < len; i++) { if (buf[i] != this->read_data()) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write verify, page 0x%08x\n", page); ret = -EIO; goto nand_write_oob_err; } }#endif /* Return happy */ *retlen = len; ret = 0; nand_write_oob_err: /* De-select the NAND device */ nand_deselect(); return ret;}static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs){ struct nand_chip *this = mtd->priv; unsigned long page;//#define __TEST__#ifdef __TEST__ /* Read the data */ int i; char buf[64]; char obyte;#endif page = ((int) ofs&~(mtd->erasesize - 1)) >> this->page_shift; /* Select the NAND device */ nand_select(); /* Send the read command */#ifdef __TEST__ this->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);#else this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page);#endif this->wait_for_ready();#ifdef __TEST__ /* Read the data */ for (i = 0; i < 64; i++) buf[i] = this->read_data(); if (buf[this->badblockpos]!=0xff) { /* De-select the NAND device */ nand_deselect(); printk("get oob byte(page:%08lx):",page); for (i = 0; i < 64; i++) { if (!(i&15)) printk("\n"); printk("%02x ",buf[i]); } return 1; }#else /* Read the data */ if (this->read_data() != 0xff) { /* De-select the NAND device */ nand_deselect(); return 1; }#endif /* De-select the NAND device */ nand_deselect(); /* Return happy */ return 0;}static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs){ struct nand_chip *this = mtd->priv; unsigned char buf[2]={0,0}; size_t retlen; printk("block bad:%d\n",ofs/mtd->erasesize); return nand_write_oob(mtd,(ofs&~(mtd->erasesize - 1))+this->badblockpos,2,&retlen,buf);}static int nand_check_blockbad (struct mtd_info *mtd, loff_t ofs){ struct nand_chip *this = mtd->priv; unsigned long page;#ifdef __TEST__ /* Read the data */ int i; char buf[64]; char obyte;#endif page = ((int) ofs&~(mtd->erasesize - 1)) >> this->page_shift; /* Send the read command */#ifdef __TEST__ this->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);#else this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page);#endif this->wait_for_ready();#ifdef __TEST__ /* Read the data */ for (i = 0; i < 64; i++) buf[i] = this->read_data(); if (buf[this->badblockpos]!=0xff) { printk("get oob byte(page:%08lx):",page); for (i = 0; i < 64; i++) { if (!(i&15)) printk("\n"); printk("%02x ",buf[i]); } return 1; }#else /* Read the data */ if (this->read_data() != 0xff) { return 1; }#endif /* Return happy */ return 0;}/* * NAND erase a block */static intnand_erase(struct mtd_info *mtd, struct erase_info *instr){ int i, page, len, status, pages_per_block; struct nand_chip *this = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, __FUNCTION__"(): start = 0x%08x, len = %i\n", (unsigned int)instr->addr, (unsigned int)instr->len); /* Start address must aligned on block boundary */ if (instr->addr & (mtd->erasesize - 1)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (instr->len & (mtd->erasesize - 1)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if ((instr->len + instr->addr) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Erase past end of device\n"); return -EINVAL; } /* Shift to get first page */ page = (int)(instr->addr >> this->page_shift); /* Calculate pages in each block */ pages_per_block = mtd->erasesize / mtd->oobblock; /* Select the NAND device */ nand_select(); /* Check the WP bit */ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); nand_deselect(); return -EIO; } /* Loop through the pages */ len = instr->len; while (len) { if (!nand_check_blockbad(mtd, page << this->page_shift)) { /* Send commands to erase a page */ this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 4000us (4ms) on some devices, so we try * and exit as quickly as possible. */ status = 0; for (i = 0; i < 32; i++) { /* Delay for 125us */ udelay(125); /* Check the status */ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if block erase succeeded */ if (status & SMC_STAT_WRITE_ERR/* || (page==1024+512)*/) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed erase, page 0x%08x\n", page); nand_deselect();#if 0 instr->state = MTD_ERASE_FAILED; if (instr->callback) instr->callback(instr);#endif nand_block_markbad(mtd,page<<this->page_shift); /* Select the NAND device */ nand_select(); //return -EIO; } } else {printk("erase block bad:%d\n",page/pages_per_block);} /* Increment page address and decrement length */ len -= mtd->erasesize; page += pages_per_block; } /* De-select the NAND device */ nand_deselect();#if 0 /* Do call back function */ instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr);#endif /* Return happy */ return 0; }/* * Scan for the SMC device */intsmc_scan(struct mtd_info *mtd){ int i, nand_maf_id, nand_dev_id; struct nand_chip *this = mtd->priv; //if (!(this->cmdfunc)) this->cmdfunc = nand_command; /* Select the device */#if defined(CONFIG_ARCH_S3C2410) nand_select();#elif defined(CONFIG_ARCH_S3C2440) this->hwcontrol(NAND_CTL_SETNCE); this->hwcontrol(NAND_CTL_CLRRnB); #endif /* Send the command for reading device ID */ nand_command(mtd, NAND_CMD_READID, 0x00, -1);#if defined(CONFIG_ARCH_S3C2410) this->wait_for_ready();#elif defined(CONFIG_ARCH_S3C2440) for (i = 0; i<100 ;i++);#endif /* Read manufacturer and device IDs */ nand_maf_id = this->read_data(); nand_dev_id = this->read_data(); //printk("Get NAND device: Manufacture ID:" // " 0x%02x, Chip ID: 0x%02x\n", // nand_maf_id, nand_dev_id); /* Print and sotre flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (nand_maf_id == nand_flash_ids[i].manufacture_id && nand_dev_id == nand_flash_ids[i].dev_id) {#ifdef USE_256BYTE_NAND_FLASH if (!mtd->size) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; if (nand_flash_ids[i].pagesize == PAGESIZE256) { mtd->oobblock = 256; mtd->oobsize = 8; this->page_shift = 8; } else { mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; } this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; }#else if (!(nand_flash_ids[i].pagesize)) { int extid; /* The 3rd id byte contains non relevant data ATM */ extid = this->read_data(); /* The 4th id byte is the important one */ extid = this->read_data(); /* Calc pagesize */ mtd->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ //busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; mtd->name = nand_flash_ids[i].name; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; this->page_shift = 11; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; this->badblockpos = 0; } else if (!(mtd->size) && (nand_flash_ids[i].pagesize != PAGESIZE256)) { mtd->name = nand_flash_ids[i].name; mtd->erasesize = nand_flash_ids[i].erasesize; mtd->size = (1 << nand_flash_ids[i].chipshift); mtd->eccsize = 256; mtd->oobblock = 512; mtd->oobsize = 16; this->page_shift = 9; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; this->badblockpos = 5; }#endif /* Do not replace user supplied command function ! */ if ((mtd->oobblock>512) && (this->cmdfunc == nand_command)) this->cmdfunc = nand_command_lp; printk("NAND device: Manufacture ID:" \ " 0x%02x, Chip ID: 0x%02x (%s)\n", nand_maf_id, nand_dev_id, mtd->name); break; } } /* De-select the device */ nand_deselect(); /* Print warning message for no device */ if (!mtd->size) { printk("No NAND device found!!!\n"); return 1; } /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; mtd->module = NULL; mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; mtd->unpoint = NULL; mtd->read = nand_read; mtd->write = nand_write; mtd->read_ecc = nand_read_ecc; mtd->write_ecc = nand_write_ecc; mtd->read_oob = nand_read_oob; mtd->write_oob = nand_write_oob; mtd->lock = NULL; mtd->unlock = NULL; mtd->block_isbad = nand_block_isbad; mtd->block_markbad = nand_block_markbad; /* Return happy */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -