📄 ~smc_core.c
字号:
/* 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 */ nand_command(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 */ nand_command(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 */ nand_command(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 */ nand_command(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 */ nand_command(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;}/* * 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 */ nand_command(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) { /* Send commands to erase a page */ nand_command(mtd, NAND_CMD_ERASE1, -1, page); nand_command(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 */ nand_command(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) { 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 return -EIO; } /* 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; /* Select the device */ nand_select(); /* Send the command for reading device ID */ nand_command(mtd, NAND_CMD_READID, 0x00, -1); this->wait_for_ready(); /* Read manufacturer and device IDs */ nand_maf_id = this->read_data(); nand_dev_id = this->read_data(); /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (nand_dev_id != nand_flash_ids[i].id) continue; if (!mtd->name) mtd->name = nand_flash_ids[i].name; this->chipsize = nand_flash_ids[i].chipsize << 20; /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; /* The 3rd id byte contains non relevant data ATM */ extid = this->read_byte(mtd); /* The 4th id byte is the important one */ extid = this->read_byte(mtd); /* 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; } else { /* Old devices have this data hardcoded in the * device id table */ mtd->erasesize = nand_flash_ids[i].erasesize; mtd->oobblock = nand_flash_ids[i].pagesize; mtd->oobsize = mtd->oobblock / 32; busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } /* Try to identify manufacturer */ for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { if (nand_manuf_ids[maf_id].id == nand_maf_id) break; } /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)e\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , mtd->name); printk (KERN_WARNING "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1); return 1; } /* Calculate the address shift from the page size */ this->page_shift = ffs(mtd->oobblock) - 1; this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ this->options &= ~NAND_CHIPOPTIONS_MSK; this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; /* Set this as a default. Board drivers can override it, if neccecary */ this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. */ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) this->options &= ~NAND_SAMSUNG_LP_OPTIONS; /* Check for AND chips with 4 page planes */ if (this->options & NAND_4PAGE_ARRAY) this->erase_cmd = multi_erase_cmd; else this->erase_cmd = single_erase_cmd; /* Do not replace user supplied command function ! */ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp;// printk (KERN_INFO "NAND device: page_shift:%d"// "bbt_erase_shift %d, chip_shift: %d \n", this->page_shift, this->bbt_erase_shift,// this->chip_shift); printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; } /* 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].model_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].page256) { 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 (!(mtd->size) && !(nand_flash_ids[i].page256)) { 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; mtd->oobblock = 2048; mtd->oobsize = 64; this->page_shift = 12; this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)]; }#endif*/ mtd->name = nand_flash_ids[i].name; mtd->size = (1 << nand_flash_ids[i].chipshift); /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; /* The 3rd id byte contains non relevant data ATM */ extid = this->read_byte(mtd); /* The 4th id byte is the important one */ extid = this->read_byte(mtd); /* 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; } else { /* Old devices have this data hardcoded in the * device id table */ mtd->erasesize = nand_flash_ids[i].erasesize; mtd->oobblock = nand_flash_ids[i].pagesize; mtd->oobsize = mtd->oobblock / 32; busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } 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; /* Return happy */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -