blob: 7933ca273c951ab4dfdffdc1b2d7216e6eb09293 [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)
13 * 2002 Thomas Gleixner (tglx@linutronix.de)
14 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000015 * 02-08-2004 tglx: support for strange chips, which cannot auto increment
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * pages on read / read_oob
17 *
18 * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes
19 * pointed this out, as he marked an auto increment capable chip
20 * as NOAUTOINCR in the board driver.
21 * Make reads over block boundaries work too
22 *
23 * 04-14-2004 tglx: first working version for 2k page size chips
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000024 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 * 05-19-2004 tglx: Basic support for Renesas AG-AND chips
26 *
27 * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared
28 * among multiple independend devices. Suggestions and initial patch
29 * from Ben Dooks <ben-mtd@fluff.org>
30 *
David A. Marlin30f464b2005-01-17 18:35:25 +000031 * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
32 * Basically, any block not rewritten may lose data when surrounding blocks
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000033 * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
David A. Marlin30f464b2005-01-17 18:35:25 +000034 * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
35 * do not lose data, force them to be rewritten when some of the surrounding
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000036 * blocks are erased. Rather than tracking a specific nearby block (which
37 * could itself go bad), use a page address 'mask' to select several blocks
David A. Marlin30f464b2005-01-17 18:35:25 +000038 * in the same area, and rewrite the BBT when any of them are erased.
39 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000040 * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
David A. Marlin30f464b2005-01-17 18:35:25 +000041 * AG-AND chips. If there was a sudden loss of power during an erase operation,
42 * a "device recovery" operation must be performed when power is restored
43 * to ensure correct operation.
44 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000045 * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
David A. Marlin068e3c02005-01-24 03:07:46 +000046 * perform extra error status checks on erase and write failures. This required
47 * adding a wrapper function for nand_read_ecc.
48 *
Vitaly Wool962034f2005-09-15 14:58:53 +010049 * 08-20-2005 vwool: suspend/resume added
50 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * Credits:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000052 * David Woodhouse for adding multichip support
53 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
55 * rework for 2K page size chips
56 *
57 * TODO:
58 * Enable cached programming for 2k page size chips
59 * Check, if mtd->ecctype should be set to MTD_ECC_HW
60 * if we have HW ecc support.
61 * The AG-AND chips have nice features for speed improvement,
62 * which are not supported yet. Read / program 4 pages in one go.
63 *
Vitaly Wool962034f2005-09-15 14:58:53 +010064 * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 *
66 * This program is free software; you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License version 2 as
68 * published by the Free Software Foundation.
69 *
70 */
71
David Woodhouse552d9202006-05-14 01:20:46 +010072#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#include <linux/delay.h>
74#include <linux/errno.h>
75#include <linux/sched.h>
76#include <linux/slab.h>
77#include <linux/types.h>
78#include <linux/mtd/mtd.h>
79#include <linux/mtd/nand.h>
80#include <linux/mtd/nand_ecc.h>
81#include <linux/mtd/compatmac.h>
82#include <linux/interrupt.h>
83#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080084#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#include <asm/io.h>
86
87#ifdef CONFIG_MTD_PARTITIONS
88#include <linux/mtd/partitions.h>
89#endif
90
91/* Define default oob placement schemes for large and small page devices */
92static struct nand_oobinfo nand_oob_8 = {
93 .useecc = MTD_NANDECC_AUTOPLACE,
94 .eccbytes = 3,
95 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +010096 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
99static struct nand_oobinfo nand_oob_16 = {
100 .useecc = MTD_NANDECC_AUTOPLACE,
101 .eccbytes = 6,
102 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +0100103 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104};
105
106static struct nand_oobinfo nand_oob_64 = {
107 .useecc = MTD_NANDECC_AUTOPLACE,
108 .eccbytes = 24,
109 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +0100110 40, 41, 42, 43, 44, 45, 46, 47,
111 48, 49, 50, 51, 52, 53, 54, 55,
112 56, 57, 58, 59, 60, 61, 62, 63},
113 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
116/* This is used for padding purposes in nand_write_oob */
117static u_char ffchars[] = {
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
126};
127
128/*
129 * NAND low-level MTD interface functions
130 */
131static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
132static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
133static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
134
David Woodhousee0c7d762006-05-13 18:07:53 +0100135static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
136static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
137 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
138static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
139static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
140static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
141 size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
142static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
143static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
144static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
145 unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf,
146 struct nand_oobinfo *oobsel);
147static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
148static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150/* Some internal functions */
David Woodhousee0c7d762006-05-13 18:07:53 +0100151static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page, u_char * oob_buf,
152 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
David Woodhousee0c7d762006-05-13 18:07:53 +0100154static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
155 u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156#else
157#define nand_verify_pages(...) (0)
158#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000159
David Woodhousee0c7d762006-05-13 18:07:53 +0100160static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162/**
163 * nand_release_device - [GENERIC] release chip
164 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000165 *
166 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100168static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
170 struct nand_chip *this = mtd->priv;
171
172 /* De-select the NAND device */
173 this->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100174
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200175 /* Release the controller and the chip */
176 spin_lock(&this->controller->lock);
177 this->controller->active = NULL;
178 this->state = FL_READY;
179 wake_up(&this->controller->wq);
180 spin_unlock(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
183/**
184 * nand_read_byte - [DEFAULT] read one byte from the chip
185 * @mtd: MTD device structure
186 *
187 * Default read function for 8bit buswith
188 */
189static u_char nand_read_byte(struct mtd_info *mtd)
190{
191 struct nand_chip *this = mtd->priv;
192 return readb(this->IO_ADDR_R);
193}
194
195/**
196 * nand_write_byte - [DEFAULT] write one byte to the chip
197 * @mtd: MTD device structure
198 * @byte: pointer to data byte to write
199 *
200 * Default write function for 8it buswith
201 */
202static void nand_write_byte(struct mtd_info *mtd, u_char byte)
203{
204 struct nand_chip *this = mtd->priv;
205 writeb(byte, this->IO_ADDR_W);
206}
207
208/**
209 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
210 * @mtd: MTD device structure
211 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000212 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 * endianess conversion
214 */
215static u_char nand_read_byte16(struct mtd_info *mtd)
216{
217 struct nand_chip *this = mtd->priv;
218 return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
219}
220
221/**
222 * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
223 * @mtd: MTD device structure
224 * @byte: pointer to data byte to write
225 *
226 * Default write function for 16bit buswith with
227 * endianess conversion
228 */
229static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
230{
231 struct nand_chip *this = mtd->priv;
232 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
233}
234
235/**
236 * nand_read_word - [DEFAULT] read one word from the chip
237 * @mtd: MTD device structure
238 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000239 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 * endianess conversion
241 */
242static u16 nand_read_word(struct mtd_info *mtd)
243{
244 struct nand_chip *this = mtd->priv;
245 return readw(this->IO_ADDR_R);
246}
247
248/**
249 * nand_write_word - [DEFAULT] write one word to the chip
250 * @mtd: MTD device structure
251 * @word: data word to write
252 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000253 * Default write function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 * endianess conversion
255 */
256static void nand_write_word(struct mtd_info *mtd, u16 word)
257{
258 struct nand_chip *this = mtd->priv;
259 writew(word, this->IO_ADDR_W);
260}
261
262/**
263 * nand_select_chip - [DEFAULT] control CE line
264 * @mtd: MTD device structure
265 * @chip: chipnumber to select, -1 for deselect
266 *
267 * Default select function for 1 chip devices.
268 */
269static void nand_select_chip(struct mtd_info *mtd, int chip)
270{
271 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100272 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 case -1:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000274 this->hwcontrol(mtd, NAND_CTL_CLRNCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 break;
276 case 0:
277 this->hwcontrol(mtd, NAND_CTL_SETNCE);
278 break;
279
280 default:
281 BUG();
282 }
283}
284
285/**
286 * nand_write_buf - [DEFAULT] write buffer to chip
287 * @mtd: MTD device structure
288 * @buf: data buffer
289 * @len: number of bytes to write
290 *
291 * Default write function for 8bit buswith
292 */
293static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
294{
295 int i;
296 struct nand_chip *this = mtd->priv;
297
David Woodhousee0c7d762006-05-13 18:07:53 +0100298 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 writeb(buf[i], this->IO_ADDR_W);
300}
301
302/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000303 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 * @mtd: MTD device structure
305 * @buf: buffer to store date
306 * @len: number of bytes to read
307 *
308 * Default read function for 8bit buswith
309 */
310static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
311{
312 int i;
313 struct nand_chip *this = mtd->priv;
314
David Woodhousee0c7d762006-05-13 18:07:53 +0100315 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 buf[i] = readb(this->IO_ADDR_R);
317}
318
319/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000320 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 * @mtd: MTD device structure
322 * @buf: buffer containing the data to compare
323 * @len: number of bytes to compare
324 *
325 * Default verify function for 8bit buswith
326 */
327static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
328{
329 int i;
330 struct nand_chip *this = mtd->priv;
331
David Woodhousee0c7d762006-05-13 18:07:53 +0100332 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (buf[i] != readb(this->IO_ADDR_R))
334 return -EFAULT;
335
336 return 0;
337}
338
339/**
340 * nand_write_buf16 - [DEFAULT] write buffer to chip
341 * @mtd: MTD device structure
342 * @buf: data buffer
343 * @len: number of bytes to write
344 *
345 * Default write function for 16bit buswith
346 */
347static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
348{
349 int i;
350 struct nand_chip *this = mtd->priv;
351 u16 *p = (u16 *) buf;
352 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000353
David Woodhousee0c7d762006-05-13 18:07:53 +0100354 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
359/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000360 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 * @mtd: MTD device structure
362 * @buf: buffer to store date
363 * @len: number of bytes to read
364 *
365 * Default read function for 16bit buswith
366 */
367static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
368{
369 int i;
370 struct nand_chip *this = mtd->priv;
371 u16 *p = (u16 *) buf;
372 len >>= 1;
373
David Woodhousee0c7d762006-05-13 18:07:53 +0100374 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 p[i] = readw(this->IO_ADDR_R);
376}
377
378/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000379 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 * @mtd: MTD device structure
381 * @buf: buffer containing the data to compare
382 * @len: number of bytes to compare
383 *
384 * Default verify function for 16bit buswith
385 */
386static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
387{
388 int i;
389 struct nand_chip *this = mtd->priv;
390 u16 *p = (u16 *) buf;
391 len >>= 1;
392
David Woodhousee0c7d762006-05-13 18:07:53 +0100393 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 if (p[i] != readw(this->IO_ADDR_R))
395 return -EFAULT;
396
397 return 0;
398}
399
400/**
401 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
402 * @mtd: MTD device structure
403 * @ofs: offset from device start
404 * @getchip: 0, if the chip is already selected
405 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000406 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 */
408static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
409{
410 int page, chipnr, res = 0;
411 struct nand_chip *this = mtd->priv;
412 u16 bad;
413
414 if (getchip) {
415 page = (int)(ofs >> this->page_shift);
416 chipnr = (int)(ofs >> this->chip_shift);
417
418 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100419 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 /* Select the NAND device */
422 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000423 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100424 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 if (this->options & NAND_BUSWIDTH_16) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100427 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 bad = cpu_to_le16(this->read_word(mtd));
429 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000430 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 if ((bad & 0xFF) != 0xff)
432 res = 1;
433 } else {
David Woodhousee0c7d762006-05-13 18:07:53 +0100434 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 if (this->read_byte(mtd) != 0xff)
436 res = 1;
437 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (getchip) {
440 /* Deselect and wake up anyone waiting on the device */
441 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000442 }
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 return res;
445}
446
447/**
448 * nand_default_block_markbad - [DEFAULT] mark a block bad
449 * @mtd: MTD device structure
450 * @ofs: offset from device start
451 *
452 * This is the default implementation, which can be overridden by
453 * a hardware specific driver.
454*/
455static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
456{
457 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100458 u_char buf[2] = { 0, 0 };
459 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100463 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000464 if (this->bbt)
465 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 /* Do we have a flash based bad block table ? */
468 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100469 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 /* We write two bytes, so we dont have to mess with 16 bit access */
472 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100473 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000476/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 * nand_check_wp - [GENERIC] check if the chip is write protected
478 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000479 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000481 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100483static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct nand_chip *this = mtd->priv;
486 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100487 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000488 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
491/**
492 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
493 * @mtd: MTD device structure
494 * @ofs: offset from device start
495 * @getchip: 0, if the chip is already selected
496 * @allowbbt: 1, if its allowed to access the bbt area
497 *
498 * Check, if the block is bad. Either by reading the bad block table or
499 * calling of the scan function.
500 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100501static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
503 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (!this->bbt)
506 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100509 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510}
511
Richard Purdie8fe833c2006-03-31 02:31:14 -0800512DEFINE_LED_TRIGGER(nand_led_trigger);
513
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000514/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000515 * Wait for the ready pin, after a command
516 * The timeout is catched later.
517 */
518static void nand_wait_ready(struct mtd_info *mtd)
519{
520 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100521 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000522
Richard Purdie8fe833c2006-03-31 02:31:14 -0800523 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000524 /* wait until command is processed or timeout occures */
525 do {
526 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800527 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700528 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000529 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800530 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000531}
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533/**
534 * nand_command - [DEFAULT] Send command to NAND device
535 * @mtd: MTD device structure
536 * @command: the command to be sent
537 * @column: the column address for this command, -1 if none
538 * @page_addr: the page address for this command, -1 if none
539 *
540 * Send command to NAND device. This function is used for small page
541 * devices (256/512 Bytes per page)
542 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100543static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 register struct nand_chip *this = mtd->priv;
546
547 /* Begin command latch cycle */
548 this->hwcontrol(mtd, NAND_CTL_SETCLE);
549 /*
550 * Write out the command to the device.
551 */
552 if (command == NAND_CMD_SEQIN) {
553 int readcmd;
554
555 if (column >= mtd->oobblock) {
556 /* OOB area */
557 column -= mtd->oobblock;
558 readcmd = NAND_CMD_READOOB;
559 } else if (column < 256) {
560 /* First 256 bytes --> READ0 */
561 readcmd = NAND_CMD_READ0;
562 } else {
563 column -= 256;
564 readcmd = NAND_CMD_READ1;
565 }
566 this->write_byte(mtd, readcmd);
567 }
568 this->write_byte(mtd, command);
569
570 /* Set ALE and clear CLE to start address cycle */
571 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
572
573 if (column != -1 || page_addr != -1) {
574 this->hwcontrol(mtd, NAND_CTL_SETALE);
575
576 /* Serially input address */
577 if (column != -1) {
578 /* Adjust columns for 16 bit buswidth */
579 if (this->options & NAND_BUSWIDTH_16)
580 column >>= 1;
581 this->write_byte(mtd, column);
582 }
583 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100584 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
585 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 /* One more address cycle for devices > 32MiB */
587 if (this->chipsize > (32 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100588 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
590 /* Latch in address */
591 this->hwcontrol(mtd, NAND_CTL_CLRALE);
592 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000593
594 /*
595 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100597 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 case NAND_CMD_PAGEPROG:
601 case NAND_CMD_ERASE1:
602 case NAND_CMD_ERASE2:
603 case NAND_CMD_SEQIN:
604 case NAND_CMD_STATUS:
605 return;
606
607 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000608 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 break;
610 udelay(this->chip_delay);
611 this->hwcontrol(mtd, NAND_CTL_SETCLE);
612 this->write_byte(mtd, NAND_CMD_STATUS);
613 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100614 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return;
616
David Woodhousee0c7d762006-05-13 18:07:53 +0100617 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000619 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 * If we don't have access to the busy pin, we apply the given
621 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100622 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100624 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 /* Apply this short delay always to ensure that we do wait tWB in
629 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100630 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000631
632 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
635/**
636 * nand_command_lp - [DEFAULT] Send command to NAND large page device
637 * @mtd: MTD device structure
638 * @command: the command to be sent
639 * @column: the column address for this command, -1 if none
640 * @page_addr: the page address for this command, -1 if none
641 *
642 * Send command to NAND device. This is the version for the new large page devices
David Woodhousee0c7d762006-05-13 18:07:53 +0100643 * We dont have the separate regions as we have in the small page devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 * We must emulate NAND_CMD_READOOB to keep the code compatible.
645 *
646 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100647static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 register struct nand_chip *this = mtd->priv;
650
651 /* Emulate NAND_CMD_READOOB */
652 if (command == NAND_CMD_READOOB) {
653 column += mtd->oobblock;
654 command = NAND_CMD_READ0;
655 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* Begin command latch cycle */
658 this->hwcontrol(mtd, NAND_CTL_SETCLE);
659 /* Write out the command to the device. */
David A. Marlin30f464b2005-01-17 18:35:25 +0000660 this->write_byte(mtd, (command & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /* End command latch cycle */
662 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
663
664 if (column != -1 || page_addr != -1) {
665 this->hwcontrol(mtd, NAND_CTL_SETALE);
666
667 /* Serially input address */
668 if (column != -1) {
669 /* Adjust columns for 16 bit buswidth */
670 if (this->options & NAND_BUSWIDTH_16)
671 column >>= 1;
672 this->write_byte(mtd, column & 0xff);
673 this->write_byte(mtd, column >> 8);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100676 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
677 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 /* One more address cycle for devices > 128MiB */
679 if (this->chipsize > (128 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100680 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682 /* Latch in address */
683 this->hwcontrol(mtd, NAND_CTL_CLRALE);
684 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000685
686 /*
687 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000688 * status, sequential in, and deplete1 need no delay
689 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 case NAND_CMD_CACHEDPROG:
693 case NAND_CMD_PAGEPROG:
694 case NAND_CMD_ERASE1:
695 case NAND_CMD_ERASE2:
696 case NAND_CMD_SEQIN:
697 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000698 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return;
700
David Woodhousee0c7d762006-05-13 18:07:53 +0100701 /*
702 * read error status commands require only a short delay
703 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000704 case NAND_CMD_STATUS_ERROR:
705 case NAND_CMD_STATUS_ERROR0:
706 case NAND_CMD_STATUS_ERROR1:
707 case NAND_CMD_STATUS_ERROR2:
708 case NAND_CMD_STATUS_ERROR3:
709 udelay(this->chip_delay);
710 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000713 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 break;
715 udelay(this->chip_delay);
716 this->hwcontrol(mtd, NAND_CTL_SETCLE);
717 this->write_byte(mtd, NAND_CMD_STATUS);
718 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100719 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return;
721
722 case NAND_CMD_READ0:
723 /* Begin command latch cycle */
724 this->hwcontrol(mtd, NAND_CTL_SETCLE);
725 /* Write out the start read command */
726 this->write_byte(mtd, NAND_CMD_READSTART);
727 /* End command latch cycle */
728 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
729 /* Fall through into ready check */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000730
David Woodhousee0c7d762006-05-13 18:07:53 +0100731 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000733 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 * If we don't have access to the busy pin, we apply the given
735 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100736 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100738 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 /* Apply this short delay always to ensure that we do wait tWB in
744 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100745 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000746
747 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750/**
751 * nand_get_device - [GENERIC] Get chip for selected access
752 * @this: the nand chip descriptor
753 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000754 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 *
756 * Get the device and lock it for exclusive access
757 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100758static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200760 spinlock_t *lock = &this->controller->lock;
761 wait_queue_head_t *wq = &this->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100762 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100763 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100764 spin_lock(lock);
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200767 /* Hardware controller shared among independend devices */
768 if (!this->controller->active)
769 this->controller->active = this;
770
771 if (this->controller->active == this && this->state == FL_READY) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100772 this->state = new_state;
773 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100774 return 0;
775 }
776 if (new_state == FL_PM_SUSPENDED) {
777 spin_unlock(lock);
778 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100779 }
780 set_current_state(TASK_UNINTERRUPTIBLE);
781 add_wait_queue(wq, &wait);
782 spin_unlock(lock);
783 schedule();
784 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 goto retry;
786}
787
788/**
789 * nand_wait - [DEFAULT] wait until the command is done
790 * @mtd: MTD device structure
791 * @this: NAND chip structure
792 * @state: state to select the max. timeout value
793 *
794 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000795 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 * general NAND and SmartMedia specs
797 *
798*/
799static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
800{
801
David Woodhousee0c7d762006-05-13 18:07:53 +0100802 unsigned long timeo = jiffies;
803 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100806 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100808 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Richard Purdie8fe833c2006-03-31 02:31:14 -0800810 led_trigger_event(nand_led_trigger, LED_FULL);
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* Apply this short delay always to ensure that we do wait tWB in
813 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100814 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100817 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000818 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100819 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000821 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* Check, if we were interrupted */
823 if (this->state != state)
824 return 0;
825
826 if (this->dev_ready) {
827 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000828 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 } else {
830 if (this->read_byte(mtd) & NAND_STATUS_READY)
831 break;
832 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000833 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800835 led_trigger_event(nand_led_trigger, LED_OFF);
836
David Woodhousee0c7d762006-05-13 18:07:53 +0100837 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 return status;
839}
840
841/**
842 * nand_write_page - [GENERIC] write one page
843 * @mtd: MTD device structure
844 * @this: NAND chip structure
845 * @page: startpage inside the chip, must be called with (page & this->pagemask)
846 * @oob_buf: out of band data buffer
847 * @oobsel: out of band selecttion structre
848 * @cached: 1 = enable cached programming if supported by chip
849 *
850 * Nand_page_program function is used for write and writev !
851 * This function will always program a full page of data
852 * If you call it with a non page aligned buffer, you're lost :)
853 *
854 * Cached programming is not supported yet.
855 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100856static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
857 u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
David Woodhousee0c7d762006-05-13 18:07:53 +0100859 int i, status;
860 u_char ecc_code[32];
861 int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
862 int *oob_config = oobsel->eccpos;
863 int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
864 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* FIXME: Enable cached programming */
867 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100870 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872 /* Write out complete page of data, take care of eccmode */
873 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100874 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100876 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 this->write_buf(mtd, this->data_poi, mtd->oobblock);
878 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000879
David Woodhousee0c7d762006-05-13 18:07:53 +0100880 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 case NAND_ECC_SOFT:
882 for (; eccsteps; eccsteps--) {
883 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
884 for (i = 0; i < 3; i++, eccidx++)
885 oob_buf[oob_config[eccidx]] = ecc_code[i];
886 datidx += this->eccsize;
887 }
888 this->write_buf(mtd, this->data_poi, mtd->oobblock);
889 break;
890 default:
891 eccbytes = this->eccbytes;
892 for (; eccsteps; eccsteps--) {
893 /* enable hardware ecc logic for write */
894 this->enable_hwecc(mtd, NAND_ECC_WRITE);
895 this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
896 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
897 for (i = 0; i < eccbytes; i++, eccidx++)
898 oob_buf[oob_config[eccidx]] = ecc_code[i];
899 /* If the hardware ecc provides syndromes then
900 * the ecc code must be written immidiately after
901 * the data bytes (words) */
902 if (this->options & NAND_HWECC_SYNDROME)
903 this->write_buf(mtd, ecc_code, eccbytes);
904 datidx += this->eccsize;
905 }
906 break;
907 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* Write out OOB data */
910 if (this->options & NAND_HWECC_SYNDROME)
911 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000912 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 this->write_buf(mtd, oob_buf, mtd->oobsize);
914
915 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100916 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 if (!cached) {
919 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100920 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000921
922 /* See if operation failed and additional status checks are available */
923 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
924 status = this->errstat(mtd, this, FL_WRITING, status, page);
925 }
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000928 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100929 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 return -EIO;
931 }
932 } else {
933 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100934 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
936 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000937 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938}
939
940#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
941/**
942 * nand_verify_pages - [GENERIC] verify the chip contents after a write
943 * @mtd: MTD device structure
944 * @this: NAND chip structure
945 * @page: startpage inside the chip, must be called with (page & this->pagemask)
946 * @numpages: number of pages to verify
947 * @oob_buf: out of band data buffer
948 * @oobsel: out of band selecttion structre
949 * @chipnr: number of the current chip
950 * @oobmode: 1 = full buffer verify, 0 = ecc only
951 *
952 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000953 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000955 * byte by byte basis. It is possible that the page was not completely erased
956 * or the page is becoming unusable due to wear. The read with ECC would catch
957 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 * it early in the page write stage. Better to write no data than invalid data.
959 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100960static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
961 u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
David Woodhousee0c7d762006-05-13 18:07:53 +0100963 int i, j, datidx = 0, oobofs = 0, res = -EIO;
964 int eccsteps = this->eccsteps;
965 int hweccbytes;
966 u_char oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
969
970 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100971 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
David Woodhousee0c7d762006-05-13 18:07:53 +0100973 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 for (j = 0; j < eccsteps; j++) {
975 /* Loop through and verify the data */
976 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100977 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 goto out;
979 }
980 datidx += mtd->eccsize;
981 /* Have we a hw generator layout ? */
982 if (!hweccbytes)
983 continue;
984 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100985 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 goto out;
987 }
988 oobofs += hweccbytes;
989 }
990
991 /* check, if we must compare all data or if we just have to
992 * compare the ecc bytes
993 */
994 if (oobmode) {
995 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100996 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 goto out;
998 }
999 } else {
1000 /* Read always, else autoincrement fails */
1001 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
1002
1003 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
1004 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 for (i = 0; i < ecccnt; i++) {
1007 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +01001008 if (oobdata[idx] != oob_buf[oobofs + idx]) {
1009 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
1010 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 goto out;
1012 }
1013 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 }
1016 oobofs += mtd->oobsize - hweccbytes * eccsteps;
1017 page++;
1018 numpages--;
1019
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001020 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 * Do this before the AUTOINCR check, so no problems
1022 * arise if a chip which does auto increment
1023 * is marked as NOAUTOINCR by the board driver.
1024 * Do this also before returning, so the chip is
1025 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +01001026 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001027 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001028 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001030 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 /* All done, return happy */
1033 if (!numpages)
1034 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001035
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001036 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001038 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001040 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 * Terminate the read command. We come here in case of an error
1042 * So we must issue a reset command.
1043 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001044 out:
1045 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return res;
1047}
1048#endif
1049
1050/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001051 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 * @mtd: MTD device structure
1053 * @from: offset to read from
1054 * @len: number of bytes to read
1055 * @retlen: pointer to variable to store the number of read bytes
1056 * @buf: the databuffer to put data
1057 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001058 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1059 * and flags = 0xff
1060 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001061static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
David Woodhousee0c7d762006-05-13 18:07:53 +01001063 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001064}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001067 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 * @mtd: MTD device structure
1069 * @from: offset to read from
1070 * @len: number of bytes to read
1071 * @retlen: pointer to variable to store the number of read bytes
1072 * @buf: the databuffer to put data
1073 * @oob_buf: filesystem supplied oob data buffer
1074 * @oobsel: oob selection structure
1075 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001076 * This function simply calls nand_do_read_ecc with flags = 0xff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001078static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1079 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001081 /* use userspace supplied oobinfo, if zero */
1082 if (oobsel == NULL)
1083 oobsel = &mtd->oobinfo;
David A. Marlin068e3c02005-01-24 03:07:46 +00001084 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1085}
1086
David A. Marlin068e3c02005-01-24 03:07:46 +00001087/**
1088 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1089 * @mtd: MTD device structure
1090 * @from: offset to read from
1091 * @len: number of bytes to read
1092 * @retlen: pointer to variable to store the number of read bytes
1093 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001094 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001095 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001096 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1097 * and how many corrected error bits are acceptable:
1098 * bits 0..7 - number of tolerable errors
1099 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1100 *
1101 * NAND read with ECC
1102 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001103int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1104 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001105{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1108 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1109 struct nand_chip *this = mtd->priv;
1110 u_char *data_poi, *oob_data = oob_buf;
Jarkko Lavinen0a18cde2005-04-11 15:16:11 +01001111 u_char ecc_calc[32];
1112 u_char ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001113 int eccmode, eccsteps;
1114 int *oob_config, datidx;
1115 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1116 int eccbytes;
1117 int compareecc = 1;
1118 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
David Woodhousee0c7d762006-05-13 18:07:53 +01001120 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 /* Do not allow reads past end of device */
1123 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001124 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 *retlen = 0;
1126 return -EINVAL;
1127 }
1128
1129 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001130 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001131 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 /* Autoplace of oob data ? Use the default placement scheme */
1134 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1135 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
1138 oob_config = oobsel->eccpos;
1139
1140 /* Select the NAND device */
1141 chipnr = (int)(from >> this->chip_shift);
1142 this->select_chip(mtd, chipnr);
1143
1144 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001145 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 page = realpage & this->pagemask;
1147
1148 /* Get raw starting column */
1149 col = from & (mtd->oobblock - 1);
1150
1151 end = mtd->oobblock;
1152 ecc = this->eccsize;
1153 eccbytes = this->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1156 compareecc = 0;
1157
1158 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001159 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 oobreadlen -= oobsel->eccbytes;
1161
1162 /* Loop until all data read */
1163 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001166 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 * If the read is not page aligned, we have to read into data buffer
1168 * due to ecc, else we read into return buffer direct
1169 */
1170 if (aligned)
1171 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001172 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001174
1175 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 *
1177 * FIXME: Make it work when we must provide oob data too,
1178 * check the usage of data_buf oob field
1179 */
1180 if (realpage == this->pagebuf && !oob_buf) {
1181 /* aligned read ? */
1182 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001183 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 goto readdata;
1185 }
1186
1187 /* Check, if we must send the read command */
1188 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001189 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001194 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1195 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 oob_data = &this->data_buf[end];
1197
1198 eccsteps = this->eccsteps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001201 case NAND_ECC_NONE:{
1202 /* No ECC, Read in a page */
1203 static unsigned long lastwhinge = 0;
1204 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1205 printk(KERN_WARNING
1206 "Reading data from NAND FLASH without ECC is not recommended\n");
1207 lastwhinge = jiffies;
1208 }
1209 this->read_buf(mtd, data_poi, end);
1210 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1214 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001215 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001217 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001220 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 this->enable_hwecc(mtd, NAND_ECC_READ);
1222 this->read_buf(mtd, &data_poi[datidx], ecc);
1223
1224 /* HW ecc with syndrome calculation must read the
1225 * syndrome from flash immidiately after the data */
1226 if (!compareecc) {
1227 /* Some hw ecc generators need to know when the
1228 * syndrome is read from flash */
1229 this->enable_hwecc(mtd, NAND_ECC_READSYN);
1230 this->read_buf(mtd, &oob_data[i], eccbytes);
1231 /* We calc error correction directly, it checks the hw
1232 * generator for an error, reads back the syndrome and
1233 * does the error correction on the fly */
David A. Marlin068e3c02005-01-24 03:07:46 +00001234 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1235 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001236 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1237 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 ecc_failed++;
1239 }
1240 } else {
1241 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001244 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
1246
1247 /* read oobdata */
1248 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1249
1250 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1251 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001252 goto readoob;
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 /* Pick the ECC bytes out of the oob data */
1255 for (j = 0; j < oobsel->eccbytes; j++)
1256 ecc_code[j] = oob_data[oob_config[j]];
1257
David Woodhousee0c7d762006-05-13 18:07:53 +01001258 /* correct data, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
1260 ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 /* Get next chunk of ecc bytes */
1263 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001264
1265 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 * This is the legacy mode. Used by YAFFS1
1267 * Should go away some day
1268 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001269 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 int *p = (int *)(&oob_data[mtd->oobsize]);
1271 p[i] = ecc_status;
1272 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001273
1274 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001275 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 ecc_failed++;
1277 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
David Woodhousee0c7d762006-05-13 18:07:53 +01001280 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 /* check, if we have a fs supplied oob-buffer */
1282 if (oob_buf) {
1283 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001284 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001286 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001288 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 int from = oobsel->oobfree[i][0];
1290 int num = oobsel->oobfree[i][1];
1291 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001292 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 break;
1295 case MTD_NANDECC_PLACE:
1296 /* YAFFS1 legacy mode */
David Woodhousee0c7d762006-05-13 18:07:53 +01001297 oob_data += this->eccsteps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 default:
1299 oob_data += mtd->oobsize;
1300 }
1301 }
1302 readdata:
1303 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001304 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 for (j = col; j < end && read < len; j++)
1306 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001307 this->pagebuf = realpage;
1308 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 read += mtd->oobblock;
1310
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001311 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 * Do this before the AUTOINCR check, so no problems
1313 * arise if a chip which does auto increment
1314 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001315 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001316 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001317 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001319 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001320
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001322 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324 /* For subsequent reads align to page boundary. */
1325 col = 0;
1326 /* Increment page address */
1327 realpage++;
1328
1329 page = realpage & this->pagemask;
1330 /* Check, if we cross a chip boundary */
1331 if (!page) {
1332 chipnr++;
1333 this->select_chip(mtd, -1);
1334 this->select_chip(mtd, chipnr);
1335 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001336 /* Check, if the chip supports auto page increment
1337 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001338 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001340 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
1342
1343 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001344 if (flags & NAND_GET_DEVICE)
1345 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 /*
1348 * Return success, if no ECC failures, else -EBADMSG
1349 * fs driver will take care of that, because
1350 * retlen == desired len and result == -EBADMSG
1351 */
1352 *retlen = read;
1353 return ecc_failed ? -EBADMSG : 0;
1354}
1355
1356/**
1357 * nand_read_oob - [MTD Interface] NAND read out-of-band
1358 * @mtd: MTD device structure
1359 * @from: offset to read from
1360 * @len: number of bytes to read
1361 * @retlen: pointer to variable to store the number of read bytes
1362 * @buf: the databuffer to put data
1363 *
1364 * NAND read out-of-band data from the spare area
1365 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001366static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
1368 int i, col, page, chipnr;
1369 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001370 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
David Woodhousee0c7d762006-05-13 18:07:53 +01001372 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 /* Shift to get page */
1375 page = (int)(from >> this->page_shift);
1376 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 /* Mask to get column */
1379 col = from & (mtd->oobsize - 1);
1380
1381 /* Initialize return length value */
1382 *retlen = 0;
1383
1384 /* Do not allow reads past end of device */
1385 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001386 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 *retlen = 0;
1388 return -EINVAL;
1389 }
1390
1391 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001392 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 /* Select the NAND device */
1395 this->select_chip(mtd, chipnr);
1396
1397 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001398 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001399 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 * Read the data, if we read more than one page
1401 * oob data, let the device transfer the data !
1402 */
1403 i = 0;
1404 while (i < len) {
1405 int thislen = mtd->oobsize - col;
1406 thislen = min_t(int, thislen, len);
1407 this->read_buf(mtd, &buf[i], thislen);
1408 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410 /* Read more ? */
1411 if (i < len) {
1412 page++;
1413 col = 0;
1414
1415 /* Check, if we cross a chip boundary */
1416 if (!(page & this->pagemask)) {
1417 chipnr++;
1418 this->select_chip(mtd, -1);
1419 this->select_chip(mtd, chipnr);
1420 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001421
1422 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001423 * Do this before the AUTOINCR check, so no problems
1424 * arise if a chip which does auto increment
1425 * is marked as NOAUTOINCR by the board driver.
1426 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001427 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001428 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001429 else
1430 nand_wait_ready(mtd);
1431
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001432 /* Check, if the chip supports auto page increment
1433 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001434 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1436 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001437 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 }
1439 }
1440 }
1441
1442 /* Deselect and wake up anyone waiting on the device */
1443 nand_release_device(mtd);
1444
1445 /* Return happy */
1446 *retlen = len;
1447 return 0;
1448}
1449
1450/**
1451 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1452 * @mtd: MTD device structure
1453 * @buf: temporary buffer
1454 * @from: offset to read from
1455 * @len: number of bytes to read
1456 * @ooblen: number of oob data bytes to read
1457 *
1458 * Read raw data including oob into buffer
1459 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001460int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
1462 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001463 int page = (int)(from >> this->page_shift);
1464 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 int sndcmd = 1;
1466 int cnt = 0;
1467 int pagesize = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001468 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
1470 /* Do not allow reads past end of device */
1471 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001472 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 return -EINVAL;
1474 }
1475
1476 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001477 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
David Woodhousee0c7d762006-05-13 18:07:53 +01001479 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001480
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 /* Add requested oob length */
1482 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001483
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 while (len) {
1485 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001486 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001487 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
David Woodhousee0c7d762006-05-13 18:07:53 +01001489 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 len -= pagesize;
1492 cnt += pagesize;
1493 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001494
1495 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001496 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001498 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001499
1500 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1502 sndcmd = 1;
1503 }
1504
1505 /* Deselect and wake up anyone waiting on the device */
1506 nand_release_device(mtd);
1507 return 0;
1508}
1509
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001510/**
1511 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 * @mtd: MTD device structure
1513 * @fsbuf: buffer given by fs driver
1514 * @oobsel: out of band selection structre
1515 * @autoplace: 1 = place given buffer into the oob bytes
1516 * @numpages: number of pages to prepare
1517 *
1518 * Return:
1519 * 1. Filesystem buffer available and autoplacement is off,
1520 * return filesystem buffer
1521 * 2. No filesystem buffer or autoplace is off, return internal
1522 * buffer
1523 * 3. Filesystem buffer is given and autoplace selected
1524 * put data from fs buffer into internal buffer and
1525 * retrun internal buffer
1526 *
1527 * Note: The internal buffer is filled with 0xff. This must
1528 * be done only once, when no autoplacement happens
1529 * Autoplacement sets the buffer dirty flag, which
1530 * forces the 0xff fill before using the buffer again.
1531 *
1532*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001533static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
1534 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
1536 struct nand_chip *this = mtd->priv;
1537 int i, len, ofs;
1538
1539 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001540 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 return fsbuf;
1542
1543 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001544 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001545 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001547 }
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 /* If we have no autoplacement or no fs buffer use the internal one */
1550 if (!autoplace || !fsbuf)
1551 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* Walk through the pages and place the data */
1554 this->oobdirty = 1;
1555 ofs = 0;
1556 while (numpages--) {
1557 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1558 int to = ofs + oobsel->oobfree[i][0];
1559 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001560 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 len += num;
1562 fsbuf += num;
1563 }
1564 ofs += mtd->oobavail;
1565 }
1566 return this->oob_buf;
1567}
1568
1569#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
1570
1571/**
1572 * nand_write - [MTD Interface] compability function for nand_write_ecc
1573 * @mtd: MTD device structure
1574 * @to: offset to write to
1575 * @len: number of bytes to write
1576 * @retlen: pointer to variable to store the number of written bytes
1577 * @buf: the data to write
1578 *
1579 * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
1580 *
1581*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001582static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583{
David Woodhousee0c7d762006-05-13 18:07:53 +01001584 return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587/**
1588 * nand_write_ecc - [MTD Interface] NAND write with ECC
1589 * @mtd: MTD device structure
1590 * @to: offset to write to
1591 * @len: number of bytes to write
1592 * @retlen: pointer to variable to store the number of written bytes
1593 * @buf: the data to write
1594 * @eccbuf: filesystem supplied oob data buffer
1595 * @oobsel: oob selection structure
1596 *
1597 * NAND write with ECC
1598 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001599static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
1600 size_t *retlen, const u_char *buf, u_char *eccbuf,
1601 struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
1603 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1604 int autoplace = 0, numpages, totalpages;
1605 struct nand_chip *this = mtd->priv;
1606 u_char *oobbuf, *bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001607 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
David Woodhousee0c7d762006-05-13 18:07:53 +01001609 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611 /* Initialize retlen, in case of early exit */
1612 *retlen = 0;
1613
1614 /* Do not allow write past end of device */
1615 if ((to + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001616 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 return -EINVAL;
1618 }
1619
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001620 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001621 if (NOTALIGNED(to) || NOTALIGNED(len)) {
1622 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return -EINVAL;
1624 }
1625
1626 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001627 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 /* Calculate chipnr */
1630 chipnr = (int)(to >> this->chip_shift);
1631 /* Select the NAND device */
1632 this->select_chip(mtd, chipnr);
1633
1634 /* Check, if it is write protected */
1635 if (nand_check_wp(mtd))
1636 goto out;
1637
1638 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001639 if (oobsel == NULL)
1640 oobsel = &mtd->oobinfo;
1641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 /* Autoplace of oob data ? Use the default placement scheme */
1643 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1644 oobsel = this->autooob;
1645 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001646 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001647 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1648 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 /* Setup variables and oob buffer */
1651 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001652 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001654 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 /* Set it relative to chip */
1658 page &= this->pagemask;
1659 startpage = page;
1660 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001661 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1662 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
1663 bufstart = (u_char *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
1665 /* Loop until all data is written */
1666 while (written < len) {
1667
David Woodhousee0c7d762006-05-13 18:07:53 +01001668 this->data_poi = (u_char *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 /* Write one page. If this is the last page to write
1670 * or the last page in this block, then use the
1671 * real pageprogram command, else select cached programming
1672 * if supported by the chip.
1673 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001674 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001676 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 /* Next oob page */
1680 oob += mtd->oobsize;
1681 /* Update written bytes count */
1682 written += mtd->oobblock;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001683 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* Increment page address */
1687 page++;
1688
1689 /* Have we hit a block boundary ? Then we have to verify and
1690 * if verify is ok, we have to setup the oob buffer for
1691 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001692 */
1693 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 int ofs;
1695 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001696 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1697 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001699 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 *retlen = written;
1703
1704 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1705 if (eccbuf)
1706 eccbuf += (page - startpage) * ofs;
1707 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001708 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 page &= this->pagemask;
1710 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001711 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001712 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 /* Check, if we cross a chip boundary */
1714 if (!page) {
1715 chipnr++;
1716 this->select_chip(mtd, -1);
1717 this->select_chip(mtd, chipnr);
1718 }
1719 }
1720 }
1721 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001722 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001724 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (!ret)
1726 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001727 else
David Woodhousee0c7d762006-05-13 18:07:53 +01001728 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
David Woodhousee0c7d762006-05-13 18:07:53 +01001730 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 /* Deselect and wake up anyone waiting on the device */
1732 nand_release_device(mtd);
1733
1734 return ret;
1735}
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737/**
1738 * nand_write_oob - [MTD Interface] NAND write out-of-band
1739 * @mtd: MTD device structure
1740 * @to: offset to write to
1741 * @len: number of bytes to write
1742 * @retlen: pointer to variable to store the number of written bytes
1743 * @buf: the data to write
1744 *
1745 * NAND write out-of-band
1746 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001747static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748{
1749 int column, page, status, ret = -EIO, chipnr;
1750 struct nand_chip *this = mtd->priv;
1751
David Woodhousee0c7d762006-05-13 18:07:53 +01001752 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001755 page = (int)(to >> this->page_shift);
1756 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 /* Mask to get column */
1759 column = to & (mtd->oobsize - 1);
1760
1761 /* Initialize return length value */
1762 *retlen = 0;
1763
1764 /* Do not allow write past end of page */
1765 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001766 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 return -EINVAL;
1768 }
1769
1770 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001771 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773 /* Select the NAND device */
1774 this->select_chip(mtd, chipnr);
1775
1776 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1777 in one of my DiskOnChip 2000 test units) will clear the whole
1778 data page too if we don't do this. I have no clue why, but
1779 I seem to have 'fixed' it in the doc2000 driver in
1780 August 1999. dwmw2. */
1781 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1782
1783 /* Check, if it is write protected */
1784 if (nand_check_wp(mtd))
1785 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 /* Invalidate the page cache, if we write to the cached page */
1788 if (page == this->pagebuf)
1789 this->pagebuf = -1;
1790
1791 if (NAND_MUST_PAD(this)) {
1792 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001793 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 /* prepad 0xff for partial programming */
1795 this->write_buf(mtd, ffchars, column);
1796 /* write data */
1797 this->write_buf(mtd, buf, len);
1798 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001799 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 } else {
1801 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001802 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 /* write data */
1804 this->write_buf(mtd, buf, len);
1805 }
1806 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001807 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
David Woodhousee0c7d762006-05-13 18:07:53 +01001809 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
1811 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001812 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001813 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 ret = -EIO;
1815 goto out;
1816 }
1817 /* Return happy */
1818 *retlen = len;
1819
1820#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1821 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001822 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001825 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 ret = -EIO;
1827 goto out;
1828 }
1829#endif
1830 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001831 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 /* Deselect and wake up anyone waiting on the device */
1833 nand_release_device(mtd);
1834
1835 return ret;
1836}
1837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838/**
1839 * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
1840 * @mtd: MTD device structure
1841 * @vecs: the iovectors to write
1842 * @count: number of vectors
1843 * @to: offset to write to
1844 * @retlen: pointer to variable to store the number of written bytes
1845 *
1846 * NAND write with kvec. This just calls the ecc function
1847 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001848static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1849 loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850{
David Woodhousee0c7d762006-05-13 18:07:53 +01001851 return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
1854/**
1855 * nand_writev_ecc - [MTD Interface] write with iovec with ecc
1856 * @mtd: MTD device structure
1857 * @vecs: the iovectors to write
1858 * @count: number of vectors
1859 * @to: offset to write to
1860 * @retlen: pointer to variable to store the number of written bytes
1861 * @eccbuf: filesystem supplied oob data buffer
1862 * @oobsel: oob selection structure
1863 *
1864 * NAND write with iovec with ecc
1865 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001866static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1867 loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868{
1869 int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
1870 int oob, numpages, autoplace = 0, startpage;
1871 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001872 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 u_char *oobbuf, *bufstart;
1874
1875 /* Preset written len for early exit */
1876 *retlen = 0;
1877
1878 /* Calculate total length of data */
1879 total_len = 0;
1880 for (i = 0; i < count; i++)
David Woodhousee0c7d762006-05-13 18:07:53 +01001881 total_len += (int)vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
David Woodhousee0c7d762006-05-13 18:07:53 +01001883 DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
1885 /* Do not allow write past end of page */
1886 if ((to + total_len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001887 DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return -EINVAL;
1889 }
1890
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001891 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001892 if (NOTALIGNED(to) || NOTALIGNED(total_len)) {
1893 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 return -EINVAL;
1895 }
1896
1897 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001898 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* Get the current chip-nr */
David Woodhousee0c7d762006-05-13 18:07:53 +01001901 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 /* Select the NAND device */
1903 this->select_chip(mtd, chipnr);
1904
1905 /* Check, if it is write protected */
1906 if (nand_check_wp(mtd))
1907 goto out;
1908
1909 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001910 if (oobsel == NULL)
1911 oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 /* Autoplace of oob data ? Use the default placement scheme */
1914 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1915 oobsel = this->autooob;
1916 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001917 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001918 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1919 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921 /* Setup start page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001922 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001924 if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 this->pagebuf = -1;
1926
1927 startpage = page & this->pagemask;
1928
1929 /* Loop until all kvec' data has been written */
1930 len = 0;
1931 while (count) {
1932 /* If the given tuple is >= pagesize then
1933 * write it out from the iov
1934 */
1935 if ((vecs->iov_len - len) >= mtd->oobblock) {
1936 /* Calc number of pages we can write
1937 * out of this iov in one go */
1938 numpages = (vecs->iov_len - len) >> this->page_shift;
1939 /* Do not cross block boundaries */
David Woodhousee0c7d762006-05-13 18:07:53 +01001940 numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
1941 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
1942 bufstart = (u_char *) vecs->iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 bufstart += len;
1944 this->data_poi = bufstart;
1945 oob = 0;
1946 for (i = 1; i <= numpages; i++) {
1947 /* Write one page. If this is the last page to write
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001948 * then use the real pageprogram command, else select
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 * cached programming if supported by the chip.
1950 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001951 ret = nand_write_page(mtd, this, page & this->pagemask,
1952 &oobbuf[oob], oobsel, i != numpages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 if (ret)
1954 goto out;
1955 this->data_poi += mtd->oobblock;
1956 len += mtd->oobblock;
1957 oob += mtd->oobsize;
1958 page++;
1959 }
1960 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001961 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 vecs++;
1963 len = 0;
1964 count--;
1965 }
1966 } else {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001967 /* We must use the internal buffer, read data out of each
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 * tuple until we have a full page to write
1969 */
1970 int cnt = 0;
1971 while (cnt < mtd->oobblock) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001972 if (vecs->iov_base != NULL && vecs->iov_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
1974 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001975 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 vecs++;
1977 len = 0;
1978 count--;
1979 }
1980 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001981 this->pagebuf = page;
1982 this->data_poi = this->data_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 bufstart = this->data_poi;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001984 numpages = 1;
David Woodhousee0c7d762006-05-13 18:07:53 +01001985 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
1986 ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 if (ret)
1988 goto out;
1989 page++;
1990 }
1991
1992 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001993 ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 if (ret)
1995 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001996
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 written += mtd->oobblock * numpages;
1998 /* All done ? */
1999 if (!count)
2000 break;
2001
2002 startpage = page & this->pagemask;
2003 /* Check, if we cross a chip boundary */
2004 if (!startpage) {
2005 chipnr++;
2006 this->select_chip(mtd, -1);
2007 this->select_chip(mtd, chipnr);
2008 }
2009 }
2010 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002011 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 /* Deselect and wake up anyone waiting on the device */
2013 nand_release_device(mtd);
2014
2015 *retlen = written;
2016 return ret;
2017}
2018
2019/**
2020 * single_erease_cmd - [GENERIC] NAND standard block erase command function
2021 * @mtd: MTD device structure
2022 * @page: the page address of the block which will be erased
2023 *
2024 * Standard erase command for NAND chips
2025 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002026static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027{
2028 struct nand_chip *this = mtd->priv;
2029 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002030 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2031 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032}
2033
2034/**
2035 * multi_erease_cmd - [GENERIC] AND specific block erase command function
2036 * @mtd: MTD device structure
2037 * @page: the page address of the block which will be erased
2038 *
2039 * AND multi block erase command function
2040 * Erase 4 consecutive blocks
2041 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002042static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043{
2044 struct nand_chip *this = mtd->priv;
2045 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002046 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2047 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2048 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2049 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2050 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}
2052
2053/**
2054 * nand_erase - [MTD Interface] erase block(s)
2055 * @mtd: MTD device structure
2056 * @instr: erase instruction
2057 *
2058 * Erase one ore more blocks
2059 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002060static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061{
David Woodhousee0c7d762006-05-13 18:07:53 +01002062 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002064
David A. Marlin30f464b2005-01-17 18:35:25 +00002065#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066/**
2067 * nand_erase_intern - [NAND Interface] erase block(s)
2068 * @mtd: MTD device structure
2069 * @instr: erase instruction
2070 * @allowbbt: allow erasing the bbt area
2071 *
2072 * Erase one ore more blocks
2073 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002074int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 int page, len, status, pages_per_block, ret, chipnr;
2077 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00002078 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
2079 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
2080 /* It is used to see if the current page is in the same */
2081 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
David Woodhousee0c7d762006-05-13 18:07:53 +01002083 DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int)instr->addr, (unsigned int)instr->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085 /* Start address must align on block boundary */
2086 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002087 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 return -EINVAL;
2089 }
2090
2091 /* Length must align on block boundary */
2092 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002093 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 return -EINVAL;
2095 }
2096
2097 /* Do not allow erase past end of device */
2098 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002099 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 return -EINVAL;
2101 }
2102
2103 instr->fail_addr = 0xffffffff;
2104
2105 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002106 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01002109 page = (int)(instr->addr >> this->page_shift);
2110 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
2112 /* Calculate pages in each block */
2113 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
2114
2115 /* Select the NAND device */
2116 this->select_chip(mtd, chipnr);
2117
2118 /* Check the WP bit */
2119 /* Check, if it is write protected */
2120 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002121 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 instr->state = MTD_ERASE_FAILED;
2123 goto erase_exit;
2124 }
2125
David A. Marlin30f464b2005-01-17 18:35:25 +00002126 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
2127 if (this->options & BBT_AUTO_REFRESH) {
2128 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2129 } else {
2130 bbt_masked_page = 0xffffffff; /* should not match anything */
2131 }
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 /* Loop through the pages */
2134 len = instr->len;
2135
2136 instr->state = MTD_ERASING;
2137
2138 while (len) {
2139 /* Check if we have a bad block, we do not erase bad blocks ! */
2140 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002141 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 instr->state = MTD_ERASE_FAILED;
2143 goto erase_exit;
2144 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002145
2146 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 the current cached page */
2148 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
2149 this->pagebuf = -1;
2150
David Woodhousee0c7d762006-05-13 18:07:53 +01002151 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002152
David Woodhousee0c7d762006-05-13 18:07:53 +01002153 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
David A. Marlin068e3c02005-01-24 03:07:46 +00002155 /* See if operation failed and additional status checks are available */
2156 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2157 status = this->errstat(mtd, this, FL_ERASING, status, page);
2158 }
2159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00002161 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002162 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 instr->state = MTD_ERASE_FAILED;
2164 instr->fail_addr = (page << this->page_shift);
2165 goto erase_exit;
2166 }
David A. Marlin30f464b2005-01-17 18:35:25 +00002167
2168 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
2169 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002170 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00002171 (page != this->bbt_td->pages[chipnr])) {
2172 rewrite_bbt[chipnr] = (page << this->page_shift);
2173 }
2174 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002175
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 /* Increment page address and decrement length */
2177 len -= (1 << this->phys_erase_shift);
2178 page += pages_per_block;
2179
2180 /* Check, if we cross a chip boundary */
2181 if (len && !(page & this->pagemask)) {
2182 chipnr++;
2183 this->select_chip(mtd, -1);
2184 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00002185
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002186 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00002187 * set the BBT page mask to see if this BBT should be rewritten */
2188 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
2189 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2190 }
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193 }
2194 instr->state = MTD_ERASE_DONE;
2195
David Woodhousee0c7d762006-05-13 18:07:53 +01002196 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
2198 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
2199 /* Do call back function */
2200 if (!ret)
2201 mtd_erase_callback(instr);
2202
2203 /* Deselect and wake up anyone waiting on the device */
2204 nand_release_device(mtd);
2205
David A. Marlin30f464b2005-01-17 18:35:25 +00002206 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
2207 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
2208 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
2209 if (rewrite_bbt[chipnr]) {
2210 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01002211 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2212 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2213 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002214 }
2215 }
2216 }
2217
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 /* Return more or less happy */
2219 return ret;
2220}
2221
2222/**
2223 * nand_sync - [MTD Interface] sync
2224 * @mtd: MTD device structure
2225 *
2226 * Sync is actually a wait for chip ready function
2227 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002228static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229{
2230 struct nand_chip *this = mtd->priv;
2231
David Woodhousee0c7d762006-05-13 18:07:53 +01002232 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
2234 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002235 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002237 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238}
2239
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240/**
2241 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2242 * @mtd: MTD device structure
2243 * @ofs: offset relative to mtd start
2244 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002245static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246{
2247 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002248 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002250
David Woodhousee0c7d762006-05-13 18:07:53 +01002251 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
2254/**
2255 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2256 * @mtd: MTD device structure
2257 * @ofs: offset relative to mtd start
2258 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002259static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260{
2261 struct nand_chip *this = mtd->priv;
2262 int ret;
2263
David Woodhousee0c7d762006-05-13 18:07:53 +01002264 if ((ret = nand_block_isbad(mtd, ofs))) {
2265 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 if (ret > 0)
2267 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002268 return ret;
2269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
2271 return this->block_markbad(mtd, ofs);
2272}
2273
2274/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002275 * nand_suspend - [MTD Interface] Suspend the NAND flash
2276 * @mtd: MTD device structure
2277 */
2278static int nand_suspend(struct mtd_info *mtd)
2279{
2280 struct nand_chip *this = mtd->priv;
2281
David Woodhousee0c7d762006-05-13 18:07:53 +01002282 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002283}
2284
2285/**
2286 * nand_resume - [MTD Interface] Resume the NAND flash
2287 * @mtd: MTD device structure
2288 */
2289static void nand_resume(struct mtd_info *mtd)
2290{
2291 struct nand_chip *this = mtd->priv;
2292
2293 if (this->state == FL_PM_SUSPENDED)
2294 nand_release_device(mtd);
2295 else
David Woodhousee0c7d762006-05-13 18:07:53 +01002296 printk(KERN_ERR "resume() called for the chip which is not in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002297
2298}
2299
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002300/*
2301 * Free allocated data structures
2302 */
2303static void nand_free_kmem(struct nand_chip *this)
2304{
2305 /* Buffer allocated by nand_scan ? */
2306 if (this->options & NAND_OOBBUF_ALLOC)
2307 kfree(this->oob_buf);
2308 /* Buffer allocated by nand_scan ? */
2309 if (this->options & NAND_DATABUF_ALLOC)
2310 kfree(this->data_buf);
2311 /* Controller allocated by nand_scan ? */
2312 if (this->options & NAND_CONTROLLER_ALLOC)
2313 kfree(this->controller);
2314}
2315
David Woodhouse52239da2006-05-14 16:54:39 +01002316/* module_text_address() isn't exported, and it's mostly a pointless
2317 test if this is a module _anyway_ -- they'd have to try _really_ hard
2318 to call us from in-kernel code if the core NAND support is modular. */
2319#ifdef MODULE
2320#define caller_is_module() (1)
2321#else
2322#define caller_is_module() module_text_address((unsigned long)__builtin_return_address(0))
2323#endif
2324
Vitaly Wool962034f2005-09-15 14:58:53 +01002325/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 * nand_scan - [NAND Interface] Scan for the NAND device
2327 * @mtd: MTD device structure
2328 * @maxchips: Number of chips to scan for
2329 *
David Woodhouse552d9202006-05-14 01:20:46 +01002330 * This fills out all the uninitialized function pointers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 * with the defaults.
2332 * The flash ID is read and the mtd/chip structures are
2333 * filled with the appropriate values. Buffers are allocated if
2334 * they are not provided by the board driver
David Woodhouse552d9202006-05-14 01:20:46 +01002335 * The mtd->owner field must be set to the module of the caller
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 *
2337 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002338int nand_scan(struct mtd_info *mtd, int maxchips)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339{
Ben Dooks3b946e32005-03-14 18:30:48 +00002340 int i, nand_maf_id, nand_dev_id, busw, maf_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 struct nand_chip *this = mtd->priv;
2342
David Woodhouse52239da2006-05-14 16:54:39 +01002343 /* Many callers got this wrong, so check for it for a while... */
2344 if (!mtd->owner && caller_is_module()) {
David Woodhouse552d9202006-05-14 01:20:46 +01002345 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2346 BUG();
2347 }
2348
David Woodhousee0c7d762006-05-13 18:07:53 +01002349 /* Get buswidth to select the correct functions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 busw = this->options & NAND_BUSWIDTH_16;
2351
2352 /* check for proper chip_delay setup, set 20us if not */
2353 if (!this->chip_delay)
2354 this->chip_delay = 20;
2355
2356 /* check, if a user supplied command function given */
2357 if (this->cmdfunc == NULL)
2358 this->cmdfunc = nand_command;
2359
2360 /* check, if a user supplied wait function given */
2361 if (this->waitfunc == NULL)
2362 this->waitfunc = nand_wait;
2363
2364 if (!this->select_chip)
2365 this->select_chip = nand_select_chip;
2366 if (!this->write_byte)
2367 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
2368 if (!this->read_byte)
2369 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2370 if (!this->write_word)
2371 this->write_word = nand_write_word;
2372 if (!this->read_word)
2373 this->read_word = nand_read_word;
2374 if (!this->block_bad)
2375 this->block_bad = nand_block_bad;
2376 if (!this->block_markbad)
2377 this->block_markbad = nand_default_block_markbad;
2378 if (!this->write_buf)
2379 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2380 if (!this->read_buf)
2381 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2382 if (!this->verify_buf)
2383 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2384 if (!this->scan_bbt)
2385 this->scan_bbt = nand_default_bbt;
2386
2387 /* Select the device */
2388 this->select_chip(mtd, 0);
2389
2390 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002391 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
2393 /* Read manufacturer and device IDs */
2394 nand_maf_id = this->read_byte(mtd);
2395 nand_dev_id = this->read_byte(mtd);
2396
2397 /* Print and store flash device information */
2398 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002399
2400 if (nand_dev_id != nand_flash_ids[i].id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 continue;
2402
David Woodhousee0c7d762006-05-13 18:07:53 +01002403 if (!mtd->name)
2404 mtd->name = nand_flash_ids[i].name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 this->chipsize = nand_flash_ids[i].chipsize << 20;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 /* New devices have all the information in additional id bytes */
2408 if (!nand_flash_ids[i].pagesize) {
2409 int extid;
2410 /* The 3rd id byte contains non relevant data ATM */
2411 extid = this->read_byte(mtd);
2412 /* The 4th id byte is the important one */
2413 extid = this->read_byte(mtd);
2414 /* Calc pagesize */
2415 mtd->oobblock = 1024 << (extid & 0x3);
2416 extid >>= 2;
2417 /* Calc oobsize */
Thomas Gleixnerd4094662005-08-11 18:13:46 +01002418 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 extid >>= 2;
2420 /* Calc blocksize. Blocksize is multiples of 64KiB */
David Woodhousee0c7d762006-05-13 18:07:53 +01002421 mtd->erasesize = (64 * 1024) << (extid & 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 extid >>= 2;
2423 /* Get buswidth information */
2424 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002425
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 } else {
2427 /* Old devices have this data hardcoded in the
2428 * device id table */
2429 mtd->erasesize = nand_flash_ids[i].erasesize;
2430 mtd->oobblock = nand_flash_ids[i].pagesize;
2431 mtd->oobsize = mtd->oobblock / 32;
2432 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2433 }
2434
Kyungmin Park0ea4a752005-02-16 09:39:39 +00002435 /* Try to identify manufacturer */
2436 for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
2437 if (nand_manuf_ids[maf_id].id == nand_maf_id)
2438 break;
2439 }
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 /* Check, if buswidth is correct. Hardware drivers should set
2442 * this correct ! */
2443 if (busw != (this->options & NAND_BUSWIDTH_16)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002444 printk(KERN_INFO "NAND device: Manufacturer ID:"
2445 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2446 nand_manuf_ids[maf_id].name, mtd->name);
2447 printk(KERN_WARNING
2448 "NAND bus width %d instead %d bit\n",
2449 (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 this->select_chip(mtd, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002451 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002453
2454 /* Calculate the address shift from the page size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 this->page_shift = ffs(mtd->oobblock) - 1;
2456 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
2457 this->chip_shift = ffs(this->chipsize) - 1;
2458
2459 /* Set the bad block position */
David Woodhousee0c7d762006-05-13 18:07:53 +01002460 this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 /* Get chip options, preserve non chip based options */
2463 this->options &= ~NAND_CHIPOPTIONS_MSK;
2464 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
David Woodhousee0c7d762006-05-13 18:07:53 +01002465 /* Set this as a default. Board drivers can override it, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 this->options |= NAND_NO_AUTOINCR;
2467 /* Check if this is a not a samsung device. Do not clear the options
2468 * for chips which are not having an extended id.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002469 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2471 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 /* Check for AND chips with 4 page planes */
2474 if (this->options & NAND_4PAGE_ARRAY)
2475 this->erase_cmd = multi_erase_cmd;
2476 else
2477 this->erase_cmd = single_erase_cmd;
2478
2479 /* Do not replace user supplied command function ! */
2480 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
2481 this->cmdfunc = nand_command_lp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002482
David Woodhousee0c7d762006-05-13 18:07:53 +01002483 printk(KERN_INFO "NAND device: Manufacturer ID:"
2484 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2485 nand_manuf_ids[maf_id].name, nand_flash_ids[i].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 break;
2487 }
2488
2489 if (!nand_flash_ids[i].name) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002490 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 this->select_chip(mtd, -1);
2492 return 1;
2493 }
2494
David Woodhousee0c7d762006-05-13 18:07:53 +01002495 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 this->select_chip(mtd, i);
2497
2498 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002499 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 /* Read manufacturer and device IDs */
2502 if (nand_maf_id != this->read_byte(mtd) ||
2503 nand_dev_id != this->read_byte(mtd))
2504 break;
2505 }
2506 if (i > 1)
2507 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002508
David Woodhousee0c7d762006-05-13 18:07:53 +01002509 /* Allocate buffers, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 if (!this->oob_buf) {
2511 size_t len;
2512 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
David Woodhousee0c7d762006-05-13 18:07:53 +01002513 this->oob_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 if (!this->oob_buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002515 printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 return -ENOMEM;
2517 }
2518 this->options |= NAND_OOBBUF_ALLOC;
2519 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (!this->data_buf) {
2522 size_t len;
2523 len = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01002524 this->data_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 if (!this->data_buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002526 printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002527 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 return -ENOMEM;
2529 }
2530 this->options |= NAND_DATABUF_ALLOC;
2531 }
2532
2533 /* Store the number of chips and calc total size for mtd */
2534 this->numchips = i;
2535 mtd->size = i * this->chipsize;
2536 /* Convert chipsize to number of pages per chip -1. */
2537 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2538 /* Preset the internal oob buffer */
2539 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2540
2541 /* If no default placement scheme is given, select an
2542 * appropriate one */
2543 if (!this->autooob) {
2544 /* Select the appropriate default oob placement scheme for
2545 * placement agnostic filesystems */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002546 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 case 8:
2548 this->autooob = &nand_oob_8;
2549 break;
2550 case 16:
2551 this->autooob = &nand_oob_16;
2552 break;
2553 case 64:
2554 this->autooob = &nand_oob_64;
2555 break;
2556 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002557 printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 BUG();
2559 }
2560 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002561
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 /* The number of bytes available for the filesystem to place fs dependend
2563 * oob data */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002564 mtd->oobavail = 0;
2565 for (i = 0; this->autooob->oobfree[i][1]; i++)
2566 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002568 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 * check ECC mode, default to software
2570 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002571 * fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002572 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002573 this->eccsize = 256; /* set default eccsize */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 this->eccbytes = 3;
2575
2576 switch (this->eccmode) {
2577 case NAND_ECC_HW12_2048:
2578 if (mtd->oobblock < 2048) {
2579 printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
2580 mtd->oobblock);
2581 this->eccmode = NAND_ECC_SOFT;
2582 this->calculate_ecc = nand_calculate_ecc;
2583 this->correct_data = nand_correct_data;
2584 } else
2585 this->eccsize = 2048;
2586 break;
2587
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002588 case NAND_ECC_HW3_512:
2589 case NAND_ECC_HW6_512:
2590 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 if (mtd->oobblock == 256) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002592 printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 this->eccmode = NAND_ECC_SOFT;
2594 this->calculate_ecc = nand_calculate_ecc;
2595 this->correct_data = nand_correct_data;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002596 } else
David Woodhousee0c7d762006-05-13 18:07:53 +01002597 this->eccsize = 512; /* set eccsize to 512 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002599
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 case NAND_ECC_HW3_256:
2601 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002602
2603 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +01002604 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 this->eccmode = NAND_ECC_NONE;
2606 break;
2607
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002608 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 this->calculate_ecc = nand_calculate_ecc;
2610 this->correct_data = nand_correct_data;
2611 break;
2612
2613 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002614 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002615 BUG();
2616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002618 /* Check hardware ecc function availability and adjust number of ecc bytes per
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 * calculation step
David Woodhousee0c7d762006-05-13 18:07:53 +01002620 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 switch (this->eccmode) {
2622 case NAND_ECC_HW12_2048:
2623 this->eccbytes += 4;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002624 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 this->eccbytes += 2;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002626 case NAND_ECC_HW6_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 this->eccbytes += 3;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002628 case NAND_ECC_HW3_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 case NAND_ECC_HW3_256:
2630 if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
2631 break;
David Woodhousee0c7d762006-05-13 18:07:53 +01002632 printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002633 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 mtd->eccsize = this->eccsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002637
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 /* Set the number of read / write steps for one page to ensure ECC generation */
2639 switch (this->eccmode) {
2640 case NAND_ECC_HW12_2048:
2641 this->eccsteps = mtd->oobblock / 2048;
2642 break;
2643 case NAND_ECC_HW3_512:
2644 case NAND_ECC_HW6_512:
2645 case NAND_ECC_HW8_512:
2646 this->eccsteps = mtd->oobblock / 512;
2647 break;
2648 case NAND_ECC_HW3_256:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002649 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 this->eccsteps = mtd->oobblock / 256;
2651 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002652
2653 case NAND_ECC_NONE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 this->eccsteps = 1;
2655 break;
2656 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /* Initialize state, waitqueue and spinlock */
2659 this->state = FL_READY;
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002660 if (!this->controller) {
2661 this->controller = kzalloc(sizeof(struct nand_hw_control),
2662 GFP_KERNEL);
2663 if (!this->controller) {
2664 nand_free_kmem(this);
2665 return -ENOMEM;
2666 }
2667 this->options |= NAND_CONTROLLER_ALLOC;
2668 }
2669 init_waitqueue_head(&this->controller->wq);
2670 spin_lock_init(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
2672 /* De-select the device */
2673 this->select_chip(mtd, -1);
2674
2675 /* Invalidate the pagebuffer reference */
2676 this->pagebuf = -1;
2677
2678 /* Fill in remaining MTD driver data */
2679 mtd->type = MTD_NANDFLASH;
2680 mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
2681 mtd->ecctype = MTD_ECC_SW;
2682 mtd->erase = nand_erase;
2683 mtd->point = NULL;
2684 mtd->unpoint = NULL;
2685 mtd->read = nand_read;
2686 mtd->write = nand_write;
2687 mtd->read_ecc = nand_read_ecc;
2688 mtd->write_ecc = nand_write_ecc;
2689 mtd->read_oob = nand_read_oob;
2690 mtd->write_oob = nand_write_oob;
2691 mtd->readv = NULL;
2692 mtd->writev = nand_writev;
2693 mtd->writev_ecc = nand_writev_ecc;
2694 mtd->sync = nand_sync;
2695 mtd->lock = NULL;
2696 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002697 mtd->suspend = nand_suspend;
2698 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 mtd->block_isbad = nand_block_isbad;
2700 mtd->block_markbad = nand_block_markbad;
2701
2702 /* and make the autooob the default one */
2703 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2704
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002705 /* Check, if we should skip the bad block table scan */
2706 if (this->options & NAND_SKIP_BBTSCAN)
2707 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002710 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711}
2712
2713/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002714 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 * @mtd: MTD device structure
2716*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002717void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718{
2719 struct nand_chip *this = mtd->priv;
2720
2721#ifdef CONFIG_MTD_PARTITIONS
2722 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002723 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724#endif
2725 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002726 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Jesper Juhlfa671642005-11-07 01:01:27 -08002728 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002729 kfree(this->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002730 /* Free buffers */
2731 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732}
2733
David Woodhousee0c7d762006-05-13 18:07:53 +01002734EXPORT_SYMBOL_GPL(nand_scan);
2735EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002736
2737static int __init nand_base_init(void)
2738{
2739 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2740 return 0;
2741}
2742
2743static void __exit nand_base_exit(void)
2744{
2745 led_trigger_unregister_simple(nand_led_trigger);
2746}
2747
2748module_init(nand_base_init);
2749module_exit(nand_base_exit);
2750
David Woodhousee0c7d762006-05-13 18:07:53 +01002751MODULE_LICENSE("GPL");
2752MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2753MODULE_DESCRIPTION("Generic NAND flash driver code");