blob: 21fce2bce4b2499172edd0990613af387d4c4ad8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/mtd/nand.c
3 *
4 * Overview:
5 * This is the generic MTD driver for NAND flash devices. It should be
6 * capable of working with almost all NAND chips currently available.
7 * Basic support for AG-AND chips is provided.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Additional technical information is available on
10 * http://www.linux-mtd.infradead.org/tech/nand.html
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000011 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020013 * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020015 * Credits:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000016 * David Woodhouse for adding multichip support
17 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
19 * rework for 2K page size chips
20 *
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020021 * TODO:
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * Enable cached programming for 2k page size chips
23 * Check, if mtd->ecctype should be set to MTD_ECC_HW
24 * if we have HW ecc support.
25 * The AG-AND chips have nice features for speed improvement,
26 * which are not supported yet. Read / program 4 pages in one go.
27 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License version 2 as
30 * published by the Free Software Foundation.
31 *
32 */
33
David Woodhouse552d9202006-05-14 01:20:46 +010034#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/delay.h>
36#include <linux/errno.h>
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +020037#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/sched.h>
39#include <linux/slab.h>
40#include <linux/types.h>
41#include <linux/mtd/mtd.h>
42#include <linux/mtd/nand.h>
43#include <linux/mtd/nand_ecc.h>
44#include <linux/mtd/compatmac.h>
45#include <linux/interrupt.h>
46#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080047#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/io.h>
49
50#ifdef CONFIG_MTD_PARTITIONS
51#include <linux/mtd/partitions.h>
52#endif
53
54/* Define default oob placement schemes for large and small page devices */
55static struct nand_oobinfo nand_oob_8 = {
56 .useecc = MTD_NANDECC_AUTOPLACE,
57 .eccbytes = 3,
58 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +010059 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070060};
61
62static struct nand_oobinfo nand_oob_16 = {
63 .useecc = MTD_NANDECC_AUTOPLACE,
64 .eccbytes = 6,
65 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +010066 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070067};
68
69static struct nand_oobinfo nand_oob_64 = {
70 .useecc = MTD_NANDECC_AUTOPLACE,
71 .eccbytes = 24,
72 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +010073 40, 41, 42, 43, 44, 45, 46, 47,
74 48, 49, 50, 51, 52, 53, 54, 55,
75 56, 57, 58, 59, 60, 61, 62, 63},
76 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79/* This is used for padding purposes in nand_write_oob */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020080static uint8_t ffchars[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
82 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
83 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
84 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
85 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89};
90
91/*
92 * NAND low-level MTD interface functions
93 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020094static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
95static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
96static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020098static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020099 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200100static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200101 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200102static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200103 size_t *retlen, const uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200104static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200105 size_t *retlen, const uint8_t *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100106static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
107static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109/* Some internal functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200110static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200111 int page, uint8_t * oob_buf,
David Woodhousee0c7d762006-05-13 18:07:53 +0100112 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200114static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200115 int page, int numpages, uint8_t *oob_buf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200116 struct nand_oobinfo *oobsel, int chipnr,
117 int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#else
119#define nand_verify_pages(...) (0)
120#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000121
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200122static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200123 int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Thomas Gleixnerd470a972006-05-23 23:48:57 +0200125/*
126 * For devices which display every fart in the system on a seperate LED. Is
127 * compiled away when LED support is disabled.
128 */
129DEFINE_LED_TRIGGER(nand_led_trigger);
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131/**
132 * nand_release_device - [GENERIC] release chip
133 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000134 *
135 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100137static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200139 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* De-select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200142 chip->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100143
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200144 /* Release the controller and the chip */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200145 spin_lock(&chip->controller->lock);
146 chip->controller->active = NULL;
147 chip->state = FL_READY;
148 wake_up(&chip->controller->wq);
149 spin_unlock(&chip->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150}
151
152/**
153 * nand_read_byte - [DEFAULT] read one byte from the chip
154 * @mtd: MTD device structure
155 *
156 * Default read function for 8bit buswith
157 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200158static uint8_t nand_read_byte(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200160 struct nand_chip *chip = mtd->priv;
161 return readb(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
163
164/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
166 * @mtd: MTD device structure
167 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000168 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 * endianess conversion
170 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200171static uint8_t nand_read_byte16(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200173 struct nand_chip *chip = mtd->priv;
174 return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 * nand_read_word - [DEFAULT] read one word from the chip
179 * @mtd: MTD device structure
180 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000181 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * endianess conversion
183 */
184static u16 nand_read_word(struct mtd_info *mtd)
185{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200186 struct nand_chip *chip = mtd->priv;
187 return readw(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
190/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 * nand_select_chip - [DEFAULT] control CE line
192 * @mtd: MTD device structure
193 * @chip: chipnumber to select, -1 for deselect
194 *
195 * Default select function for 1 chip devices.
196 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200197static void nand_select_chip(struct mtd_info *mtd, int chipnr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200199 struct nand_chip *chip = mtd->priv;
200
201 switch (chipnr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 case -1:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200203 chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 break;
205 case 0:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200206 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
207 NAND_NCE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 break;
209
210 default:
211 BUG();
212 }
213}
214
215/**
216 * nand_write_buf - [DEFAULT] write buffer to chip
217 * @mtd: MTD device structure
218 * @buf: data buffer
219 * @len: number of bytes to write
220 *
221 * Default write function for 8bit buswith
222 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200223static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200226 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
David Woodhousee0c7d762006-05-13 18:07:53 +0100228 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200229 writeb(buf[i], chip->IO_ADDR_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000233 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 * @mtd: MTD device structure
235 * @buf: buffer to store date
236 * @len: number of bytes to read
237 *
238 * Default read function for 8bit buswith
239 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200240static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200243 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
David Woodhousee0c7d762006-05-13 18:07:53 +0100245 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200246 buf[i] = readb(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000250 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 * @mtd: MTD device structure
252 * @buf: buffer containing the data to compare
253 * @len: number of bytes to compare
254 *
255 * Default verify function for 8bit buswith
256 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200257static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200260 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Woodhousee0c7d762006-05-13 18:07:53 +0100262 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200263 if (buf[i] != readb(chip->IO_ADDR_R))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return -EFAULT;
265
266 return 0;
267}
268
269/**
270 * nand_write_buf16 - [DEFAULT] write buffer to chip
271 * @mtd: MTD device structure
272 * @buf: data buffer
273 * @len: number of bytes to write
274 *
275 * Default write function for 16bit buswith
276 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200277static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
279 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200280 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 u16 *p = (u16 *) buf;
282 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000283
David Woodhousee0c7d762006-05-13 18:07:53 +0100284 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200285 writew(p[i], chip->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287}
288
289/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000290 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 * @mtd: MTD device structure
292 * @buf: buffer to store date
293 * @len: number of bytes to read
294 *
295 * Default read function for 16bit buswith
296 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200297static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200300 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 u16 *p = (u16 *) buf;
302 len >>= 1;
303
David Woodhousee0c7d762006-05-13 18:07:53 +0100304 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200305 p[i] = readw(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
308/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000309 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 * @mtd: MTD device structure
311 * @buf: buffer containing the data to compare
312 * @len: number of bytes to compare
313 *
314 * Default verify function for 16bit buswith
315 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200316static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200319 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 u16 *p = (u16 *) buf;
321 len >>= 1;
322
David Woodhousee0c7d762006-05-13 18:07:53 +0100323 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200324 if (p[i] != readw(chip->IO_ADDR_R))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return -EFAULT;
326
327 return 0;
328}
329
330/**
331 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
332 * @mtd: MTD device structure
333 * @ofs: offset from device start
334 * @getchip: 0, if the chip is already selected
335 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000336 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 */
338static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
339{
340 int page, chipnr, res = 0;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200341 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 u16 bad;
343
344 if (getchip) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200345 page = (int)(ofs >> chip->page_shift);
346 chipnr = (int)(ofs >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200348 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200351 chip->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000352 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100353 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200355 if (chip->options & NAND_BUSWIDTH_16) {
356 chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
357 page & chip->pagemask);
358 bad = cpu_to_le16(chip->read_word(mtd));
359 if (chip->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000360 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if ((bad & 0xFF) != 0xff)
362 res = 1;
363 } else {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200364 chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
365 page & chip->pagemask);
366 if (chip->read_byte(mtd) != 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 res = 1;
368 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000369
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200370 if (getchip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return res;
374}
375
376/**
377 * nand_default_block_markbad - [DEFAULT] mark a block bad
378 * @mtd: MTD device structure
379 * @ofs: offset from device start
380 *
381 * This is the default implementation, which can be overridden by
382 * a hardware specific driver.
383*/
384static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
385{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200386 struct nand_chip *chip = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200387 uint8_t buf[2] = { 0, 0 };
David Woodhousee0c7d762006-05-13 18:07:53 +0100388 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* Get block number */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200392 block = ((int)ofs) >> chip->bbt_erase_shift;
393 if (chip->bbt)
394 chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
396 /* Do we have a flash based bad block table ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200397 if (chip->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100398 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* We write two bytes, so we dont have to mess with 16 bit access */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200401 ofs += mtd->oobsize + (chip->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100402 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000405/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 * nand_check_wp - [GENERIC] check if the chip is write protected
407 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000408 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000410 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100412static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200414 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 /* Check the WP bit */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200416 chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
417 return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
420/**
421 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
422 * @mtd: MTD device structure
423 * @ofs: offset from device start
424 * @getchip: 0, if the chip is already selected
425 * @allowbbt: 1, if its allowed to access the bbt area
426 *
427 * Check, if the block is bad. Either by reading the bad block table or
428 * calling of the scan function.
429 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200430static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
431 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200433 struct nand_chip *chip = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000434
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200435 if (!chip->bbt)
436 return chip->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100439 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000442/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000443 * Wait for the ready pin, after a command
444 * The timeout is catched later.
445 */
446static void nand_wait_ready(struct mtd_info *mtd)
447{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200448 struct nand_chip *chip = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100449 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000450
Richard Purdie8fe833c2006-03-31 02:31:14 -0800451 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000452 /* wait until command is processed or timeout occures */
453 do {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200454 if (chip->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800455 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700456 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000457 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800458 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461/**
462 * nand_command - [DEFAULT] Send command to NAND device
463 * @mtd: MTD device structure
464 * @command: the command to be sent
465 * @column: the column address for this command, -1 if none
466 * @page_addr: the page address for this command, -1 if none
467 *
468 * Send command to NAND device. This function is used for small page
469 * devices (256/512 Bytes per page)
470 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200471static void nand_command(struct mtd_info *mtd, unsigned int command,
472 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200474 register struct nand_chip *chip = mtd->priv;
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200475 int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 /*
478 * Write out the command to the device.
479 */
480 if (command == NAND_CMD_SEQIN) {
481 int readcmd;
482
Joern Engel28318772006-05-22 23:18:05 +0200483 if (column >= mtd->writesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 /* OOB area */
Joern Engel28318772006-05-22 23:18:05 +0200485 column -= mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 readcmd = NAND_CMD_READOOB;
487 } else if (column < 256) {
488 /* First 256 bytes --> READ0 */
489 readcmd = NAND_CMD_READ0;
490 } else {
491 column -= 256;
492 readcmd = NAND_CMD_READ1;
493 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200494 chip->cmd_ctrl(mtd, readcmd, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200495 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200497 chip->cmd_ctrl(mtd, command, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200499 /*
500 * Address cycle, when necessary
501 */
502 ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
503 /* Serially input address */
504 if (column != -1) {
505 /* Adjust columns for 16 bit buswidth */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200506 if (chip->options & NAND_BUSWIDTH_16)
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200507 column >>= 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200508 chip->cmd_ctrl(mtd, column, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200509 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200511 if (page_addr != -1) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200512 chip->cmd_ctrl(mtd, page_addr, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200513 ctrl &= ~NAND_CTRL_CHANGE;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200514 chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200515 /* One more address cycle for devices > 32MiB */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200516 if (chip->chipsize > (32 << 20))
517 chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200518 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200519 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000520
521 /*
522 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100524 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 case NAND_CMD_PAGEPROG:
528 case NAND_CMD_ERASE1:
529 case NAND_CMD_ERASE2:
530 case NAND_CMD_SEQIN:
531 case NAND_CMD_STATUS:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200532 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return;
534
535 case NAND_CMD_RESET:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200536 if (chip->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 break;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200538 udelay(chip->chip_delay);
539 chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200540 NAND_CTRL_CLE | NAND_CTRL_CHANGE);
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200541 chip->cmd_ctrl(mtd,
542 NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200543 while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return;
545
David Woodhousee0c7d762006-05-13 18:07:53 +0100546 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000548 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 * If we don't have access to the busy pin, we apply the given
550 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100551 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200552 if (!chip->dev_ready) {
553 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* Apply this short delay always to ensure that we do wait tWB in
558 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100559 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000560
561 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
564/**
565 * nand_command_lp - [DEFAULT] Send command to NAND large page device
566 * @mtd: MTD device structure
567 * @command: the command to be sent
568 * @column: the column address for this command, -1 if none
569 * @page_addr: the page address for this command, -1 if none
570 *
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200571 * Send command to NAND device. This is the version for the new large page
572 * devices We dont have the separate regions as we have in the small page
573 * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 *
575 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200576static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
577 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200579 register struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 /* Emulate NAND_CMD_READOOB */
582 if (command == NAND_CMD_READOOB) {
Joern Engel28318772006-05-22 23:18:05 +0200583 column += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 command = NAND_CMD_READ0;
585 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000586
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200587 /* Command latch cycle */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200588 chip->cmd_ctrl(mtd, command & 0xff,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200589 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 if (column != -1 || page_addr != -1) {
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200592 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 /* Serially input address */
595 if (column != -1) {
596 /* Adjust columns for 16 bit buswidth */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200597 if (chip->options & NAND_BUSWIDTH_16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 column >>= 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200599 chip->cmd_ctrl(mtd, column, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200600 ctrl &= ~NAND_CTRL_CHANGE;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200601 chip->cmd_ctrl(mtd, column >> 8, ctrl);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (page_addr != -1) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200604 chip->cmd_ctrl(mtd, page_addr, ctrl);
605 chip->cmd_ctrl(mtd, page_addr >> 8,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200606 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /* One more address cycle for devices > 128MiB */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200608 if (chip->chipsize > (128 << 20))
609 chip->cmd_ctrl(mtd, page_addr >> 16,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200610 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200613 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000614
615 /*
616 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000617 * status, sequential in, and deplete1 need no delay
618 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 case NAND_CMD_CACHEDPROG:
622 case NAND_CMD_PAGEPROG:
623 case NAND_CMD_ERASE1:
624 case NAND_CMD_ERASE2:
625 case NAND_CMD_SEQIN:
626 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000627 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return;
629
David Woodhousee0c7d762006-05-13 18:07:53 +0100630 /*
631 * read error status commands require only a short delay
632 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000633 case NAND_CMD_STATUS_ERROR:
634 case NAND_CMD_STATUS_ERROR0:
635 case NAND_CMD_STATUS_ERROR1:
636 case NAND_CMD_STATUS_ERROR2:
637 case NAND_CMD_STATUS_ERROR3:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200638 udelay(chip->chip_delay);
David A. Marlin30f464b2005-01-17 18:35:25 +0000639 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 case NAND_CMD_RESET:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200642 if (chip->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 break;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200644 udelay(chip->chip_delay);
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200645 chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
646 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
647 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
648 NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200649 while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return;
651
652 case NAND_CMD_READ0:
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200653 chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
654 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
655 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
656 NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000657
David Woodhousee0c7d762006-05-13 18:07:53 +0100658 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000660 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 * If we don't have access to the busy pin, we apply the given
662 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100663 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200664 if (!chip->dev_ready) {
665 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /* Apply this short delay always to ensure that we do wait tWB in
671 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100672 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000673
674 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
677/**
678 * nand_get_device - [GENERIC] Get chip for selected access
679 * @this: the nand chip descriptor
680 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000681 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 *
683 * Get the device and lock it for exclusive access
684 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200685static int
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200686nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200688 spinlock_t *lock = &chip->controller->lock;
689 wait_queue_head_t *wq = &chip->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100690 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100691 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100692 spin_lock(lock);
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200695 /* Hardware controller shared among independend devices */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200696 if (!chip->controller->active)
697 chip->controller->active = chip;
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200698
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200699 if (chip->controller->active == chip && chip->state == FL_READY) {
700 chip->state = new_state;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100701 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100702 return 0;
703 }
704 if (new_state == FL_PM_SUSPENDED) {
705 spin_unlock(lock);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200706 return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100707 }
708 set_current_state(TASK_UNINTERRUPTIBLE);
709 add_wait_queue(wq, &wait);
710 spin_unlock(lock);
711 schedule();
712 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 goto retry;
714}
715
716/**
717 * nand_wait - [DEFAULT] wait until the command is done
718 * @mtd: MTD device structure
719 * @this: NAND chip structure
720 * @state: state to select the max. timeout value
721 *
722 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000723 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 * general NAND and SmartMedia specs
725 *
726*/
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200727static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
729
David Woodhousee0c7d762006-05-13 18:07:53 +0100730 unsigned long timeo = jiffies;
731 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100734 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100736 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Richard Purdie8fe833c2006-03-31 02:31:14 -0800738 led_trigger_event(nand_led_trigger, LED_FULL);
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 /* Apply this short delay always to ensure that we do wait tWB in
741 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100742 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200744 if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
745 chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000746 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200747 chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000749 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* Check, if we were interrupted */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200751 if (chip->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200754 if (chip->dev_ready) {
755 if (chip->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000756 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 } else {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200758 if (chip->read_byte(mtd) & NAND_STATUS_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 break;
760 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000761 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800763 led_trigger_event(nand_led_trigger, LED_OFF);
764
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200765 status = (int)chip->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return status;
767}
768
769/**
770 * nand_write_page - [GENERIC] write one page
771 * @mtd: MTD device structure
772 * @this: NAND chip structure
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200773 * @page: startpage inside the chip, must be called with (page & chip->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 * @oob_buf: out of band data buffer
775 * @oobsel: out of band selecttion structre
776 * @cached: 1 = enable cached programming if supported by chip
777 *
778 * Nand_page_program function is used for write and writev !
779 * This function will always program a full page of data
780 * If you call it with a non page aligned buffer, you're lost :)
781 *
782 * Cached programming is not supported yet.
783 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200784static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, int page,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200785 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
David Woodhousee0c7d762006-05-13 18:07:53 +0100787 int i, status;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200788 uint8_t ecc_code[32];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200789 int eccmode = oobsel->useecc ? chip->ecc.mode : NAND_ECC_NONE;
David Woodhousee0c7d762006-05-13 18:07:53 +0100790 int *oob_config = oobsel->eccpos;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200791 int datidx = 0, eccidx = 0, eccsteps = chip->ecc.steps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100792 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 /* FIXME: Enable cached programming */
795 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 /* Send command to begin auto page programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200798 chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 /* Write out complete page of data, take care of eccmode */
801 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100802 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100804 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200805 chip->write_buf(mtd, chip->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000807
David Woodhousee0c7d762006-05-13 18:07:53 +0100808 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 case NAND_ECC_SOFT:
810 for (; eccsteps; eccsteps--) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200811 chip->ecc.calculate(mtd, &chip->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 for (i = 0; i < 3; i++, eccidx++)
813 oob_buf[oob_config[eccidx]] = ecc_code[i];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200814 datidx += chip->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200816 chip->write_buf(mtd, chip->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818 default:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200819 eccbytes = chip->ecc.bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 for (; eccsteps; eccsteps--) {
821 /* enable hardware ecc logic for write */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200822 chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
823 chip->write_buf(mtd, &chip->data_poi[datidx], chip->ecc.size);
824 chip->ecc.calculate(mtd, &chip->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 for (i = 0; i < eccbytes; i++, eccidx++)
826 oob_buf[oob_config[eccidx]] = ecc_code[i];
827 /* If the hardware ecc provides syndromes then
828 * the ecc code must be written immidiately after
829 * the data bytes (words) */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200830 if (chip->options & NAND_HWECC_SYNDROME)
831 chip->write_buf(mtd, ecc_code, eccbytes);
832 datidx += chip->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834 break;
835 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* Write out OOB data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200838 if (chip->options & NAND_HWECC_SYNDROME)
839 chip->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000840 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200841 chip->write_buf(mtd, oob_buf, mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 /* Send command to actually program the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200844 chip->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 if (!cached) {
847 /* call wait ready function */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200848 status = chip->waitfunc(mtd, chip, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000849
850 /* See if operation failed and additional status checks are available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200851 if ((status & NAND_STATUS_FAIL) && (chip->errstat)) {
852 status = chip->errstat(mtd, chip, FL_WRITING, status, page);
David A. Marlin068e3c02005-01-24 03:07:46 +0000853 }
854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000856 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100857 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return -EIO;
859 }
860 } else {
861 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100862 /* wait until cache is ready */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200863 // status = chip->waitfunc (mtd, this, FL_CACHEDRPG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000865 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
868#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
869/**
870 * nand_verify_pages - [GENERIC] verify the chip contents after a write
871 * @mtd: MTD device structure
872 * @this: NAND chip structure
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200873 * @page: startpage inside the chip, must be called with (page & chip->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 * @numpages: number of pages to verify
875 * @oob_buf: out of band data buffer
876 * @oobsel: out of band selecttion structre
877 * @chipnr: number of the current chip
878 * @oobmode: 1 = full buffer verify, 0 = ecc only
879 *
880 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000881 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000883 * byte by byte basis. It is possible that the page was not completely erased
884 * or the page is becoming unusable due to wear. The read with ECC would catch
885 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 * it early in the page write stage. Better to write no data than invalid data.
887 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200888static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip, int page, int numpages,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200889 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
David Woodhousee0c7d762006-05-13 18:07:53 +0100891 int i, j, datidx = 0, oobofs = 0, res = -EIO;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200892 int eccsteps = chip->eccsteps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100893 int hweccbytes;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200894 uint8_t oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200896 hweccbytes = (chip->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
898 /* Send command to read back the first page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200899 chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
David Woodhousee0c7d762006-05-13 18:07:53 +0100901 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 for (j = 0; j < eccsteps; j++) {
903 /* Loop through and verify the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200904 if (chip->verify_buf(mtd, &chip->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100905 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 goto out;
907 }
908 datidx += mtd->eccsize;
909 /* Have we a hw generator layout ? */
910 if (!hweccbytes)
911 continue;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200912 if (chip->verify_buf(mtd, &chip->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100913 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 goto out;
915 }
916 oobofs += hweccbytes;
917 }
918
919 /* check, if we must compare all data or if we just have to
920 * compare the ecc bytes
921 */
922 if (oobmode) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200923 if (chip->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100924 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 goto out;
926 }
927 } else {
928 /* Read always, else autoincrement fails */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200929 chip->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
932 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 for (i = 0; i < ecccnt; i++) {
935 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +0100936 if (oobdata[idx] != oob_buf[oobofs + idx]) {
937 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
938 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 goto out;
940 }
941 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 oobofs += mtd->oobsize - hweccbytes * eccsteps;
945 page++;
946 numpages--;
947
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000948 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 * Do this before the AUTOINCR check, so no problems
950 * arise if a chip which does auto increment
951 * is marked as NOAUTOINCR by the board driver.
952 * Do this also before returning, so the chip is
953 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +0100954 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200955 if (!chip->dev_ready)
956 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 else
Thomas Gleixner3b887752005-02-22 21:56:49 +0000958 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 /* All done, return happy */
961 if (!numpages)
962 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000963
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000964 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if (!NAND_CANAUTOINCR(this))
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200966 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000968 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 * Terminate the read command. We come here in case of an error
970 * So we must issue a reset command.
971 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100972 out:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200973 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return res;
975}
976#endif
977
978/**
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +0200979 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
980 * @mtd: mtd info structure
981 * @chip: nand chip info structure
982 * @buf: buffer to store read data
David A. Marlin068e3c02005-01-24 03:07:46 +0000983 */
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +0200984static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
985 uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +0200987 int i, eccsize = chip->ecc.size;
988 int eccbytes = chip->ecc.bytes;
989 int eccsteps = chip->ecc.steps;
990 uint8_t *p = buf;
991 uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
992 uint8_t *ecc_code = ecc_calc + mtd->oobsize;
993 int *eccpos = chip->autooob->eccpos;
994
995 chip->read_buf(mtd, buf, mtd->writesize);
996 chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);
997
998 if (chip->ecc.mode == NAND_ECC_NONE)
999 return 0;
1000
1001 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
1002 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1003
1004 for (i = 0; i < chip->ecc.total; i++)
1005 ecc_code[i] = chip->oob_buf[eccpos[i]];
1006
1007 eccsteps = chip->ecc.steps;
1008 p = buf;
1009
1010 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1011 int stat;
1012
1013 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
1014 if (stat == -1)
1015 mtd->ecc_stats.failed++;
1016 else
1017 mtd->ecc_stats.corrected += stat;
1018 }
1019 return 0;
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001020}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022/**
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001023 * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
1024 * @mtd: mtd info structure
1025 * @chip: nand chip info structure
1026 * @buf: buffer to store read data
1027 *
1028 * Not for syndrome calculating ecc controllers which need a special oob layout
1029 */
1030static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
1031 uint8_t *buf)
1032{
1033 int i, eccsize = chip->ecc.size;
1034 int eccbytes = chip->ecc.bytes;
1035 int eccsteps = chip->ecc.steps;
1036 uint8_t *p = buf;
1037 uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
1038 uint8_t *ecc_code = ecc_calc + mtd->oobsize;
1039 int *eccpos = chip->autooob->eccpos;
1040
1041 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1042 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1043 chip->read_buf(mtd, p, eccsize);
1044 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1045 }
1046 chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);
1047
1048 for (i = 0; i < chip->ecc.total; i++)
1049 ecc_code[i] = chip->oob_buf[eccpos[i]];
1050
1051 eccsteps = chip->ecc.steps;
1052 p = buf;
1053
1054 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1055 int stat;
1056
1057 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
1058 if (stat == -1)
1059 mtd->ecc_stats.failed++;
1060 else
1061 mtd->ecc_stats.corrected += stat;
1062 }
1063 return 0;
1064}
1065
1066/**
1067 * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
1068 * @mtd: mtd info structure
1069 * @chip: nand chip info structure
1070 * @buf: buffer to store read data
1071 *
1072 * The hw generator calculates the error syndrome automatically. Therefor
1073 * we need a special oob layout and .
1074 */
1075static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
1076 uint8_t *buf)
1077{
1078 int i, eccsize = chip->ecc.size;
1079 int eccbytes = chip->ecc.bytes;
1080 int eccsteps = chip->ecc.steps;
1081 uint8_t *p = buf;
1082 uint8_t *oob = chip->oob_buf;
1083
1084 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1085 int stat;
1086
1087 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1088 chip->read_buf(mtd, p, eccsize);
1089
1090 if (chip->ecc.prepad) {
1091 chip->read_buf(mtd, oob, chip->ecc.prepad);
1092 oob += chip->ecc.prepad;
1093 }
1094
1095 chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
1096 chip->read_buf(mtd, oob, eccbytes);
1097 stat = chip->ecc.correct(mtd, p, oob, NULL);
1098
1099 if (stat == -1)
1100 mtd->ecc_stats.failed++;
1101 else
1102 mtd->ecc_stats.corrected += stat;
1103
1104 oob += eccbytes;
1105
1106 if (chip->ecc.postpad) {
1107 chip->read_buf(mtd, oob, chip->ecc.postpad);
1108 oob += chip->ecc.postpad;
1109 }
1110 }
1111
1112 /* Calculate remaining oob bytes */
1113 i = oob - chip->oob_buf;
1114 if (i)
1115 chip->read_buf(mtd, oob, i);
1116
1117 return 0;
1118}
1119
1120/**
1121 * nand_do_read - [Internal] Read data with ECC
1122 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001123 * @mtd: MTD device structure
1124 * @from: offset to read from
1125 * @len: number of bytes to read
1126 * @retlen: pointer to variable to store the number of read bytes
1127 * @buf: the databuffer to put data
David A. Marlin068e3c02005-01-24 03:07:46 +00001128 *
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001129 * Internal function. Called with chip held.
David A. Marlin068e3c02005-01-24 03:07:46 +00001130 */
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001131int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
1132 size_t *retlen, uint8_t *buf)
David A. Marlin068e3c02005-01-24 03:07:46 +00001133{
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001134 int chipnr, page, realpage, col, bytes, aligned;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001135 struct nand_chip *chip = mtd->priv;
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001136 struct mtd_ecc_stats stats;
1137 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1138 int sndcmd = 1;
1139 int ret = 0;
1140 uint32_t readlen = len;
1141 uint8_t *bufpoi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001143 stats = mtd->ecc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001145 chipnr = (int)(from >> chip->chip_shift);
1146 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001148 realpage = (int)(from >> chip->page_shift);
1149 page = realpage & chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001151 col = (int)(from & (mtd->writesize - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001153 while(1) {
1154 bytes = min(mtd->writesize - col, readlen);
1155 aligned = (bytes == mtd->writesize);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001156
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001157 /* Is the current page in the buffer ? */
1158 if (realpage != chip->pagebuf) {
1159 bufpoi = aligned ? buf : chip->data_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001161 if (likely(sndcmd)) {
1162 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
1163 sndcmd = 0;
1164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001166 /* Now read the page into the buffer */
1167 ret = chip->ecc.read_page(mtd, chip, bufpoi);
1168 if (ret < 0)
David Woodhousee0c7d762006-05-13 18:07:53 +01001169 break;
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001170
1171 /* Transfer not aligned data */
1172 if (!aligned) {
1173 chip->pagebuf = realpage;
1174 memcpy(buf, chip->data_buf + col, bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001176
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001177 if (!(chip->options & NAND_NO_READRDY)) {
1178 /*
1179 * Apply delay or wait for ready/busy pin. Do
1180 * this before the AUTOINCR check, so no
1181 * problems arise if a chip which does auto
1182 * increment is marked as NOAUTOINCR by the
1183 * board driver.
1184 */
1185 if (!chip->dev_ready)
1186 udelay(chip->chip_delay);
1187 else
1188 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001190 } else
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001191 memcpy(buf, chip->data_buf + col, bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001193 buf += bytes;
1194 readlen -= bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001195
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001196 if (!readlen)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001197 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 /* For subsequent reads align to page boundary. */
1200 col = 0;
1201 /* Increment page address */
1202 realpage++;
1203
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001204 page = realpage & chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 /* Check, if we cross a chip boundary */
1206 if (!page) {
1207 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001208 chip->select_chip(mtd, -1);
1209 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 }
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001211
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001212 /* Check, if the chip supports auto page increment
1213 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001214 */
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001215 if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001216 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001219 *retlen = len - (size_t) readlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02001221 if (ret)
1222 return ret;
1223
1224 return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
1225}
1226
1227/**
1228 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
1229 * @mtd: MTD device structure
1230 * @from: offset to read from
1231 * @len: number of bytes to read
1232 * @retlen: pointer to variable to store the number of read bytes
1233 * @buf: the databuffer to put data
1234 *
1235 * Get hold of the chip and call nand_do_read
1236 */
1237static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
1238 size_t *retlen, uint8_t *buf)
1239{
1240 int ret;
1241
1242 *retlen = 0;
1243 /* Do not allow reads past end of device */
1244 if ((from + len) > mtd->size)
1245 return -EINVAL;
1246 if (!len)
1247 return 0;
1248
1249 nand_get_device(mtd->priv, mtd, FL_READING);
1250
1251 ret = nand_do_read(mtd, from, len, retlen, buf);
1252
1253 nand_release_device(mtd);
1254
1255 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256}
1257
1258/**
1259 * nand_read_oob - [MTD Interface] NAND read out-of-band
1260 * @mtd: MTD device structure
1261 * @from: offset to read from
1262 * @len: number of bytes to read
1263 * @retlen: pointer to variable to store the number of read bytes
1264 * @buf: the databuffer to put data
1265 *
1266 * NAND read out-of-band data from the spare area
1267 */
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001268static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
1269 size_t *retlen, uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270{
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001271 int col, page, realpage, chipnr, sndcmd = 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001272 struct nand_chip *chip = mtd->priv;
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001273 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1274 int readlen = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001276 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n",
1277 (unsigned int)from, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279 /* Initialize return length value */
1280 *retlen = 0;
1281
1282 /* Do not allow reads past end of device */
1283 if ((from + len) > mtd->size) {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001284 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1285 "Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 return -EINVAL;
1287 }
1288
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001289 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001291 chipnr = (int)(from >> chip->chip_shift);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001292 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001294 /* Shift to get page */
1295 realpage = (int)(from >> chip->page_shift);
1296 page = realpage & chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001298 /* Mask to get column */
1299 col = from & (mtd->oobsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001301 while(1) {
1302 int bytes = min((int)(mtd->oobsize - col), readlen);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001303
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001304 if (likely(sndcmd)) {
1305 chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page);
1306 sndcmd = 0;
1307 }
1308
1309 chip->read_buf(mtd, buf, bytes);
1310
1311 readlen -= bytes;
1312 if (!readlen)
1313 break;
1314
1315 if (!(chip->options & NAND_NO_READRDY)) {
1316 /*
1317 * Apply delay or wait for ready/busy pin. Do this
1318 * before the AUTOINCR check, so no problems arise if a
1319 * chip which does auto increment is marked as
1320 * NOAUTOINCR by the board driver.
Thomas Gleixner19870da2005-07-15 14:53:51 +01001321 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001322 if (!chip->dev_ready)
1323 udelay(chip->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001324 else
1325 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001327
1328 buf += bytes;
1329 bytes = mtd->oobsize;
1330 col = 0;
1331
1332 /* Increment page address */
1333 realpage++;
1334
1335 page = realpage & chip->pagemask;
1336 /* Check, if we cross a chip boundary */
1337 if (!page) {
1338 chipnr++;
1339 chip->select_chip(mtd, -1);
1340 chip->select_chip(mtd, chipnr);
1341 }
1342
1343 /* Check, if the chip supports auto page increment
1344 * or if we have hit a block boundary.
1345 */
1346 if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
1347 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
1349
1350 /* Deselect and wake up anyone waiting on the device */
1351 nand_release_device(mtd);
1352
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 *retlen = len;
1354 return 0;
1355}
1356
1357/**
1358 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1359 * @mtd: MTD device structure
1360 * @buf: temporary buffer
1361 * @from: offset to read from
1362 * @len: number of bytes to read
1363 * @ooblen: number of oob data bytes to read
1364 *
1365 * Read raw data including oob into buffer
1366 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001367int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
1368 size_t ooblen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001370 struct nand_chip *chip = mtd->priv;
1371 int page = (int)(from >> chip->page_shift);
1372 int chipnr = (int)(from >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 int sndcmd = 1;
1374 int cnt = 0;
Joern Engel28318772006-05-22 23:18:05 +02001375 int pagesize = mtd->writesize + mtd->oobsize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001376 int blockcheck;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 /* Do not allow reads past end of device */
1379 if ((from + len) > mtd->size) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001380 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: "
1381 "Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return -EINVAL;
1383 }
1384
1385 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001386 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001388 chip->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 /* Add requested oob length */
1391 len += ooblen;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001392 blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 while (len) {
1395 if (sndcmd)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001396 chip->cmdfunc(mtd, NAND_CMD_READ0, 0,
1397 page & chip->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001398 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001400 chip->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 len -= pagesize;
1403 cnt += pagesize;
1404 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001405
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001406 if (!chip->dev_ready)
1407 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001409 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001410
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001411 /*
1412 * Check, if the chip supports auto page increment or if we
1413 * cross a block boundary.
1414 */
1415 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 sndcmd = 1;
1417 }
1418
1419 /* Deselect and wake up anyone waiting on the device */
1420 nand_release_device(mtd);
1421 return 0;
1422}
1423
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001424/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001425 * nand_write_raw - [GENERIC] Write raw data including oob
1426 * @mtd: MTD device structure
1427 * @buf: source buffer
1428 * @to: offset to write to
1429 * @len: number of bytes to write
1430 * @buf: source buffer
1431 * @oob: oob buffer
1432 *
1433 * Write raw data including oob
1434 */
1435int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1436 uint8_t *buf, uint8_t *oob)
1437{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001438 struct nand_chip *chip = mtd->priv;
1439 int page = (int)(to >> chip->page_shift);
1440 int chipnr = (int)(to >> chip->chip_shift);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001441 int ret;
1442
1443 *retlen = 0;
1444
1445 /* Do not allow writes past end of device */
1446 if ((to + len) > mtd->size) {
1447 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
1448 "beyond end of device\n");
1449 return -EINVAL;
1450 }
1451
1452 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001453 nand_get_device(chip, mtd, FL_WRITING);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001454
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001455 chip->select_chip(mtd, chipnr);
1456 chip->data_poi = buf;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001457
1458 while (len != *retlen) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001459 ret = nand_write_page(mtd, chip, page, oob, &mtd->oobinfo, 0);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001460 if (ret)
1461 return ret;
1462 page++;
1463 *retlen += mtd->writesize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001464 chip->data_poi += mtd->writesize;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001465 oob += mtd->oobsize;
1466 }
1467
1468 /* Deselect and wake up anyone waiting on the device */
1469 nand_release_device(mtd);
1470 return 0;
1471}
Thomas Gleixner38217202006-05-23 22:33:52 +02001472EXPORT_SYMBOL_GPL(nand_write_raw);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001473
1474/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001475 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 * @mtd: MTD device structure
1477 * @fsbuf: buffer given by fs driver
1478 * @oobsel: out of band selection structre
1479 * @autoplace: 1 = place given buffer into the oob bytes
1480 * @numpages: number of pages to prepare
1481 *
1482 * Return:
1483 * 1. Filesystem buffer available and autoplacement is off,
1484 * return filesystem buffer
1485 * 2. No filesystem buffer or autoplace is off, return internal
1486 * buffer
1487 * 3. Filesystem buffer is given and autoplace selected
1488 * put data from fs buffer into internal buffer and
1489 * retrun internal buffer
1490 *
1491 * Note: The internal buffer is filled with 0xff. This must
1492 * be done only once, when no autoplacement happens
1493 * Autoplacement sets the buffer dirty flag, which
1494 * forces the 0xff fill before using the buffer again.
1495 *
1496*/
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001497static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
David Woodhousee0c7d762006-05-13 18:07:53 +01001498 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001500 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 int i, len, ofs;
1502
1503 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001504 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return fsbuf;
1506
1507 /* Check, if the buffer must be filled with ff again */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001508 if (chip->oobdirty) {
1509 memset(chip->oob_buf, 0xff, mtd->oobsize << (chip->phys_erase_shift - chip->page_shift));
1510 chip->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001511 }
1512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 /* If we have no autoplacement or no fs buffer use the internal one */
1514 if (!autoplace || !fsbuf)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001515 return chip->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 /* Walk through the pages and place the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001518 chip->oobdirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 ofs = 0;
1520 while (numpages--) {
1521 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1522 int to = ofs + oobsel->oobfree[i][0];
1523 int num = oobsel->oobfree[i][1];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001524 memcpy(&chip->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 len += num;
1526 fsbuf += num;
1527 }
1528 ofs += mtd->oobavail;
1529 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001530 return chip->oob_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531}
1532
Joern Engel28318772006-05-22 23:18:05 +02001533#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001536 * nand_write - [MTD Interface] NAND write with ECC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 * @mtd: MTD device structure
1538 * @to: offset to write to
1539 * @len: number of bytes to write
1540 * @retlen: pointer to variable to store the number of written bytes
1541 * @buf: the data to write
1542 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 * NAND write with ECC
1544 */
Thomas Gleixner9223a452006-05-23 17:21:03 +02001545static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1546 size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1549 int autoplace = 0, numpages, totalpages;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001550 struct nand_chip *chip = mtd->priv;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001551 uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001552 int ppblock = (1 << (chip->phys_erase_shift - chip->page_shift));
Thomas Gleixner9223a452006-05-23 17:21:03 +02001553 struct nand_oobinfo *oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Thomas Gleixner9223a452006-05-23 17:21:03 +02001555 DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 /* Initialize retlen, in case of early exit */
1558 *retlen = 0;
1559
1560 /* Do not allow write past end of device */
1561 if ((to + len) > mtd->size) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001562 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 return -EINVAL;
1564 }
1565
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001566 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001567 if (NOTALIGNED(to) || NOTALIGNED(len)) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001568 printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 return -EINVAL;
1570 }
1571
1572 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001573 nand_get_device(chip, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /* Calculate chipnr */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001576 chipnr = (int)(to >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001578 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580 /* Check, if it is write protected */
1581 if (nand_check_wp(mtd))
1582 goto out;
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 /* Autoplace of oob data ? Use the default placement scheme */
1585 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001586 oobsel = chip->autooob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001588 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001589 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1590 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 /* Setup variables and oob buffer */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001593 totalpages = len >> chip->page_shift;
1594 page = (int)(to >> chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001596 if (page <= chip->pagebuf && chip->pagebuf < (page + totalpages))
1597 chip->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 /* Set it relative to chip */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001600 page &= chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 startpage = page;
1602 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001603 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1604 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001605 bufstart = (uint8_t *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 /* Loop until all data is written */
1608 while (written < len) {
1609
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001610 chip->data_poi = (uint8_t *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 /* Write one page. If this is the last page to write
1612 * or the last page in this block, then use the
1613 * real pageprogram command, else select cached programming
1614 * if supported by the chip.
1615 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001616 ret = nand_write_page(mtd, chip, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001618 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* Next oob page */
1622 oob += mtd->oobsize;
1623 /* Update written bytes count */
Joern Engel28318772006-05-22 23:18:05 +02001624 written += mtd->writesize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001625 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* Increment page address */
1629 page++;
1630
1631 /* Have we hit a block boundary ? Then we have to verify and
1632 * if verify is ok, we have to setup the oob buffer for
1633 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001634 */
1635 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 int ofs;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001637 chip->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001638 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1639 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001641 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 *retlen = written;
1645
1646 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1647 if (eccbuf)
1648 eccbuf += (page - startpage) * ofs;
1649 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001650 numpages = min(totalpages, ppblock);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001651 page &= chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001653 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001654 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* Check, if we cross a chip boundary */
1656 if (!page) {
1657 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001658 chip->select_chip(mtd, -1);
1659 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
1661 }
1662 }
1663 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001664 cmp:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001665 chip->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001666 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 if (!ret)
1668 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001669 else
Thomas Gleixner9223a452006-05-23 17:21:03 +02001670 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
David Woodhousee0c7d762006-05-13 18:07:53 +01001672 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Deselect and wake up anyone waiting on the device */
1674 nand_release_device(mtd);
1675
1676 return ret;
1677}
1678
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001679
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680/**
1681 * nand_write_oob - [MTD Interface] NAND write out-of-band
1682 * @mtd: MTD device structure
1683 * @to: offset to write to
1684 * @len: number of bytes to write
1685 * @retlen: pointer to variable to store the number of written bytes
1686 * @buf: the data to write
1687 *
1688 * NAND write out-of-band
1689 */
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001690static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1691 size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
1693 int column, page, status, ret = -EIO, chipnr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001694 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001696 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
1697 (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 /* Initialize return length value */
1700 *retlen = 0;
1701
1702 /* Do not allow write past end of page */
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001703 column = to & (mtd->oobsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 if ((column + len) > mtd->oobsize) {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001705 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1706 "Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 return -EINVAL;
1708 }
1709
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001710 nand_get_device(chip, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001712 chipnr = (int)(to >> chip->chip_shift);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001713 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001715 /* Shift to get page */
1716 page = (int)(to >> chip->page_shift);
1717
1718 /*
1719 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
1720 * of my DiskOnChip 2000 test units) will clear the whole data page too
1721 * if we don't do this. I have no clue why, but I seem to have 'fixed'
1722 * it in the doc2000 driver in August 1999. dwmw2.
1723 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001724 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 /* Check, if it is write protected */
1727 if (nand_check_wp(mtd))
1728 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001731 if (page == chip->pagebuf)
1732 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001734 if (NAND_MUST_PAD(chip)) {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001735 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize,
1736 page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 /* prepad 0xff for partial programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001738 chip->write_buf(mtd, ffchars, column);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 /* write data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001740 chip->write_buf(mtd, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 /* postpad 0xff for partial programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001742 chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 } else {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001744 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column,
1745 page & chip->pagemask);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001746 chip->write_buf(mtd, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
1748 /* Send command to program the OOB data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001749 chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001751 status = chip->waitfunc(mtd, chip, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001754 if (status & NAND_STATUS_FAIL) {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001755 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1756 "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 ret = -EIO;
1758 goto out;
1759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 *retlen = len;
1761
1762#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1763 /* Send command to read back the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001764 chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001766 if (chip->verify_buf(mtd, buf, len)) {
Thomas Gleixner7314e9e2006-05-25 09:51:54 +02001767 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1768 "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ret = -EIO;
1770 goto out;
1771 }
1772#endif
1773 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001774 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 /* Deselect and wake up anyone waiting on the device */
1776 nand_release_device(mtd);
1777
1778 return ret;
1779}
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 * single_erease_cmd - [GENERIC] NAND standard block erase command function
1783 * @mtd: MTD device structure
1784 * @page: the page address of the block which will be erased
1785 *
1786 * Standard erase command for NAND chips
1787 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001788static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001790 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 /* Send commands to erase a block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001792 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1793 chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794}
1795
1796/**
1797 * multi_erease_cmd - [GENERIC] AND specific block erase command function
1798 * @mtd: MTD device structure
1799 * @page: the page address of the block which will be erased
1800 *
1801 * AND multi block erase command function
1802 * Erase 4 consecutive blocks
1803 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001804static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001806 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* Send commands to erase a block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001808 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1809 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1810 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1811 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1812 chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813}
1814
1815/**
1816 * nand_erase - [MTD Interface] erase block(s)
1817 * @mtd: MTD device structure
1818 * @instr: erase instruction
1819 *
1820 * Erase one ore more blocks
1821 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001822static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823{
David Woodhousee0c7d762006-05-13 18:07:53 +01001824 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001826
David A. Marlin30f464b2005-01-17 18:35:25 +00001827#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001829 * nand_erase_nand - [Internal] erase block(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 * @mtd: MTD device structure
1831 * @instr: erase instruction
1832 * @allowbbt: allow erasing the bbt area
1833 *
1834 * Erase one ore more blocks
1835 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001836int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
1837 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838{
1839 int page, len, status, pages_per_block, ret, chipnr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001840 struct nand_chip *chip = mtd->priv;
1841 int rewrite_bbt[NAND_MAX_CHIPS]={0};
1842 unsigned int bbt_masked_page = 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001844 DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
1845 (unsigned int)instr->addr, (unsigned int)instr->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 /* Start address must align on block boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001848 if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001849 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 return -EINVAL;
1851 }
1852
1853 /* Length must align on block boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001854 if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
1855 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1856 "Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 return -EINVAL;
1858 }
1859
1860 /* Do not allow erase past end of device */
1861 if ((instr->len + instr->addr) > mtd->size) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001862 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1863 "Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 return -EINVAL;
1865 }
1866
1867 instr->fail_addr = 0xffffffff;
1868
1869 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001870 nand_get_device(chip, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872 /* Shift to get first page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001873 page = (int)(instr->addr >> chip->page_shift);
1874 chipnr = (int)(instr->addr >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876 /* Calculate pages in each block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001877 pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001880 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 /* Check, if it is write protected */
1883 if (nand_check_wp(mtd)) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001884 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1885 "Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 instr->state = MTD_ERASE_FAILED;
1887 goto erase_exit;
1888 }
1889
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001890 /*
1891 * If BBT requires refresh, set the BBT page mask to see if the BBT
1892 * should be rewritten. Otherwise the mask is set to 0xffffffff which
1893 * can not be matched. This is also done when the bbt is actually
1894 * erased to avoid recusrsive updates
1895 */
1896 if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
1897 bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
David A. Marlin30f464b2005-01-17 18:35:25 +00001898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 /* Loop through the pages */
1900 len = instr->len;
1901
1902 instr->state = MTD_ERASING;
1903
1904 while (len) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001905 /*
1906 * heck if we have a bad block, we do not erase bad blocks !
1907 */
1908 if (nand_block_checkbad(mtd, ((loff_t) page) <<
1909 chip->page_shift, 0, allowbbt)) {
1910 printk(KERN_WARNING "nand_erase: attempt to erase a "
1911 "bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 instr->state = MTD_ERASE_FAILED;
1913 goto erase_exit;
1914 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001915
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001916 /*
1917 * Invalidate the page cache, if we erase the block which
1918 * contains the current cached page
1919 */
1920 if (page <= chip->pagebuf && chip->pagebuf <
1921 (page + pages_per_block))
1922 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001924 chip->erase_cmd(mtd, page & chip->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001925
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001926 status = chip->waitfunc(mtd, chip, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001928 /*
1929 * See if operation failed and additional status checks are
1930 * available
1931 */
1932 if ((status & NAND_STATUS_FAIL) && (chip->errstat))
1933 status = chip->errstat(mtd, chip, FL_ERASING,
1934 status, page);
David A. Marlin068e3c02005-01-24 03:07:46 +00001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001937 if (status & NAND_STATUS_FAIL) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001938 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1939 "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 instr->state = MTD_ERASE_FAILED;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001941 instr->fail_addr = (page << chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 goto erase_exit;
1943 }
David A. Marlin30f464b2005-01-17 18:35:25 +00001944
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001945 /*
1946 * If BBT requires refresh, set the BBT rewrite flag to the
1947 * page being erased
1948 */
1949 if (bbt_masked_page != 0xffffffff &&
1950 (page & BBT_PAGE_MASK) == bbt_masked_page)
1951 rewrite_bbt[chipnr] = (page << chip->page_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 /* Increment page address and decrement length */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001954 len -= (1 << chip->phys_erase_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 page += pages_per_block;
1956
1957 /* Check, if we cross a chip boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001958 if (len && !(page & chip->pagemask)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001960 chip->select_chip(mtd, -1);
1961 chip->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00001962
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001963 /*
1964 * If BBT requires refresh and BBT-PERCHIP, set the BBT
1965 * page mask to see if this BBT should be rewritten
1966 */
1967 if (bbt_masked_page != 0xffffffff &&
1968 (chip->bbt_td->options & NAND_BBT_PERCHIP))
1969 bbt_masked_page = chip->bbt_td->pages[chipnr] &
1970 BBT_PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972 }
1973 instr->state = MTD_ERASE_DONE;
1974
David Woodhousee0c7d762006-05-13 18:07:53 +01001975 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1978 /* Do call back function */
1979 if (!ret)
1980 mtd_erase_callback(instr);
1981
1982 /* Deselect and wake up anyone waiting on the device */
1983 nand_release_device(mtd);
1984
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001985 /*
1986 * If BBT requires refresh and erase was successful, rewrite any
1987 * selected bad block tables
1988 */
1989 if (bbt_masked_page == 0xffffffff || ret)
1990 return ret;
1991
1992 for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
1993 if (!rewrite_bbt[chipnr])
1994 continue;
1995 /* update the BBT for chip */
1996 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
1997 "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
1998 chip->bbt_td->pages[chipnr]);
1999 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002000 }
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 /* Return more or less happy */
2003 return ret;
2004}
2005
2006/**
2007 * nand_sync - [MTD Interface] sync
2008 * @mtd: MTD device structure
2009 *
2010 * Sync is actually a wait for chip ready function
2011 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002012static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002014 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
David Woodhousee0c7d762006-05-13 18:07:53 +01002016 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002019 nand_get_device(chip, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002021 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022}
2023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002025 * nand_block_isbad - [MTD Interface] Check if block at offset is bad
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 * @mtd: MTD device structure
2027 * @ofs: offset relative to mtd start
2028 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002029static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
2031 /* Check for invalid offset */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002032 if (offs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002034
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002035 return nand_block_checkbad(mtd, offs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036}
2037
2038/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002039 * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 * @mtd: MTD device structure
2041 * @ofs: offset relative to mtd start
2042 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002043static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002045 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 int ret;
2047
David Woodhousee0c7d762006-05-13 18:07:53 +01002048 if ((ret = nand_block_isbad(mtd, ofs))) {
2049 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (ret > 0)
2051 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002052 return ret;
2053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002055 return chip->block_markbad(mtd, ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056}
2057
2058/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002059 * nand_suspend - [MTD Interface] Suspend the NAND flash
2060 * @mtd: MTD device structure
2061 */
2062static int nand_suspend(struct mtd_info *mtd)
2063{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002064 struct nand_chip *chip = mtd->priv;
Vitaly Wool962034f2005-09-15 14:58:53 +01002065
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002066 return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002067}
2068
2069/**
2070 * nand_resume - [MTD Interface] Resume the NAND flash
2071 * @mtd: MTD device structure
2072 */
2073static void nand_resume(struct mtd_info *mtd)
2074{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002075 struct nand_chip *chip = mtd->priv;
Vitaly Wool962034f2005-09-15 14:58:53 +01002076
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002077 if (chip->state == FL_PM_SUSPENDED)
Vitaly Wool962034f2005-09-15 14:58:53 +01002078 nand_release_device(mtd);
2079 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002080 printk(KERN_ERR "nand_resume() called for a chip which is not "
2081 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002082}
2083
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002084/*
2085 * Free allocated data structures
2086 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002087static void nand_free_kmem(struct nand_chip *chip)
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002088{
2089 /* Buffer allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002090 if (chip->options & NAND_OOBBUF_ALLOC)
2091 kfree(chip->oob_buf);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002092 /* Buffer allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002093 if (chip->options & NAND_DATABUF_ALLOC)
2094 kfree(chip->data_buf);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002095 /* Controller allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002096 if (chip->options & NAND_CONTROLLER_ALLOC)
2097 kfree(chip->controller);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002098}
2099
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002100/*
2101 * Allocate buffers and data structures
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002103static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *chip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104{
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002105 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002107 if (!chip->oob_buf) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002108 len = mtd->oobsize <<
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002109 (chip->phys_erase_shift - chip->page_shift);
2110 chip->oob_buf = kmalloc(len, GFP_KERNEL);
2111 if (!chip->oob_buf)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002112 goto outerr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002113 chip->options |= NAND_OOBBUF_ALLOC;
David Woodhouse552d9202006-05-14 01:20:46 +01002114 }
2115
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002116 if (!chip->data_buf) {
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002117 len = mtd->writesize + mtd->oobsize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002118 chip->data_buf = kmalloc(len, GFP_KERNEL);
2119 if (!chip->data_buf)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002120 goto outerr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002121 chip->options |= NAND_DATABUF_ALLOC;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002124 if (!chip->controller) {
2125 chip->controller = kzalloc(sizeof(struct nand_hw_control),
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002126 GFP_KERNEL);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002127 if (!chip->controller)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002128 goto outerr;
Thomas Gleixner04bbd0e2006-05-25 09:45:29 +02002129
2130 spin_lock_init(&chip->controller->lock);
2131 init_waitqueue_head(&chip->controller->wq);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002132 chip->options |= NAND_CONTROLLER_ALLOC;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002133 }
2134 return 0;
2135
2136 outerr:
2137 printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002138 nand_free_kmem(chip);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002139 return -ENOMEM;
2140}
2141
2142/*
2143 * Set default functions
2144 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002145static void nand_set_defaults(struct nand_chip *chip, int busw)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002146{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 /* check for proper chip_delay setup, set 20us if not */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002148 if (!chip->chip_delay)
2149 chip->chip_delay = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
2151 /* check, if a user supplied command function given */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002152 if (chip->cmdfunc == NULL)
2153 chip->cmdfunc = nand_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155 /* check, if a user supplied wait function given */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002156 if (chip->waitfunc == NULL)
2157 chip->waitfunc = nand_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002159 if (!chip->select_chip)
2160 chip->select_chip = nand_select_chip;
2161 if (!chip->read_byte)
2162 chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2163 if (!chip->read_word)
2164 chip->read_word = nand_read_word;
2165 if (!chip->block_bad)
2166 chip->block_bad = nand_block_bad;
2167 if (!chip->block_markbad)
2168 chip->block_markbad = nand_default_block_markbad;
2169 if (!chip->write_buf)
2170 chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2171 if (!chip->read_buf)
2172 chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2173 if (!chip->verify_buf)
2174 chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2175 if (!chip->scan_bbt)
2176 chip->scan_bbt = nand_default_bbt;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002177}
2178
2179/*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002180 * Get the flash and manufacturer id and lookup if the type is supported
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002181 */
2182static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002183 struct nand_chip *chip,
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002184 int busw, int *maf_id)
2185{
2186 struct nand_flash_dev *type = NULL;
2187 int i, dev_id, maf_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
2189 /* Select the device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002190 chip->select_chip(mtd, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
2192 /* Send the command for reading device ID */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002193 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
2195 /* Read manufacturer and device IDs */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002196 *maf_id = chip->read_byte(mtd);
2197 dev_id = chip->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002199 /* Lookup the flash id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002201 if (dev_id == nand_flash_ids[i].id) {
2202 type = &nand_flash_ids[i];
2203 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002207 if (!type)
2208 return ERR_PTR(-ENODEV);
2209
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002210 chip->chipsize = nand_flash_ids[i].chipsize << 20;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002211
2212 /* Newer devices have all the information in additional id bytes */
2213 if (!nand_flash_ids[i].pagesize) {
2214 int extid;
2215 /* The 3rd id byte contains non relevant data ATM */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002216 extid = chip->read_byte(mtd);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002217 /* The 4th id byte is the important one */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002218 extid = chip->read_byte(mtd);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002219 /* Calc pagesize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002220 mtd->writesize = 1024 << (extid & 0x3);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002221 extid >>= 2;
2222 /* Calc oobsize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002223 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002224 extid >>= 2;
2225 /* Calc blocksize. Blocksize is multiples of 64KiB */
2226 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2227 extid >>= 2;
2228 /* Get buswidth information */
2229 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
2230
2231 } else {
2232 /*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002233 * Old devices have chip data hardcoded in the device id table
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002234 */
2235 mtd->erasesize = nand_flash_ids[i].erasesize;
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002236 mtd->writesize = nand_flash_ids[i].pagesize;
2237 mtd->oobsize = mtd->writesize / 32;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002238 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2239 }
2240
2241 /* Try to identify manufacturer */
2242 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
2243 if (nand_manuf_ids[maf_idx].id == *maf_id)
2244 break;
2245 }
2246
2247 /*
2248 * Check, if buswidth is correct. Hardware drivers should set
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002249 * chip correct !
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002250 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002251 if (busw != (chip->options & NAND_BUSWIDTH_16)) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002252 printk(KERN_INFO "NAND device: Manufacturer ID:"
2253 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2254 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2255 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002256 (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002257 busw ? 16 : 8);
2258 return ERR_PTR(-EINVAL);
2259 }
2260
2261 /* Calculate the address shift from the page size */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002262 chip->page_shift = ffs(mtd->writesize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002263 /* Convert chipsize to number of pages per chip -1. */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002264 chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002265
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002266 chip->bbt_erase_shift = chip->phys_erase_shift =
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002267 ffs(mtd->erasesize) - 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002268 chip->chip_shift = ffs(chip->chipsize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002269
2270 /* Set the bad block position */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002271 chip->badblockpos = mtd->writesize > 512 ?
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002272 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2273
2274 /* Get chip options, preserve non chip based options */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002275 chip->options &= ~NAND_CHIPOPTIONS_MSK;
2276 chip->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002277
2278 /*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002279 * Set chip as a default. Board drivers can override it, if necessary
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002280 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002281 chip->options |= NAND_NO_AUTOINCR;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002282
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002283 /* Check if chip is a not a samsung device. Do not clear the
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002284 * options for chips which are not having an extended id.
2285 */
2286 if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002287 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002288
2289 /* Check for AND chips with 4 page planes */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002290 if (chip->options & NAND_4PAGE_ARRAY)
2291 chip->erase_cmd = multi_erase_cmd;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002292 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002293 chip->erase_cmd = single_erase_cmd;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002294
2295 /* Do not replace user supplied command function ! */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002296 if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
2297 chip->cmdfunc = nand_command_lp;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002298
2299 printk(KERN_INFO "NAND device: Manufacturer ID:"
2300 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2301 nand_manuf_ids[maf_idx].name, type->name);
2302
2303 return type;
2304}
2305
2306/* module_text_address() isn't exported, and it's mostly a pointless
2307 test if this is a module _anyway_ -- they'd have to try _really_ hard
2308 to call us from in-kernel code if the core NAND support is modular. */
2309#ifdef MODULE
2310#define caller_is_module() (1)
2311#else
2312#define caller_is_module() \
2313 module_text_address((unsigned long)__builtin_return_address(0))
2314#endif
2315
2316/**
2317 * nand_scan - [NAND Interface] Scan for the NAND device
2318 * @mtd: MTD device structure
2319 * @maxchips: Number of chips to scan for
2320 *
2321 * This fills out all the uninitialized function pointers
2322 * with the defaults.
2323 * The flash ID is read and the mtd/chip structures are
2324 * filled with the appropriate values. Buffers are allocated if
2325 * they are not provided by the board driver
2326 * The mtd->owner field must be set to the module of the caller
2327 *
2328 */
2329int nand_scan(struct mtd_info *mtd, int maxchips)
2330{
2331 int i, busw, nand_maf_id;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002332 struct nand_chip *chip = mtd->priv;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002333 struct nand_flash_dev *type;
2334
2335 /* Many callers got this wrong, so check for it for a while... */
2336 if (!mtd->owner && caller_is_module()) {
2337 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2338 BUG();
2339 }
2340
2341 /* Get buswidth to select the correct functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002342 busw = chip->options & NAND_BUSWIDTH_16;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002343 /* Set the default functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002344 nand_set_defaults(chip, busw);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002345
2346 /* Read the flash type */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002347 type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002348
2349 if (IS_ERR(type)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002350 printk(KERN_WARNING "No NAND device found!!!\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002351 chip->select_chip(mtd, -1);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002352 return PTR_ERR(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 }
2354
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002355 /* Check for a chip array */
David Woodhousee0c7d762006-05-13 18:07:53 +01002356 for (i = 1; i < maxchips; i++) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002357 chip->select_chip(mtd, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 /* Send the command for reading device ID */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002359 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /* Read manufacturer and device IDs */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002361 if (nand_maf_id != chip->read_byte(mtd) ||
2362 type->id != chip->read_byte(mtd))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 break;
2364 }
2365 if (i > 1)
2366 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 /* Store the number of chips and calc total size for mtd */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002369 chip->numchips = i;
2370 mtd->size = i * chip->chipsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002372 /* Allocate buffers and data structures */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002373 if (nand_allocate_kmem(mtd, chip))
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002374 return -ENOMEM;
2375
2376 /* Preset the internal oob buffer */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002377 memset(chip->oob_buf, 0xff,
2378 mtd->oobsize << (chip->phys_erase_shift - chip->page_shift));
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002379
2380 /*
2381 * If no default placement scheme is given, select an appropriate one
2382 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002383 if (!chip->autooob) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002384 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 case 8:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002386 chip->autooob = &nand_oob_8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 break;
2388 case 16:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002389 chip->autooob = &nand_oob_16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 break;
2391 case 64:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002392 chip->autooob = &nand_oob_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 break;
2394 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002395 printk(KERN_WARNING "No oob scheme defined for "
2396 "oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 BUG();
2398 }
2399 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002400
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002401 /*
2402 * The number of bytes available for the filesystem to place fs
2403 * dependend oob data
2404 */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002405 mtd->oobavail = 0;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002406 for (i = 0; chip->autooob->oobfree[i][1]; i++)
2407 mtd->oobavail += chip->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002409 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002410 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2411 * selected and we have 256 byte pagesize fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002412 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002413 switch (chip->ecc.mode) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002414 case NAND_ECC_HW:
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02002415 /* Use standard hwecc read page function ? */
2416 if (!chip->ecc.read_page)
2417 chip->ecc.read_page = nand_read_page_hwecc;
2418
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002419 case NAND_ECC_HW_SYNDROME:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002420 if (!chip->ecc.calculate || !chip->ecc.correct ||
2421 !chip->ecc.hwctl) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002422 printk(KERN_WARNING "No ECC functions supplied, "
2423 "Hardware ECC not possible\n");
2424 BUG();
2425 }
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02002426 /* Use standard syndrome read page function ? */
2427 if (!chip->ecc.read_page)
2428 chip->ecc.read_page = nand_read_page_syndrome;
2429
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002430 if (mtd->writesize >= chip->ecc.size)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002431 break;
2432 printk(KERN_WARNING "%d byte HW ECC not possible on "
2433 "%d byte page size, fallback to SW ECC\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002434 chip->ecc.size, mtd->writesize);
2435 chip->ecc.mode = NAND_ECC_SOFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002437 case NAND_ECC_SOFT:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002438 chip->ecc.calculate = nand_calculate_ecc;
2439 chip->ecc.correct = nand_correct_data;
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02002440 chip->ecc.read_page = nand_read_page_swecc;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002441 chip->ecc.size = 256;
2442 chip->ecc.bytes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002444
2445 case NAND_ECC_NONE:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002446 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2447 "This is not recommended !!\n");
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02002448 chip->ecc.read_page = nand_read_page_swecc;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002449 chip->ecc.size = mtd->writesize;
2450 chip->ecc.bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002453 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002454 chip->ecc.mode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002455 BUG();
2456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002458 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002459 * Set the number of read / write steps for one page depending on ECC
2460 * mode
2461 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002462 chip->ecc.steps = mtd->writesize / chip->ecc.size;
2463 if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002464 printk(KERN_WARNING "Invalid ecc parameters\n");
2465 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
Thomas Gleixnerf5bbdac2006-05-25 10:07:16 +02002467 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002468
Thomas Gleixner04bbd0e2006-05-25 09:45:29 +02002469 /* Initialize state */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002470 chip->state = FL_READY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
2472 /* De-select the device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002473 chip->select_chip(mtd, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
2475 /* Invalidate the pagebuffer reference */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002476 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
2478 /* Fill in remaining MTD driver data */
2479 mtd->type = MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02002480 mtd->flags = MTD_CAP_NANDFLASH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 mtd->ecctype = MTD_ECC_SW;
2482 mtd->erase = nand_erase;
2483 mtd->point = NULL;
2484 mtd->unpoint = NULL;
2485 mtd->read = nand_read;
2486 mtd->write = nand_write;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 mtd->read_oob = nand_read_oob;
2488 mtd->write_oob = nand_write_oob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 mtd->sync = nand_sync;
2490 mtd->lock = NULL;
2491 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002492 mtd->suspend = nand_suspend;
2493 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 mtd->block_isbad = nand_block_isbad;
2495 mtd->block_markbad = nand_block_markbad;
2496
2497 /* and make the autooob the default one */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002498 memcpy(&mtd->oobinfo, chip->autooob, sizeof(mtd->oobinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002500 /* Check, if we should skip the bad block table scan */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002501 if (chip->options & NAND_SKIP_BBTSCAN)
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002502 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
2504 /* Build bad block table */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002505 return chip->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506}
2507
2508/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002509 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 * @mtd: MTD device structure
2511*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002512void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002514 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516#ifdef CONFIG_MTD_PARTITIONS
2517 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002518 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519#endif
2520 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002521 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
Jesper Juhlfa671642005-11-07 01:01:27 -08002523 /* Free bad block table memory */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002524 kfree(chip->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002525 /* Free buffers */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002526 nand_free_kmem(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527}
2528
David Woodhousee0c7d762006-05-13 18:07:53 +01002529EXPORT_SYMBOL_GPL(nand_scan);
2530EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002531
2532static int __init nand_base_init(void)
2533{
2534 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2535 return 0;
2536}
2537
2538static void __exit nand_base_exit(void)
2539{
2540 led_trigger_unregister_simple(nand_led_trigger);
2541}
2542
2543module_init(nand_base_init);
2544module_exit(nand_base_exit);
2545
David Woodhousee0c7d762006-05-13 18:07:53 +01002546MODULE_LICENSE("GPL");
2547MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2548MODULE_DESCRIPTION("Generic NAND flash driver code");