📄 jz4730_nand.c
字号:
/*************************************************************************** ** NAND Flash Driver for Jz4730. ** ** This file was derived from CELinux. The header files should also be ** referred to CELinux. ** ***************************************************************************/#include "cdefs.h"#include "types.h"#include "nand.h"#include "bitops.h"#include "debug.h"#include <stdlib.h>#include <string.h>#include "jiffies.h"#include "byteorder.h"#include "delay.h"#include "errno.h"#include "ucos_ii.h"#include "task_prio.h"#ifdef CONFIG_MTD_PARTITIONS# include "mtd_partition.h"#endif#include "memzero.h"#include "regs.h"//-------------------------------------------------------------------////-------------------- nand_base.c routines ------------------------////-------------------------------------------------------------------///* Define default oob placement schemes for large and small page devices */static struct nand_oobinfo nand_oob_8 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 3, .eccpos = {0, 1, 2}, .oobfree = { {3, 2}, {6, 2} }};static struct nand_oobinfo nand_oob_16 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, .eccpos = {0, 1, 2, 3, 6, 7}, .oobfree = { {8, 8} }};static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {2, 38} }};/* This is used for padding purposes in nand_write_oob */static u_char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,};/* * NAND low-level MTD interface functions */static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen);static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);static void nand_sync (struct mtd_info *mtd);/* Some internal functions */static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode);#ifdef CONFIG_MTD_NAND_VERIFY_WRITEstatic int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);#else#define nand_verify_pages(...) (0)#endif/** * 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 */static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state){ u8 err; for (;;) { if (this->state == FL_READY) { this->state = new_state; return 0; } if (new_state == FL_PM_SUSPENDED) { return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; } OSMutexPend(this->mutex, 0, &err); }}/** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */static void nand_release_device (struct mtd_info *mtd){ struct nand_chip* this = mtd->priv; u32 psr; bool flag; /* De-select the NAND device */ nand_select_chip(mtd, -1); local_irq_save(psr); flag = (this->mutex->OSEventCnt & 0xffU) != 0xffU && (this->mutex->OSEventCnt & 0xffU) == OSPrioCur; local_irq_restore(psr); /* Release the chip */ this->state = FL_READY; if (flag) OSMutexPost(this->mutex);}/** * nand_read_byte - [DEFAULT] read one byte from the chip * @mtd: MTD device structure * * Default read function for 8bit buswith */static u_char nand_read_byte(struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; return readb(this->IO_ADDR_R);}/** * nand_write_byte - [DEFAULT] write one byte to the chip * @mtd: MTD device structure * @byte: pointer to data byte to write * * Default write function for 8it buswith */static void nand_write_byte(struct mtd_info *mtd, u_char byte){ struct nand_chip *this = mtd->priv; writeb(byte, this->IO_ADDR_W);}/** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * * Default read function for 16bit buswith with * endianess conversion */static u_char nand_read_byte16(struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; return (u_char) readw(this->IO_ADDR_R);}/** * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip * @mtd: MTD device structure * @byte: pointer to data byte to write * * Default write function for 16bit buswith with * endianess conversion */static void nand_write_byte16(struct mtd_info *mtd, u_char byte){ struct nand_chip *this = mtd->priv; writew((u16) byte, this->IO_ADDR_W);}/** * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * * Default read function for 16bit buswith without * endianess conversion */static u16 nand_read_word(struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; return readw(this->IO_ADDR_R);}/** * nand_write_word - [DEFAULT] write one word to the chip * @mtd: MTD device structure * @word: data word to write * * Default write function for 16bit buswith without * endianess conversion */static void nand_write_word(struct mtd_info *mtd, u16 word){ struct nand_chip *this = mtd->priv; writew(word, this->IO_ADDR_W);}/** * nand_select_chip - [DEFAULT] control CE line * @mtd: MTD device structure * @chip: chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */static void nand_select_chip(struct mtd_info *mtd, int chip){ struct nand_chip *this = mtd->priv; switch(chip) { case -1: this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; case 0: this->hwcontrol(mtd, NAND_CTL_SETNCE); break; default: BUG(); }}/** * nand_write_buf - [DEFAULT] write buffer to chip * @mtd: MTD device structure * @buf: data buffer * @len: number of bytes to write * * Default write function for 8bit buswith */static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; for (i=0; i<len; i++) writeb(buf[i], this->IO_ADDR_W);}/** * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read * * Default read function for 8bit buswith */static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; for (i=0; i<len; i++) buf[i] = readb(this->IO_ADDR_R);}/** * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare * * Default verify function for 8bit buswith */static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; for (i=0; i<len; i++) if (buf[i] != readb(this->IO_ADDR_R)) return -EFAULT; return 0;}/** * nand_write_buf16 - [DEFAULT] write buffer to chip * @mtd: MTD device structure * @buf: data buffer * @len: number of bytes to write * * Default write function for 16bit buswith */static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; for (i=0; i<len; i++) writew(p[i], this->IO_ADDR_W); }/** * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read * * Default read function for 16bit buswith */static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; for (i=0; i<len; i++) p[i] = readw(this->IO_ADDR_R);}/** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare * * Default verify function for 16bit buswith */static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len){ int i; struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; for (i=0; i<len; i++) if (p[i] != readw(this->IO_ADDR_R)) return -EFAULT; return 0;}/** * nand_block_bad - [DEFAULT] Read bad block marker from the chip * @mtd: MTD device structure * @ofs: offset from device start * @getchip: 0, if the chip is already selected * * Check, if the block is bad. */static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip){ int page, chipnr, res = 0; struct nand_chip *this = mtd->priv; u16 bad; if (getchip) { page = (int)(ofs >> this->page_shift); chipnr = (int)(ofs >> this->chip_shift); /* Grab the lock and see if the device is available */ nand_get_device (this, mtd, FL_READING); /* Select the NAND device */ this->select_chip(mtd, chipnr); } else page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); bad = cpu_to_le16(this->read_word(mtd)); if (this->badblockpos & 0x1) bad >>= 1; if ((bad & 0xFF) != 0xff) res = 1; } else { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); if (this->read_byte(mtd) != 0xff) res = 1; } 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; if (this->bbt) 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -