📄 nand_base.c
字号:
#ifdef CONFIG_SURPORT_WINCE#if 0 char oob_buf[16]; SectorInfo *psi = (SectorInfo *)oob_buf; int i; this->cmdfunc (mtd, NAND_CMD_READOOB, 0, page & this->pagemask); this->read_buf(mtd, oob_buf, 16); if (psi->bOEMReserved == (OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY) && psi->bBadBlock == BADBLOCKMARK) res = 0; else if (psi->bBadBlock != 0xff) res = 1;#endif //printf("bad? ofs = 0x%x, RESERVED_BOOT_BLOCKS = 0x%x, mtd->erasesize = 0x%x, mul = 0x%x\n", ofs, RESERVED_BOOT_BLOCKS, mtd->erasesize, RESERVED_BOOT_BLOCKS*mtd->erasesize); if (ofs < RESERVED_BOOT_BLOCKS * mtd->erasesize) res = 0; else#endif { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); if (this->read_byte(mtd) != 0xff) res = 1; } // Apply delay or wait for ready/busy pin // add by www.arm9.net, if not, the erase will be failed if (!this->dev_ready) udelay (this->chip_delay); else while (!this->dev_ready(mtd)); } if (getchip) { /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); } return res;}/** * nand_default_block_markbad - [DEFAULT] mark a block bad * @mtd: MTD device structure * @ofs: offset from device start * * This is the default implementation, which can be overridden by * a hardware specific driver.*/static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs){ struct nand_chip *this = mtd->priv; u_char buf[2] = {0, 0}; size_t retlen; int block; /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) return nand_update_bbt (mtd, ofs); /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); return nand_write_oob (mtd, ofs , 2, &retlen, buf);}/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd: MTD device structure * Check, if the device is write protected * * The function expects, that the device is already selected */static int nand_check_wp (struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); return (this->read_byte(mtd) & 0x80) ? 0 : 1;}/** * nand_block_checkbad - [GENERIC] Check if a block is marked bad * @mtd: MTD device structure * @ofs: offset from device start * @getchip: 0, if the chip is already selected * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt){ struct nand_chip *this = mtd->priv;// if (!this->bbt) return this->block_bad(mtd, ofs, getchip); /* Return info from the table */// return nand_isbad_bbt (mtd, ofs, allowbbt);}/** * nand_command - [DEFAULT] Send command to NAND device * @mtd: MTD device structure * @command: the command to be sent * @column: the column address for this command, -1 if none * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *this = mtd->priv; /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* * Write out the command to the device. */ if (command == NAND_CMD_SEQIN) { int readcmd; if (column >= mtd->oobblock) { /* OOB area */ column -= mtd->oobblock; readcmd = NAND_CMD_READOOB; } else if (column < 256) { /* First 256 bytes --> READ0 */ readcmd = NAND_CMD_READ0; } else { column -= 256; readcmd = NAND_CMD_READ1; } this->write_byte(mtd, readcmd); } this->write_byte(mtd, command); /* Set ALE and clear CLE to start address cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { this->hwcontrol(mtd, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; this->write_byte(mtd, column); } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } /* * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: return; case NAND_CMD_RESET: if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); while ( !(this->read_byte(mtd) & 0x40)); return; /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); /* wait until command is processed */ while (!this->dev_ready(mtd));}/** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd: MTD device structure * @command: the command to be sent * @column: the column address for this command, -1 if none * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page devices * We dont have the seperate regions as we have in the small page devices. * We must emulate NAND_CMD_READOOB to keep the code compatible. * */static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *this = mtd->priv; /* Emulate NAND_CMD_READOOB */ if (command == NAND_CMD_READOOB) { column += mtd->oobblock; command = NAND_CMD_READ0; } /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ this->write_byte(mtd, command); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); if (column != -1 || page_addr != -1) { this->hwcontrol(mtd, NAND_CTL_SETALE); /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; this->write_byte(mtd, column & 0xff); this->write_byte(mtd, column >> 8); } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } /* * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: return; case NAND_CMD_RESET: if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); while ( !(this->read_byte(mtd) & 0x40)); return; case NAND_CMD_READ0: /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the start read command */ this->write_byte(mtd, NAND_CMD_READSTART); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); /* wait until command is processed */ while (!this->dev_ready(mtd));}/** * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure * @new_state: the state which is requested * * Get the device and lock it for exclusive access *//* XXX U-BOOT XXX */#if 0static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state){ struct nand_chip *active = this; DECLARE_WAITQUEUE (wait, current); /* * Grab the lock and see if the device is available */retry: /* Hardware controller shared among independend devices */ if (this->controller) { spin_lock (&this->controller->lock); if (this->controller->active) active = this->controller->active; else this->controller->active = this; spin_unlock (&this->controller->lock); } if (active == this) { spin_lock (&this->chip_lock); if (this->state == FL_READY) { this->state = new_state; spin_unlock (&this->chip_lock); return; } } set_current_state (TASK_UNINTERRUPTIBLE); add_wait_queue (&active->wq, &wait); spin_unlock (&active->chip_lock); schedule (); remove_wait_queue (&active->wq, &wait); goto retry;}#elsestatic void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) {}#endif/** * nand_wait - [DEFAULT] wait until the command is done * @mtd: MTD device structure * @this: NAND chip structure * @state: state to select the max. timeout value * * Wait for command done. This applies to erase and program only * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs **//* XXX U-BOOT XXX */#if 0static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state){ unsigned long timeo = jiffies; int status; if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else timeo += (HZ * 20) / 1000; /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); else this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ if (this->state != state) return 0; if (this->dev_ready) { if (this->dev_ready(mtd)) break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; } yield (); } status = (int) this->read_byte(mtd); return status; return 0;}#elsestatic int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state){ unsigned long timeo; if (state == FL_ERASING) timeo = CFG_HZ * 400; else timeo = CFG_HZ * 20; if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); else this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); reset_timer(); while (1) { if (get_timer(0) > timeo) { printf("Timeout!"); return 0; } if (this->dev_ready) { if (this->dev_ready(mtd)) break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; } }#ifdef PPCHAMELON_NAND_TIMER_HACK reset_timer(); while (get_timer(0) < 10);#endif /* PPCHAMELON_NAND_TIMER_HACK */ return this->read_byte(mtd);}#endif/** * nand_write_page - [GENERIC] write one page * @mtd: MTD device structure * @this: NAND chip structure * @page: startpage inside the chip, must be called with (page & this->pagemask)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -