?? nand_base.c
字號:
/* * drivers/mtd/nand.c * * Overview: * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. * Basic support for AG-AND chips is provided. * * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob * * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes * pointed this out, as he marked an auto increment capable chip * as NOAUTOINCR in the board driver. * Make reads over block boundaries work too * * 04-14-2004 tglx: first working version for 2k page size chips * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared * among multiple independend devices. Suggestions and initial patch * from Ben Dooks <ben-mtd@fluff.org> * * Credits: * David Woodhouse for adding multichip support * * Aleph One Ltd. and Toby Churchill Ltd. for supporting the * rework for 2K page size chips * * TODO: * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW * if we have HW ecc support. * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * *//* XXX U-BOOT XXX */#if 0#include <linux/delay.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/compatmac.h>#include <linux/interrupt.h>#include <linux/bitops.h>#include <asm/io.h>#ifdef CONFIG_MTD_PARTITIONS#include <linux/mtd/partitions.h>#endif#endif#include <common.h>#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)#include <malloc.h>#include <watchdog.h>#include <linux/mtd/compat.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <asm/io.h>#include <asm/errno.h>#ifdef CONFIG_JFFS2_NAND#include <jffs2/jffs2.h>#endif/* 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);/* XXX U-BOOT XXX */#if 0static 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);#endifstatic 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)#endifstatic void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);/** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device *//* XXX U-BOOT XXX */#if 0static void nand_release_device (struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; /* De-select the NAND device */ this->select_chip(mtd, -1); /* Do we have a hardware controller ? */ if (this->controller) { spin_lock(&this->controller->lock); this->controller->active = NULL; spin_unlock(&this->controller->lock); } /* Release the chip */ spin_lock (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock (&this->chip_lock);}#elsestatic void nand_release_device (struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; this->select_chip(mtd, -1); /* De-select the NAND device */}#endif/** * 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) cpu_to_le16(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(le16_to_cpu((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; page = (int)(ofs >> this->page_shift) & this->pagemask; if (getchip) { 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); } if (this->options & NAND_BUSWIDTH_16) { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page); 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); 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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -