blob: 6ef1893996ce7a6de6b9d57199872304217f2f25 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/mtd/nand.c
3 *
4 * Overview:
5 * This is the generic MTD driver for NAND flash devices. It should be
6 * capable of working with almost all NAND chips currently available.
7 * Basic support for AG-AND chips is provided.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Additional technical information is available on
10 * http://www.linux-mtd.infradead.org/tech/nand.html
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000011 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020013 * 2002 Thomas Gleixner (tglx@linutronix.de)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
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
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020028 * among multiple independend devices. Suggestions and initial
29 * patch from Ben Dooks <ben-mtd@fluff.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 *
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020031 * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb"
32 * issue. Basically, any block not rewritten may lose data when
33 * surrounding blocks are rewritten many times. JFFS2 ensures
34 * this doesn't happen for blocks it uses, but the Bad Block
35 * Table(s) may not be rewritten. To ensure they do not lose
36 * data, force them to be rewritten when some of the surrounding
37 * blocks are erased. Rather than tracking a specific nearby
38 * block (which could itself go bad), use a page address 'mask' to
39 * select several blocks in the same area, and rewrite the BBT
40 * when any of them are erased.
David A. Marlin30f464b2005-01-17 18:35:25 +000041 *
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020042 * 01-03-2005 dmarlin: added support for the device recovery command sequence
43 * for Renesas AG-AND chips. If there was a sudden loss of power
44 * during an erase operation, a "device recovery" operation must
45 * be performed when power is restored to ensure correct
46 * operation.
David A. Marlin30f464b2005-01-17 18:35:25 +000047 *
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020048 * 01-20-2005 dmarlin: added support for optional hardware specific callback
49 * routine to perform extra error status checks on erase and write
50 * failures. This required adding a wrapper function for
51 * nand_read_ecc.
David A. Marlin068e3c02005-01-24 03:07:46 +000052 *
Vitaly Wool962034f2005-09-15 14:58:53 +010053 * 08-20-2005 vwool: suspend/resume added
54 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 * Credits:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000056 * David Woodhouse for adding multichip support
57 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
59 * rework for 2K page size chips
60 *
61 * TODO:
62 * Enable cached programming for 2k page size chips
63 * Check, if mtd->ecctype should be set to MTD_ECC_HW
64 * if we have HW ecc support.
65 * The AG-AND chips have nice features for speed improvement,
66 * which are not supported yet. Read / program 4 pages in one go.
67 *
Vitaly Wool962034f2005-09-15 14:58:53 +010068 * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *
70 * This program is free software; you can redistribute it and/or modify
71 * it under the terms of the GNU General Public License version 2 as
72 * published by the Free Software Foundation.
73 *
74 */
75
David Woodhouse552d9202006-05-14 01:20:46 +010076#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#include <linux/delay.h>
78#include <linux/errno.h>
79#include <linux/sched.h>
80#include <linux/slab.h>
81#include <linux/types.h>
82#include <linux/mtd/mtd.h>
83#include <linux/mtd/nand.h>
84#include <linux/mtd/nand_ecc.h>
85#include <linux/mtd/compatmac.h>
86#include <linux/interrupt.h>
87#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080088#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#include <asm/io.h>
90
91#ifdef CONFIG_MTD_PARTITIONS
92#include <linux/mtd/partitions.h>
93#endif
94
95/* Define default oob placement schemes for large and small page devices */
96static struct nand_oobinfo nand_oob_8 = {
97 .useecc = MTD_NANDECC_AUTOPLACE,
98 .eccbytes = 3,
99 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +0100100 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101};
102
103static struct nand_oobinfo nand_oob_16 = {
104 .useecc = MTD_NANDECC_AUTOPLACE,
105 .eccbytes = 6,
106 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +0100107 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110static struct nand_oobinfo nand_oob_64 = {
111 .useecc = MTD_NANDECC_AUTOPLACE,
112 .eccbytes = 24,
113 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +0100114 40, 41, 42, 43, 44, 45, 46, 47,
115 48, 49, 50, 51, 52, 53, 54, 55,
116 56, 57, 58, 59, 60, 61, 62, 63},
117 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
119
120/* This is used for padding purposes in nand_write_oob */
121static u_char ffchars[] = {
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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130};
131
132/*
133 * NAND low-level MTD interface functions
134 */
135static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
136static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
137static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
138
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200139static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
140 size_t *retlen, u_char *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100141static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200142 size_t *retlen, u_char *buf, u_char *eccbuf,
143 struct nand_oobinfo *oobsel);
144static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
145 size_t *retlen, u_char *buf);
146static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
147 size_t *retlen, const u_char *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100148static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200149 size_t *retlen, const u_char *buf, u_char *eccbuf,
150 struct nand_oobinfo *oobsel);
151static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
152 size_t *retlen, const u_char *buf);
153static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs,
154 unsigned long count, loff_t to, size_t *retlen);
David Woodhousee0c7d762006-05-13 18:07:53 +0100155static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200156 unsigned long count, loff_t to, size_t *retlen,
157 u_char *eccbuf, struct nand_oobinfo *oobsel);
David Woodhousee0c7d762006-05-13 18:07:53 +0100158static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
159static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161/* Some internal functions */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200162static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this,
163 int page, u_char * oob_buf,
David Woodhousee0c7d762006-05-13 18:07:53 +0100164 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200166static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this,
167 int page, int numpages, u_char *oob_buf,
168 struct nand_oobinfo *oobsel, int chipnr,
169 int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170#else
171#define nand_verify_pages(...) (0)
172#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000173
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200174static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd,
175 int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177/**
178 * nand_release_device - [GENERIC] release chip
179 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000180 *
181 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100183static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
185 struct nand_chip *this = mtd->priv;
186
187 /* De-select the NAND device */
188 this->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100189
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200190 /* Release the controller and the chip */
191 spin_lock(&this->controller->lock);
192 this->controller->active = NULL;
193 this->state = FL_READY;
194 wake_up(&this->controller->wq);
195 spin_unlock(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
198/**
199 * nand_read_byte - [DEFAULT] read one byte from the chip
200 * @mtd: MTD device structure
201 *
202 * Default read function for 8bit buswith
203 */
204static u_char nand_read_byte(struct mtd_info *mtd)
205{
206 struct nand_chip *this = mtd->priv;
207 return readb(this->IO_ADDR_R);
208}
209
210/**
211 * nand_write_byte - [DEFAULT] write one byte to the chip
212 * @mtd: MTD device structure
213 * @byte: pointer to data byte to write
214 *
215 * Default write function for 8it buswith
216 */
217static void nand_write_byte(struct mtd_info *mtd, u_char byte)
218{
219 struct nand_chip *this = mtd->priv;
220 writeb(byte, this->IO_ADDR_W);
221}
222
223/**
224 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
225 * @mtd: MTD device structure
226 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000227 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 * endianess conversion
229 */
230static u_char nand_read_byte16(struct mtd_info *mtd)
231{
232 struct nand_chip *this = mtd->priv;
233 return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
234}
235
236/**
237 * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
238 * @mtd: MTD device structure
239 * @byte: pointer to data byte to write
240 *
241 * Default write function for 16bit buswith with
242 * endianess conversion
243 */
244static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
245{
246 struct nand_chip *this = mtd->priv;
247 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
248}
249
250/**
251 * nand_read_word - [DEFAULT] read one word from the chip
252 * @mtd: MTD device structure
253 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000254 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 * endianess conversion
256 */
257static u16 nand_read_word(struct mtd_info *mtd)
258{
259 struct nand_chip *this = mtd->priv;
260 return readw(this->IO_ADDR_R);
261}
262
263/**
264 * nand_write_word - [DEFAULT] write one word to the chip
265 * @mtd: MTD device structure
266 * @word: data word to write
267 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000268 * Default write function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 * endianess conversion
270 */
271static void nand_write_word(struct mtd_info *mtd, u16 word)
272{
273 struct nand_chip *this = mtd->priv;
274 writew(word, this->IO_ADDR_W);
275}
276
277/**
278 * nand_select_chip - [DEFAULT] control CE line
279 * @mtd: MTD device structure
280 * @chip: chipnumber to select, -1 for deselect
281 *
282 * Default select function for 1 chip devices.
283 */
284static void nand_select_chip(struct mtd_info *mtd, int chip)
285{
286 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100287 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 case -1:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000289 this->hwcontrol(mtd, NAND_CTL_CLRNCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 break;
291 case 0:
292 this->hwcontrol(mtd, NAND_CTL_SETNCE);
293 break;
294
295 default:
296 BUG();
297 }
298}
299
300/**
301 * nand_write_buf - [DEFAULT] write buffer to chip
302 * @mtd: MTD device structure
303 * @buf: data buffer
304 * @len: number of bytes to write
305 *
306 * Default write function for 8bit buswith
307 */
308static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
309{
310 int i;
311 struct nand_chip *this = mtd->priv;
312
David Woodhousee0c7d762006-05-13 18:07:53 +0100313 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 writeb(buf[i], this->IO_ADDR_W);
315}
316
317/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000318 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 * @mtd: MTD device structure
320 * @buf: buffer to store date
321 * @len: number of bytes to read
322 *
323 * Default read function for 8bit buswith
324 */
325static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
326{
327 int i;
328 struct nand_chip *this = mtd->priv;
329
David Woodhousee0c7d762006-05-13 18:07:53 +0100330 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 buf[i] = readb(this->IO_ADDR_R);
332}
333
334/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000335 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 * @mtd: MTD device structure
337 * @buf: buffer containing the data to compare
338 * @len: number of bytes to compare
339 *
340 * Default verify function for 8bit buswith
341 */
342static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
343{
344 int i;
345 struct nand_chip *this = mtd->priv;
346
David Woodhousee0c7d762006-05-13 18:07:53 +0100347 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (buf[i] != readb(this->IO_ADDR_R))
349 return -EFAULT;
350
351 return 0;
352}
353
354/**
355 * nand_write_buf16 - [DEFAULT] write buffer to chip
356 * @mtd: MTD device structure
357 * @buf: data buffer
358 * @len: number of bytes to write
359 *
360 * Default write function for 16bit buswith
361 */
362static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
363{
364 int i;
365 struct nand_chip *this = mtd->priv;
366 u16 *p = (u16 *) buf;
367 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000368
David Woodhousee0c7d762006-05-13 18:07:53 +0100369 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
374/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000375 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 * @mtd: MTD device structure
377 * @buf: buffer to store date
378 * @len: number of bytes to read
379 *
380 * Default read function for 16bit buswith
381 */
382static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
383{
384 int i;
385 struct nand_chip *this = mtd->priv;
386 u16 *p = (u16 *) buf;
387 len >>= 1;
388
David Woodhousee0c7d762006-05-13 18:07:53 +0100389 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 p[i] = readw(this->IO_ADDR_R);
391}
392
393/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000394 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 * @mtd: MTD device structure
396 * @buf: buffer containing the data to compare
397 * @len: number of bytes to compare
398 *
399 * Default verify function for 16bit buswith
400 */
401static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
402{
403 int i;
404 struct nand_chip *this = mtd->priv;
405 u16 *p = (u16 *) buf;
406 len >>= 1;
407
David Woodhousee0c7d762006-05-13 18:07:53 +0100408 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 if (p[i] != readw(this->IO_ADDR_R))
410 return -EFAULT;
411
412 return 0;
413}
414
415/**
416 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
417 * @mtd: MTD device structure
418 * @ofs: offset from device start
419 * @getchip: 0, if the chip is already selected
420 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000421 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 */
423static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
424{
425 int page, chipnr, res = 0;
426 struct nand_chip *this = mtd->priv;
427 u16 bad;
428
429 if (getchip) {
430 page = (int)(ofs >> this->page_shift);
431 chipnr = (int)(ofs >> this->chip_shift);
432
433 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100434 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 /* Select the NAND device */
437 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000438 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100439 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 if (this->options & NAND_BUSWIDTH_16) {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200442 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
443 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 bad = cpu_to_le16(this->read_word(mtd));
445 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000446 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if ((bad & 0xFF) != 0xff)
448 res = 1;
449 } else {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200450 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
451 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (this->read_byte(mtd) != 0xff)
453 res = 1;
454 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (getchip) {
457 /* Deselect and wake up anyone waiting on the device */
458 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000459 }
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return res;
462}
463
464/**
465 * nand_default_block_markbad - [DEFAULT] mark a block bad
466 * @mtd: MTD device structure
467 * @ofs: offset from device start
468 *
469 * This is the default implementation, which can be overridden by
470 * a hardware specific driver.
471*/
472static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
473{
474 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100475 u_char buf[2] = { 0, 0 };
476 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100480 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000481 if (this->bbt)
482 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 /* Do we have a flash based bad block table ? */
485 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100486 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 /* We write two bytes, so we dont have to mess with 16 bit access */
489 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100490 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000493/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 * nand_check_wp - [GENERIC] check if the chip is write protected
495 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000496 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000498 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100500static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 struct nand_chip *this = mtd->priv;
503 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100504 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000505 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508/**
509 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
510 * @mtd: MTD device structure
511 * @ofs: offset from device start
512 * @getchip: 0, if the chip is already selected
513 * @allowbbt: 1, if its allowed to access the bbt area
514 *
515 * Check, if the block is bad. Either by reading the bad block table or
516 * calling of the scan function.
517 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200518static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
519 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
521 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (!this->bbt)
524 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100527 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528}
529
Richard Purdie8fe833c2006-03-31 02:31:14 -0800530DEFINE_LED_TRIGGER(nand_led_trigger);
531
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000532/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000533 * Wait for the ready pin, after a command
534 * The timeout is catched later.
535 */
536static void nand_wait_ready(struct mtd_info *mtd)
537{
538 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100539 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000540
Richard Purdie8fe833c2006-03-31 02:31:14 -0800541 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000542 /* wait until command is processed or timeout occures */
543 do {
544 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800545 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700546 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000547 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800548 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000549}
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551/**
552 * nand_command - [DEFAULT] Send command to NAND device
553 * @mtd: MTD device structure
554 * @command: the command to be sent
555 * @column: the column address for this command, -1 if none
556 * @page_addr: the page address for this command, -1 if none
557 *
558 * Send command to NAND device. This function is used for small page
559 * devices (256/512 Bytes per page)
560 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200561static void nand_command(struct mtd_info *mtd, unsigned command, int column,
562 int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 register struct nand_chip *this = mtd->priv;
565
566 /* Begin command latch cycle */
567 this->hwcontrol(mtd, NAND_CTL_SETCLE);
568 /*
569 * Write out the command to the device.
570 */
571 if (command == NAND_CMD_SEQIN) {
572 int readcmd;
573
574 if (column >= mtd->oobblock) {
575 /* OOB area */
576 column -= mtd->oobblock;
577 readcmd = NAND_CMD_READOOB;
578 } else if (column < 256) {
579 /* First 256 bytes --> READ0 */
580 readcmd = NAND_CMD_READ0;
581 } else {
582 column -= 256;
583 readcmd = NAND_CMD_READ1;
584 }
585 this->write_byte(mtd, readcmd);
586 }
587 this->write_byte(mtd, command);
588
589 /* Set ALE and clear CLE to start address cycle */
590 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
591
592 if (column != -1 || page_addr != -1) {
593 this->hwcontrol(mtd, NAND_CTL_SETALE);
594
595 /* Serially input address */
596 if (column != -1) {
597 /* Adjust columns for 16 bit buswidth */
598 if (this->options & NAND_BUSWIDTH_16)
599 column >>= 1;
600 this->write_byte(mtd, column);
601 }
602 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100603 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
604 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 /* One more address cycle for devices > 32MiB */
606 if (this->chipsize > (32 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100607 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609 /* Latch in address */
610 this->hwcontrol(mtd, NAND_CTL_CLRALE);
611 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000612
613 /*
614 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100616 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 case NAND_CMD_PAGEPROG:
620 case NAND_CMD_ERASE1:
621 case NAND_CMD_ERASE2:
622 case NAND_CMD_SEQIN:
623 case NAND_CMD_STATUS:
624 return;
625
626 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000627 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 break;
629 udelay(this->chip_delay);
630 this->hwcontrol(mtd, NAND_CTL_SETCLE);
631 this->write_byte(mtd, NAND_CMD_STATUS);
632 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100633 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return;
635
David Woodhousee0c7d762006-05-13 18:07:53 +0100636 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000638 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 * If we don't have access to the busy pin, we apply the given
640 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100641 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100643 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 /* Apply this short delay always to ensure that we do wait tWB in
648 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100649 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000650
651 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
654/**
655 * nand_command_lp - [DEFAULT] Send command to NAND large page device
656 * @mtd: MTD device structure
657 * @command: the command to be sent
658 * @column: the column address for this command, -1 if none
659 * @page_addr: the page address for this command, -1 if none
660 *
661 * Send command to NAND device. This is the version for the new large page devices
David Woodhousee0c7d762006-05-13 18:07:53 +0100662 * We dont have the separate regions as we have in the small page devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 * We must emulate NAND_CMD_READOOB to keep the code compatible.
664 *
665 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100666static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 register struct nand_chip *this = mtd->priv;
669
670 /* Emulate NAND_CMD_READOOB */
671 if (command == NAND_CMD_READOOB) {
672 column += mtd->oobblock;
673 command = NAND_CMD_READ0;
674 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /* Begin command latch cycle */
677 this->hwcontrol(mtd, NAND_CTL_SETCLE);
678 /* Write out the command to the device. */
David A. Marlin30f464b2005-01-17 18:35:25 +0000679 this->write_byte(mtd, (command & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 /* End command latch cycle */
681 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
682
683 if (column != -1 || page_addr != -1) {
684 this->hwcontrol(mtd, NAND_CTL_SETALE);
685
686 /* Serially input address */
687 if (column != -1) {
688 /* Adjust columns for 16 bit buswidth */
689 if (this->options & NAND_BUSWIDTH_16)
690 column >>= 1;
691 this->write_byte(mtd, column & 0xff);
692 this->write_byte(mtd, column >> 8);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100695 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
696 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /* One more address cycle for devices > 128MiB */
698 if (this->chipsize > (128 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100699 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
701 /* Latch in address */
702 this->hwcontrol(mtd, NAND_CTL_CLRALE);
703 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000704
705 /*
706 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000707 * status, sequential in, and deplete1 need no delay
708 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 case NAND_CMD_CACHEDPROG:
712 case NAND_CMD_PAGEPROG:
713 case NAND_CMD_ERASE1:
714 case NAND_CMD_ERASE2:
715 case NAND_CMD_SEQIN:
716 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000717 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return;
719
David Woodhousee0c7d762006-05-13 18:07:53 +0100720 /*
721 * read error status commands require only a short delay
722 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000723 case NAND_CMD_STATUS_ERROR:
724 case NAND_CMD_STATUS_ERROR0:
725 case NAND_CMD_STATUS_ERROR1:
726 case NAND_CMD_STATUS_ERROR2:
727 case NAND_CMD_STATUS_ERROR3:
728 udelay(this->chip_delay);
729 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000732 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 break;
734 udelay(this->chip_delay);
735 this->hwcontrol(mtd, NAND_CTL_SETCLE);
736 this->write_byte(mtd, NAND_CMD_STATUS);
737 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100738 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
740
741 case NAND_CMD_READ0:
742 /* Begin command latch cycle */
743 this->hwcontrol(mtd, NAND_CTL_SETCLE);
744 /* Write out the start read command */
745 this->write_byte(mtd, NAND_CMD_READSTART);
746 /* End command latch cycle */
747 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
748 /* Fall through into ready check */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000749
David Woodhousee0c7d762006-05-13 18:07:53 +0100750 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000752 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 * If we don't have access to the busy pin, we apply the given
754 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100755 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100757 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 /* Apply this short delay always to ensure that we do wait tWB in
763 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100764 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000765
766 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767}
768
769/**
770 * nand_get_device - [GENERIC] Get chip for selected access
771 * @this: the nand chip descriptor
772 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000773 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 *
775 * Get the device and lock it for exclusive access
776 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200777static int
778nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200780 spinlock_t *lock = &this->controller->lock;
781 wait_queue_head_t *wq = &this->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100782 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100783 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100784 spin_lock(lock);
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200787 /* Hardware controller shared among independend devices */
788 if (!this->controller->active)
789 this->controller->active = this;
790
791 if (this->controller->active == this && this->state == FL_READY) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100792 this->state = new_state;
793 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100794 return 0;
795 }
796 if (new_state == FL_PM_SUSPENDED) {
797 spin_unlock(lock);
798 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100799 }
800 set_current_state(TASK_UNINTERRUPTIBLE);
801 add_wait_queue(wq, &wait);
802 spin_unlock(lock);
803 schedule();
804 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 goto retry;
806}
807
808/**
809 * nand_wait - [DEFAULT] wait until the command is done
810 * @mtd: MTD device structure
811 * @this: NAND chip structure
812 * @state: state to select the max. timeout value
813 *
814 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000815 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 * general NAND and SmartMedia specs
817 *
818*/
819static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
820{
821
David Woodhousee0c7d762006-05-13 18:07:53 +0100822 unsigned long timeo = jiffies;
823 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100826 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100828 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Richard Purdie8fe833c2006-03-31 02:31:14 -0800830 led_trigger_event(nand_led_trigger, LED_FULL);
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 /* Apply this short delay always to ensure that we do wait tWB in
833 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100834 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100837 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000838 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100839 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000841 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* Check, if we were interrupted */
843 if (this->state != state)
844 return 0;
845
846 if (this->dev_ready) {
847 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000848 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 } else {
850 if (this->read_byte(mtd) & NAND_STATUS_READY)
851 break;
852 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000853 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800855 led_trigger_event(nand_led_trigger, LED_OFF);
856
David Woodhousee0c7d762006-05-13 18:07:53 +0100857 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return status;
859}
860
861/**
862 * nand_write_page - [GENERIC] write one page
863 * @mtd: MTD device structure
864 * @this: NAND chip structure
865 * @page: startpage inside the chip, must be called with (page & this->pagemask)
866 * @oob_buf: out of band data buffer
867 * @oobsel: out of band selecttion structre
868 * @cached: 1 = enable cached programming if supported by chip
869 *
870 * Nand_page_program function is used for write and writev !
871 * This function will always program a full page of data
872 * If you call it with a non page aligned buffer, you're lost :)
873 *
874 * Cached programming is not supported yet.
875 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100876static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
877 u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
David Woodhousee0c7d762006-05-13 18:07:53 +0100879 int i, status;
880 u_char ecc_code[32];
881 int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
882 int *oob_config = oobsel->eccpos;
883 int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
884 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 /* FIXME: Enable cached programming */
887 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100890 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892 /* Write out complete page of data, take care of eccmode */
893 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100894 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100896 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 this->write_buf(mtd, this->data_poi, mtd->oobblock);
898 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000899
David Woodhousee0c7d762006-05-13 18:07:53 +0100900 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 case NAND_ECC_SOFT:
902 for (; eccsteps; eccsteps--) {
903 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
904 for (i = 0; i < 3; i++, eccidx++)
905 oob_buf[oob_config[eccidx]] = ecc_code[i];
906 datidx += this->eccsize;
907 }
908 this->write_buf(mtd, this->data_poi, mtd->oobblock);
909 break;
910 default:
911 eccbytes = this->eccbytes;
912 for (; eccsteps; eccsteps--) {
913 /* enable hardware ecc logic for write */
914 this->enable_hwecc(mtd, NAND_ECC_WRITE);
915 this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
916 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
917 for (i = 0; i < eccbytes; i++, eccidx++)
918 oob_buf[oob_config[eccidx]] = ecc_code[i];
919 /* If the hardware ecc provides syndromes then
920 * the ecc code must be written immidiately after
921 * the data bytes (words) */
922 if (this->options & NAND_HWECC_SYNDROME)
923 this->write_buf(mtd, ecc_code, eccbytes);
924 datidx += this->eccsize;
925 }
926 break;
927 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /* Write out OOB data */
930 if (this->options & NAND_HWECC_SYNDROME)
931 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000932 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 this->write_buf(mtd, oob_buf, mtd->oobsize);
934
935 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100936 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 if (!cached) {
939 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100940 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000941
942 /* See if operation failed and additional status checks are available */
943 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
944 status = this->errstat(mtd, this, FL_WRITING, status, page);
945 }
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000948 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100949 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 return -EIO;
951 }
952 } else {
953 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100954 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
956 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000957 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958}
959
960#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
961/**
962 * nand_verify_pages - [GENERIC] verify the chip contents after a write
963 * @mtd: MTD device structure
964 * @this: NAND chip structure
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200965 * @page: startpage inside the chip, must be called with (page & this->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 * @numpages: number of pages to verify
967 * @oob_buf: out of band data buffer
968 * @oobsel: out of band selecttion structre
969 * @chipnr: number of the current chip
970 * @oobmode: 1 = full buffer verify, 0 = ecc only
971 *
972 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000973 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000975 * byte by byte basis. It is possible that the page was not completely erased
976 * or the page is becoming unusable due to wear. The read with ECC would catch
977 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 * it early in the page write stage. Better to write no data than invalid data.
979 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100980static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
981 u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
David Woodhousee0c7d762006-05-13 18:07:53 +0100983 int i, j, datidx = 0, oobofs = 0, res = -EIO;
984 int eccsteps = this->eccsteps;
985 int hweccbytes;
986 u_char oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
989
990 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100991 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
David Woodhousee0c7d762006-05-13 18:07:53 +0100993 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 for (j = 0; j < eccsteps; j++) {
995 /* Loop through and verify the data */
996 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100997 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 goto out;
999 }
1000 datidx += mtd->eccsize;
1001 /* Have we a hw generator layout ? */
1002 if (!hweccbytes)
1003 continue;
1004 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001005 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 goto out;
1007 }
1008 oobofs += hweccbytes;
1009 }
1010
1011 /* check, if we must compare all data or if we just have to
1012 * compare the ecc bytes
1013 */
1014 if (oobmode) {
1015 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001016 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 goto out;
1018 }
1019 } else {
1020 /* Read always, else autoincrement fails */
1021 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
1022
1023 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
1024 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 for (i = 0; i < ecccnt; i++) {
1027 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +01001028 if (oobdata[idx] != oob_buf[oobofs + idx]) {
1029 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
1030 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 goto out;
1032 }
1033 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 }
1036 oobofs += mtd->oobsize - hweccbytes * eccsteps;
1037 page++;
1038 numpages--;
1039
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001040 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 * Do this before the AUTOINCR check, so no problems
1042 * arise if a chip which does auto increment
1043 * is marked as NOAUTOINCR by the board driver.
1044 * Do this also before returning, so the chip is
1045 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +01001046 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001047 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001048 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001050 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052 /* All done, return happy */
1053 if (!numpages)
1054 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001055
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001056 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001058 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001060 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 * Terminate the read command. We come here in case of an error
1062 * So we must issue a reset command.
1063 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001064 out:
1065 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return res;
1067}
1068#endif
1069
1070/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001071 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 * @mtd: MTD device structure
1073 * @from: offset to read from
1074 * @len: number of bytes to read
1075 * @retlen: pointer to variable to store the number of read bytes
1076 * @buf: the databuffer to put data
1077 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001078 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1079 * and flags = 0xff
1080 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001081static 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 -07001082{
David Woodhousee0c7d762006-05-13 18:07:53 +01001083 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001084}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001087 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 * @mtd: MTD device structure
1089 * @from: offset to read from
1090 * @len: number of bytes to read
1091 * @retlen: pointer to variable to store the number of read bytes
1092 * @buf: the databuffer to put data
1093 * @oob_buf: filesystem supplied oob data buffer
1094 * @oobsel: oob selection structure
1095 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001096 * This function simply calls nand_do_read_ecc with flags = 0xff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001098static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1099 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001101 /* use userspace supplied oobinfo, if zero */
1102 if (oobsel == NULL)
1103 oobsel = &mtd->oobinfo;
David A. Marlin068e3c02005-01-24 03:07:46 +00001104 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1105}
1106
David A. Marlin068e3c02005-01-24 03:07:46 +00001107/**
1108 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1109 * @mtd: MTD device structure
1110 * @from: offset to read from
1111 * @len: number of bytes to read
1112 * @retlen: pointer to variable to store the number of read bytes
1113 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001114 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001115 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001116 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1117 * and how many corrected error bits are acceptable:
1118 * bits 0..7 - number of tolerable errors
1119 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1120 *
1121 * NAND read with ECC
1122 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001123int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1124 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001125{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1128 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1129 struct nand_chip *this = mtd->priv;
1130 u_char *data_poi, *oob_data = oob_buf;
Jarkko Lavinen0a18cde2005-04-11 15:16:11 +01001131 u_char ecc_calc[32];
1132 u_char ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001133 int eccmode, eccsteps;
1134 int *oob_config, datidx;
1135 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1136 int eccbytes;
1137 int compareecc = 1;
1138 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
David Woodhousee0c7d762006-05-13 18:07:53 +01001140 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 -07001141
1142 /* Do not allow reads past end of device */
1143 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001144 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 *retlen = 0;
1146 return -EINVAL;
1147 }
1148
1149 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001150 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001151 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* Autoplace of oob data ? Use the default placement scheme */
1154 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1155 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
1158 oob_config = oobsel->eccpos;
1159
1160 /* Select the NAND device */
1161 chipnr = (int)(from >> this->chip_shift);
1162 this->select_chip(mtd, chipnr);
1163
1164 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001165 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 page = realpage & this->pagemask;
1167
1168 /* Get raw starting column */
1169 col = from & (mtd->oobblock - 1);
1170
1171 end = mtd->oobblock;
1172 ecc = this->eccsize;
1173 eccbytes = this->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1176 compareecc = 0;
1177
1178 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001179 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 oobreadlen -= oobsel->eccbytes;
1181
1182 /* Loop until all data read */
1183 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001186 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 * If the read is not page aligned, we have to read into data buffer
1188 * due to ecc, else we read into return buffer direct
1189 */
1190 if (aligned)
1191 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001192 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001194
1195 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 *
1197 * FIXME: Make it work when we must provide oob data too,
1198 * check the usage of data_buf oob field
1199 */
1200 if (realpage == this->pagebuf && !oob_buf) {
1201 /* aligned read ? */
1202 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001203 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 goto readdata;
1205 }
1206
1207 /* Check, if we must send the read command */
1208 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001209 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001214 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1215 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 oob_data = &this->data_buf[end];
1217
1218 eccsteps = this->eccsteps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001221 case NAND_ECC_NONE:{
1222 /* No ECC, Read in a page */
1223 static unsigned long lastwhinge = 0;
1224 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1225 printk(KERN_WARNING
1226 "Reading data from NAND FLASH without ECC is not recommended\n");
1227 lastwhinge = jiffies;
1228 }
1229 this->read_buf(mtd, data_poi, end);
1230 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1234 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001235 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001237 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001240 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 this->enable_hwecc(mtd, NAND_ECC_READ);
1242 this->read_buf(mtd, &data_poi[datidx], ecc);
1243
1244 /* HW ecc with syndrome calculation must read the
1245 * syndrome from flash immidiately after the data */
1246 if (!compareecc) {
1247 /* Some hw ecc generators need to know when the
1248 * syndrome is read from flash */
1249 this->enable_hwecc(mtd, NAND_ECC_READSYN);
1250 this->read_buf(mtd, &oob_data[i], eccbytes);
1251 /* We calc error correction directly, it checks the hw
1252 * generator for an error, reads back the syndrome and
1253 * does the error correction on the fly */
David A. Marlin068e3c02005-01-24 03:07:46 +00001254 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1255 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001256 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1257 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 ecc_failed++;
1259 }
1260 } else {
1261 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001264 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266
1267 /* read oobdata */
1268 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1269
1270 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1271 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001272 goto readoob;
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 /* Pick the ECC bytes out of the oob data */
1275 for (j = 0; j < oobsel->eccbytes; j++)
1276 ecc_code[j] = oob_data[oob_config[j]];
1277
David Woodhousee0c7d762006-05-13 18:07:53 +01001278 /* correct data, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
1280 ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 /* Get next chunk of ecc bytes */
1283 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001284
1285 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 * This is the legacy mode. Used by YAFFS1
1287 * Should go away some day
1288 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001289 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 int *p = (int *)(&oob_data[mtd->oobsize]);
1291 p[i] = ecc_status;
1292 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001293
1294 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001295 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 ecc_failed++;
1297 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
David Woodhousee0c7d762006-05-13 18:07:53 +01001300 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 /* check, if we have a fs supplied oob-buffer */
1302 if (oob_buf) {
1303 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001304 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001306 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001308 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 int from = oobsel->oobfree[i][0];
1310 int num = oobsel->oobfree[i][1];
1311 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001312 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 break;
1315 case MTD_NANDECC_PLACE:
1316 /* YAFFS1 legacy mode */
David Woodhousee0c7d762006-05-13 18:07:53 +01001317 oob_data += this->eccsteps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 default:
1319 oob_data += mtd->oobsize;
1320 }
1321 }
1322 readdata:
1323 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001324 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 for (j = col; j < end && read < len; j++)
1326 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001327 this->pagebuf = realpage;
1328 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 read += mtd->oobblock;
1330
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001331 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 * Do this before the AUTOINCR check, so no problems
1333 * arise if a chip which does auto increment
1334 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001335 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001336 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001337 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001339 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 /* For subsequent reads align to page boundary. */
1345 col = 0;
1346 /* Increment page address */
1347 realpage++;
1348
1349 page = realpage & this->pagemask;
1350 /* Check, if we cross a chip boundary */
1351 if (!page) {
1352 chipnr++;
1353 this->select_chip(mtd, -1);
1354 this->select_chip(mtd, chipnr);
1355 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001356 /* Check, if the chip supports auto page increment
1357 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001358 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001360 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 }
1362
1363 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001364 if (flags & NAND_GET_DEVICE)
1365 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 /*
1368 * Return success, if no ECC failures, else -EBADMSG
1369 * fs driver will take care of that, because
1370 * retlen == desired len and result == -EBADMSG
1371 */
1372 *retlen = read;
1373 return ecc_failed ? -EBADMSG : 0;
1374}
1375
1376/**
1377 * nand_read_oob - [MTD Interface] NAND read out-of-band
1378 * @mtd: MTD device structure
1379 * @from: offset to read from
1380 * @len: number of bytes to read
1381 * @retlen: pointer to variable to store the number of read bytes
1382 * @buf: the databuffer to put data
1383 *
1384 * NAND read out-of-band data from the spare area
1385 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001386static 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 -07001387{
1388 int i, col, page, chipnr;
1389 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001390 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
David Woodhousee0c7d762006-05-13 18:07:53 +01001392 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 -07001393
1394 /* Shift to get page */
1395 page = (int)(from >> this->page_shift);
1396 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 /* Mask to get column */
1399 col = from & (mtd->oobsize - 1);
1400
1401 /* Initialize return length value */
1402 *retlen = 0;
1403
1404 /* Do not allow reads past end of device */
1405 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001406 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 *retlen = 0;
1408 return -EINVAL;
1409 }
1410
1411 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001412 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
1414 /* Select the NAND device */
1415 this->select_chip(mtd, chipnr);
1416
1417 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001418 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001419 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 * Read the data, if we read more than one page
1421 * oob data, let the device transfer the data !
1422 */
1423 i = 0;
1424 while (i < len) {
1425 int thislen = mtd->oobsize - col;
1426 thislen = min_t(int, thislen, len);
1427 this->read_buf(mtd, &buf[i], thislen);
1428 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 /* Read more ? */
1431 if (i < len) {
1432 page++;
1433 col = 0;
1434
1435 /* Check, if we cross a chip boundary */
1436 if (!(page & this->pagemask)) {
1437 chipnr++;
1438 this->select_chip(mtd, -1);
1439 this->select_chip(mtd, chipnr);
1440 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001441
1442 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001443 * Do this before the AUTOINCR check, so no problems
1444 * arise if a chip which does auto increment
1445 * is marked as NOAUTOINCR by the board driver.
1446 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001447 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001448 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001449 else
1450 nand_wait_ready(mtd);
1451
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001452 /* Check, if the chip supports auto page increment
1453 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001454 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1456 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001457 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 }
1459 }
1460 }
1461
1462 /* Deselect and wake up anyone waiting on the device */
1463 nand_release_device(mtd);
1464
1465 /* Return happy */
1466 *retlen = len;
1467 return 0;
1468}
1469
1470/**
1471 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1472 * @mtd: MTD device structure
1473 * @buf: temporary buffer
1474 * @from: offset to read from
1475 * @len: number of bytes to read
1476 * @ooblen: number of oob data bytes to read
1477 *
1478 * Read raw data including oob into buffer
1479 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001480int 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 -07001481{
1482 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001483 int page = (int)(from >> this->page_shift);
1484 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 int sndcmd = 1;
1486 int cnt = 0;
1487 int pagesize = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001488 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
1490 /* Do not allow reads past end of device */
1491 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001492 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return -EINVAL;
1494 }
1495
1496 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001497 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
David Woodhousee0c7d762006-05-13 18:07:53 +01001499 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 /* Add requested oob length */
1502 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 while (len) {
1505 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001506 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001507 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
David Woodhousee0c7d762006-05-13 18:07:53 +01001509 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
1511 len -= pagesize;
1512 cnt += pagesize;
1513 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001514
1515 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001516 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001518 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001519
1520 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1522 sndcmd = 1;
1523 }
1524
1525 /* Deselect and wake up anyone waiting on the device */
1526 nand_release_device(mtd);
1527 return 0;
1528}
1529
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001530/**
1531 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 * @mtd: MTD device structure
1533 * @fsbuf: buffer given by fs driver
1534 * @oobsel: out of band selection structre
1535 * @autoplace: 1 = place given buffer into the oob bytes
1536 * @numpages: number of pages to prepare
1537 *
1538 * Return:
1539 * 1. Filesystem buffer available and autoplacement is off,
1540 * return filesystem buffer
1541 * 2. No filesystem buffer or autoplace is off, return internal
1542 * buffer
1543 * 3. Filesystem buffer is given and autoplace selected
1544 * put data from fs buffer into internal buffer and
1545 * retrun internal buffer
1546 *
1547 * Note: The internal buffer is filled with 0xff. This must
1548 * be done only once, when no autoplacement happens
1549 * Autoplacement sets the buffer dirty flag, which
1550 * forces the 0xff fill before using the buffer again.
1551 *
1552*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001553static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
1554 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
1556 struct nand_chip *this = mtd->priv;
1557 int i, len, ofs;
1558
1559 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001560 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return fsbuf;
1562
1563 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001564 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001565 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001567 }
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 /* If we have no autoplacement or no fs buffer use the internal one */
1570 if (!autoplace || !fsbuf)
1571 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 /* Walk through the pages and place the data */
1574 this->oobdirty = 1;
1575 ofs = 0;
1576 while (numpages--) {
1577 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1578 int to = ofs + oobsel->oobfree[i][0];
1579 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001580 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 len += num;
1582 fsbuf += num;
1583 }
1584 ofs += mtd->oobavail;
1585 }
1586 return this->oob_buf;
1587}
1588
1589#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
1590
1591/**
1592 * nand_write - [MTD Interface] compability function for nand_write_ecc
1593 * @mtd: MTD device structure
1594 * @to: offset to write to
1595 * @len: number of bytes to write
1596 * @retlen: pointer to variable to store the number of written bytes
1597 * @buf: the data to write
1598 *
1599 * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
1600 *
1601*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001602static 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 -07001603{
David Woodhousee0c7d762006-05-13 18:07:53 +01001604 return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607/**
1608 * nand_write_ecc - [MTD Interface] NAND write with ECC
1609 * @mtd: MTD device structure
1610 * @to: offset to write to
1611 * @len: number of bytes to write
1612 * @retlen: pointer to variable to store the number of written bytes
1613 * @buf: the data to write
1614 * @eccbuf: filesystem supplied oob data buffer
1615 * @oobsel: oob selection structure
1616 *
1617 * NAND write with ECC
1618 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001619static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
1620 size_t *retlen, const u_char *buf, u_char *eccbuf,
1621 struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1624 int autoplace = 0, numpages, totalpages;
1625 struct nand_chip *this = mtd->priv;
1626 u_char *oobbuf, *bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001627 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
David Woodhousee0c7d762006-05-13 18:07:53 +01001629 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 -07001630
1631 /* Initialize retlen, in case of early exit */
1632 *retlen = 0;
1633
1634 /* Do not allow write past end of device */
1635 if ((to + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001636 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 return -EINVAL;
1638 }
1639
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001640 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001641 if (NOTALIGNED(to) || NOTALIGNED(len)) {
1642 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 return -EINVAL;
1644 }
1645
1646 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001647 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 /* Calculate chipnr */
1650 chipnr = (int)(to >> this->chip_shift);
1651 /* Select the NAND device */
1652 this->select_chip(mtd, chipnr);
1653
1654 /* Check, if it is write protected */
1655 if (nand_check_wp(mtd))
1656 goto out;
1657
1658 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001659 if (oobsel == NULL)
1660 oobsel = &mtd->oobinfo;
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 /* Autoplace of oob data ? Use the default placement scheme */
1663 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1664 oobsel = this->autooob;
1665 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001666 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001667 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1668 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 /* Setup variables and oob buffer */
1671 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001672 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001674 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 /* Set it relative to chip */
1678 page &= this->pagemask;
1679 startpage = page;
1680 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001681 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1682 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
1683 bufstart = (u_char *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685 /* Loop until all data is written */
1686 while (written < len) {
1687
David Woodhousee0c7d762006-05-13 18:07:53 +01001688 this->data_poi = (u_char *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 /* Write one page. If this is the last page to write
1690 * or the last page in this block, then use the
1691 * real pageprogram command, else select cached programming
1692 * if supported by the chip.
1693 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001694 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001696 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* Next oob page */
1700 oob += mtd->oobsize;
1701 /* Update written bytes count */
1702 written += mtd->oobblock;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001703 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 /* Increment page address */
1707 page++;
1708
1709 /* Have we hit a block boundary ? Then we have to verify and
1710 * if verify is ok, we have to setup the oob buffer for
1711 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001712 */
1713 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 int ofs;
1715 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001716 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1717 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001719 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 *retlen = written;
1723
1724 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1725 if (eccbuf)
1726 eccbuf += (page - startpage) * ofs;
1727 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001728 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 page &= this->pagemask;
1730 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001731 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001732 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* Check, if we cross a chip boundary */
1734 if (!page) {
1735 chipnr++;
1736 this->select_chip(mtd, -1);
1737 this->select_chip(mtd, chipnr);
1738 }
1739 }
1740 }
1741 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001742 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001744 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if (!ret)
1746 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001747 else
David Woodhousee0c7d762006-05-13 18:07:53 +01001748 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
David Woodhousee0c7d762006-05-13 18:07:53 +01001750 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 /* Deselect and wake up anyone waiting on the device */
1752 nand_release_device(mtd);
1753
1754 return ret;
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757/**
1758 * nand_write_oob - [MTD Interface] NAND write out-of-band
1759 * @mtd: MTD device structure
1760 * @to: offset to write to
1761 * @len: number of bytes to write
1762 * @retlen: pointer to variable to store the number of written bytes
1763 * @buf: the data to write
1764 *
1765 * NAND write out-of-band
1766 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001767static 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 -07001768{
1769 int column, page, status, ret = -EIO, chipnr;
1770 struct nand_chip *this = mtd->priv;
1771
David Woodhousee0c7d762006-05-13 18:07:53 +01001772 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 -07001773
1774 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001775 page = (int)(to >> this->page_shift);
1776 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 /* Mask to get column */
1779 column = to & (mtd->oobsize - 1);
1780
1781 /* Initialize return length value */
1782 *retlen = 0;
1783
1784 /* Do not allow write past end of page */
1785 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001786 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 return -EINVAL;
1788 }
1789
1790 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001791 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793 /* Select the NAND device */
1794 this->select_chip(mtd, chipnr);
1795
1796 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1797 in one of my DiskOnChip 2000 test units) will clear the whole
1798 data page too if we don't do this. I have no clue why, but
1799 I seem to have 'fixed' it in the doc2000 driver in
1800 August 1999. dwmw2. */
1801 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1802
1803 /* Check, if it is write protected */
1804 if (nand_check_wp(mtd))
1805 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* Invalidate the page cache, if we write to the cached page */
1808 if (page == this->pagebuf)
1809 this->pagebuf = -1;
1810
1811 if (NAND_MUST_PAD(this)) {
1812 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001813 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 /* prepad 0xff for partial programming */
1815 this->write_buf(mtd, ffchars, column);
1816 /* write data */
1817 this->write_buf(mtd, buf, len);
1818 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001819 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 } else {
1821 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001822 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 /* write data */
1824 this->write_buf(mtd, buf, len);
1825 }
1826 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001827 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
David Woodhousee0c7d762006-05-13 18:07:53 +01001829 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001832 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001833 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 ret = -EIO;
1835 goto out;
1836 }
1837 /* Return happy */
1838 *retlen = len;
1839
1840#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1841 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001842 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001845 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 ret = -EIO;
1847 goto out;
1848 }
1849#endif
1850 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001851 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* Deselect and wake up anyone waiting on the device */
1853 nand_release_device(mtd);
1854
1855 return ret;
1856}
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858/**
1859 * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
1860 * @mtd: MTD device structure
1861 * @vecs: the iovectors to write
1862 * @count: number of vectors
1863 * @to: offset to write to
1864 * @retlen: pointer to variable to store the number of written bytes
1865 *
1866 * NAND write with kvec. This just calls the ecc function
1867 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001868static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1869 loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
David Woodhousee0c7d762006-05-13 18:07:53 +01001871 return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872}
1873
1874/**
1875 * nand_writev_ecc - [MTD Interface] write with iovec with ecc
1876 * @mtd: MTD device structure
1877 * @vecs: the iovectors to write
1878 * @count: number of vectors
1879 * @to: offset to write to
1880 * @retlen: pointer to variable to store the number of written bytes
1881 * @eccbuf: filesystem supplied oob data buffer
1882 * @oobsel: oob selection structure
1883 *
1884 * NAND write with iovec with ecc
1885 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001886static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1887 loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888{
1889 int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
1890 int oob, numpages, autoplace = 0, startpage;
1891 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001892 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 u_char *oobbuf, *bufstart;
1894
1895 /* Preset written len for early exit */
1896 *retlen = 0;
1897
1898 /* Calculate total length of data */
1899 total_len = 0;
1900 for (i = 0; i < count; i++)
David Woodhousee0c7d762006-05-13 18:07:53 +01001901 total_len += (int)vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
David Woodhousee0c7d762006-05-13 18:07:53 +01001903 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 -07001904
1905 /* Do not allow write past end of page */
1906 if ((to + total_len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001907 DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 return -EINVAL;
1909 }
1910
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001911 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001912 if (NOTALIGNED(to) || NOTALIGNED(total_len)) {
1913 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 return -EINVAL;
1915 }
1916
1917 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001918 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920 /* Get the current chip-nr */
David Woodhousee0c7d762006-05-13 18:07:53 +01001921 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 /* Select the NAND device */
1923 this->select_chip(mtd, chipnr);
1924
1925 /* Check, if it is write protected */
1926 if (nand_check_wp(mtd))
1927 goto out;
1928
1929 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001930 if (oobsel == NULL)
1931 oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 /* Autoplace of oob data ? Use the default placement scheme */
1934 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1935 oobsel = this->autooob;
1936 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001937 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001938 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1939 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 /* Setup start page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001942 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001944 if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 this->pagebuf = -1;
1946
1947 startpage = page & this->pagemask;
1948
1949 /* Loop until all kvec' data has been written */
1950 len = 0;
1951 while (count) {
1952 /* If the given tuple is >= pagesize then
1953 * write it out from the iov
1954 */
1955 if ((vecs->iov_len - len) >= mtd->oobblock) {
1956 /* Calc number of pages we can write
1957 * out of this iov in one go */
1958 numpages = (vecs->iov_len - len) >> this->page_shift;
1959 /* Do not cross block boundaries */
David Woodhousee0c7d762006-05-13 18:07:53 +01001960 numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
1961 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
1962 bufstart = (u_char *) vecs->iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 bufstart += len;
1964 this->data_poi = bufstart;
1965 oob = 0;
1966 for (i = 1; i <= numpages; i++) {
1967 /* Write one page. If this is the last page to write
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001968 * then use the real pageprogram command, else select
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 * cached programming if supported by the chip.
1970 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001971 ret = nand_write_page(mtd, this, page & this->pagemask,
1972 &oobbuf[oob], oobsel, i != numpages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 if (ret)
1974 goto out;
1975 this->data_poi += mtd->oobblock;
1976 len += mtd->oobblock;
1977 oob += mtd->oobsize;
1978 page++;
1979 }
1980 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001981 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 vecs++;
1983 len = 0;
1984 count--;
1985 }
1986 } else {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001987 /* We must use the internal buffer, read data out of each
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 * tuple until we have a full page to write
1989 */
1990 int cnt = 0;
1991 while (cnt < mtd->oobblock) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001992 if (vecs->iov_base != NULL && vecs->iov_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
1994 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001995 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 vecs++;
1997 len = 0;
1998 count--;
1999 }
2000 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002001 this->pagebuf = page;
2002 this->data_poi = this->data_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 bufstart = this->data_poi;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002004 numpages = 1;
David Woodhousee0c7d762006-05-13 18:07:53 +01002005 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
2006 ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 if (ret)
2008 goto out;
2009 page++;
2010 }
2011
2012 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01002013 ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 if (ret)
2015 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 written += mtd->oobblock * numpages;
2018 /* All done ? */
2019 if (!count)
2020 break;
2021
2022 startpage = page & this->pagemask;
2023 /* Check, if we cross a chip boundary */
2024 if (!startpage) {
2025 chipnr++;
2026 this->select_chip(mtd, -1);
2027 this->select_chip(mtd, chipnr);
2028 }
2029 }
2030 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002031 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 /* Deselect and wake up anyone waiting on the device */
2033 nand_release_device(mtd);
2034
2035 *retlen = written;
2036 return ret;
2037}
2038
2039/**
2040 * single_erease_cmd - [GENERIC] NAND standard block erase command function
2041 * @mtd: MTD device structure
2042 * @page: the page address of the block which will be erased
2043 *
2044 * Standard erase command for NAND chips
2045 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002046static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047{
2048 struct nand_chip *this = mtd->priv;
2049 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002050 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2051 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052}
2053
2054/**
2055 * multi_erease_cmd - [GENERIC] AND specific block erase command function
2056 * @mtd: MTD device structure
2057 * @page: the page address of the block which will be erased
2058 *
2059 * AND multi block erase command function
2060 * Erase 4 consecutive blocks
2061 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002062static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063{
2064 struct nand_chip *this = mtd->priv;
2065 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002066 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2067 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2068 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2069 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2070 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071}
2072
2073/**
2074 * nand_erase - [MTD Interface] erase block(s)
2075 * @mtd: MTD device structure
2076 * @instr: erase instruction
2077 *
2078 * Erase one ore more blocks
2079 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002080static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081{
David Woodhousee0c7d762006-05-13 18:07:53 +01002082 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002084
David A. Marlin30f464b2005-01-17 18:35:25 +00002085#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086/**
2087 * nand_erase_intern - [NAND Interface] erase block(s)
2088 * @mtd: MTD device structure
2089 * @instr: erase instruction
2090 * @allowbbt: allow erasing the bbt area
2091 *
2092 * Erase one ore more blocks
2093 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002094int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095{
2096 int page, len, status, pages_per_block, ret, chipnr;
2097 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00002098 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
2099 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
2100 /* It is used to see if the current page is in the same */
2101 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
David Woodhousee0c7d762006-05-13 18:07:53 +01002103 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 -07002104
2105 /* Start address must align on block boundary */
2106 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002107 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 return -EINVAL;
2109 }
2110
2111 /* Length must align on block boundary */
2112 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002113 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 return -EINVAL;
2115 }
2116
2117 /* Do not allow erase past end of device */
2118 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002119 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 return -EINVAL;
2121 }
2122
2123 instr->fail_addr = 0xffffffff;
2124
2125 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002126 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
2128 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01002129 page = (int)(instr->addr >> this->page_shift);
2130 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
2132 /* Calculate pages in each block */
2133 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
2134
2135 /* Select the NAND device */
2136 this->select_chip(mtd, chipnr);
2137
2138 /* Check the WP bit */
2139 /* Check, if it is write protected */
2140 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002141 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 instr->state = MTD_ERASE_FAILED;
2143 goto erase_exit;
2144 }
2145
David A. Marlin30f464b2005-01-17 18:35:25 +00002146 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
2147 if (this->options & BBT_AUTO_REFRESH) {
2148 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2149 } else {
2150 bbt_masked_page = 0xffffffff; /* should not match anything */
2151 }
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /* Loop through the pages */
2154 len = instr->len;
2155
2156 instr->state = MTD_ERASING;
2157
2158 while (len) {
2159 /* Check if we have a bad block, we do not erase bad blocks ! */
2160 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002161 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 instr->state = MTD_ERASE_FAILED;
2163 goto erase_exit;
2164 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002165
2166 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 the current cached page */
2168 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
2169 this->pagebuf = -1;
2170
David Woodhousee0c7d762006-05-13 18:07:53 +01002171 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002172
David Woodhousee0c7d762006-05-13 18:07:53 +01002173 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
David A. Marlin068e3c02005-01-24 03:07:46 +00002175 /* See if operation failed and additional status checks are available */
2176 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2177 status = this->errstat(mtd, this, FL_ERASING, status, page);
2178 }
2179
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00002181 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002182 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 instr->state = MTD_ERASE_FAILED;
2184 instr->fail_addr = (page << this->page_shift);
2185 goto erase_exit;
2186 }
David A. Marlin30f464b2005-01-17 18:35:25 +00002187
2188 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
2189 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002190 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00002191 (page != this->bbt_td->pages[chipnr])) {
2192 rewrite_bbt[chipnr] = (page << this->page_shift);
2193 }
2194 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /* Increment page address and decrement length */
2197 len -= (1 << this->phys_erase_shift);
2198 page += pages_per_block;
2199
2200 /* Check, if we cross a chip boundary */
2201 if (len && !(page & this->pagemask)) {
2202 chipnr++;
2203 this->select_chip(mtd, -1);
2204 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00002205
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002206 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00002207 * set the BBT page mask to see if this BBT should be rewritten */
2208 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
2209 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2210 }
2211
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 }
2213 }
2214 instr->state = MTD_ERASE_DONE;
2215
David Woodhousee0c7d762006-05-13 18:07:53 +01002216 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
2219 /* Do call back function */
2220 if (!ret)
2221 mtd_erase_callback(instr);
2222
2223 /* Deselect and wake up anyone waiting on the device */
2224 nand_release_device(mtd);
2225
David A. Marlin30f464b2005-01-17 18:35:25 +00002226 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
2227 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
2228 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
2229 if (rewrite_bbt[chipnr]) {
2230 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01002231 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2232 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2233 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002234 }
2235 }
2236 }
2237
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 /* Return more or less happy */
2239 return ret;
2240}
2241
2242/**
2243 * nand_sync - [MTD Interface] sync
2244 * @mtd: MTD device structure
2245 *
2246 * Sync is actually a wait for chip ready function
2247 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002248static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249{
2250 struct nand_chip *this = mtd->priv;
2251
David Woodhousee0c7d762006-05-13 18:07:53 +01002252 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
2254 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002255 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002257 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258}
2259
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260/**
2261 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2262 * @mtd: MTD device structure
2263 * @ofs: offset relative to mtd start
2264 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002265static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266{
2267 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002268 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002270
David Woodhousee0c7d762006-05-13 18:07:53 +01002271 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272}
2273
2274/**
2275 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2276 * @mtd: MTD device structure
2277 * @ofs: offset relative to mtd start
2278 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002279static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280{
2281 struct nand_chip *this = mtd->priv;
2282 int ret;
2283
David Woodhousee0c7d762006-05-13 18:07:53 +01002284 if ((ret = nand_block_isbad(mtd, ofs))) {
2285 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 if (ret > 0)
2287 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002288 return ret;
2289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 return this->block_markbad(mtd, ofs);
2292}
2293
2294/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002295 * nand_suspend - [MTD Interface] Suspend the NAND flash
2296 * @mtd: MTD device structure
2297 */
2298static int nand_suspend(struct mtd_info *mtd)
2299{
2300 struct nand_chip *this = mtd->priv;
2301
David Woodhousee0c7d762006-05-13 18:07:53 +01002302 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002303}
2304
2305/**
2306 * nand_resume - [MTD Interface] Resume the NAND flash
2307 * @mtd: MTD device structure
2308 */
2309static void nand_resume(struct mtd_info *mtd)
2310{
2311 struct nand_chip *this = mtd->priv;
2312
2313 if (this->state == FL_PM_SUSPENDED)
2314 nand_release_device(mtd);
2315 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002316 printk(KERN_ERR "nand_resume() called for a chip which is not "
2317 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002318}
2319
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002320/*
2321 * Free allocated data structures
2322 */
2323static void nand_free_kmem(struct nand_chip *this)
2324{
2325 /* Buffer allocated by nand_scan ? */
2326 if (this->options & NAND_OOBBUF_ALLOC)
2327 kfree(this->oob_buf);
2328 /* Buffer allocated by nand_scan ? */
2329 if (this->options & NAND_DATABUF_ALLOC)
2330 kfree(this->data_buf);
2331 /* Controller allocated by nand_scan ? */
2332 if (this->options & NAND_CONTROLLER_ALLOC)
2333 kfree(this->controller);
2334}
2335
David Woodhouse52239da2006-05-14 16:54:39 +01002336/* module_text_address() isn't exported, and it's mostly a pointless
2337 test if this is a module _anyway_ -- they'd have to try _really_ hard
2338 to call us from in-kernel code if the core NAND support is modular. */
2339#ifdef MODULE
2340#define caller_is_module() (1)
2341#else
2342#define caller_is_module() module_text_address((unsigned long)__builtin_return_address(0))
2343#endif
2344
Vitaly Wool962034f2005-09-15 14:58:53 +01002345/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 * nand_scan - [NAND Interface] Scan for the NAND device
2347 * @mtd: MTD device structure
2348 * @maxchips: Number of chips to scan for
2349 *
David Woodhouse552d9202006-05-14 01:20:46 +01002350 * This fills out all the uninitialized function pointers
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 * with the defaults.
2352 * The flash ID is read and the mtd/chip structures are
2353 * filled with the appropriate values. Buffers are allocated if
2354 * they are not provided by the board driver
David Woodhouse552d9202006-05-14 01:20:46 +01002355 * The mtd->owner field must be set to the module of the caller
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 *
2357 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002358int nand_scan(struct mtd_info *mtd, int maxchips)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359{
Ben Dooks3b946e32005-03-14 18:30:48 +00002360 int i, nand_maf_id, nand_dev_id, busw, maf_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 struct nand_chip *this = mtd->priv;
2362
David Woodhouse52239da2006-05-14 16:54:39 +01002363 /* Many callers got this wrong, so check for it for a while... */
2364 if (!mtd->owner && caller_is_module()) {
David Woodhouse552d9202006-05-14 01:20:46 +01002365 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2366 BUG();
2367 }
2368
David Woodhousee0c7d762006-05-13 18:07:53 +01002369 /* Get buswidth to select the correct functions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 busw = this->options & NAND_BUSWIDTH_16;
2371
2372 /* check for proper chip_delay setup, set 20us if not */
2373 if (!this->chip_delay)
2374 this->chip_delay = 20;
2375
2376 /* check, if a user supplied command function given */
2377 if (this->cmdfunc == NULL)
2378 this->cmdfunc = nand_command;
2379
2380 /* check, if a user supplied wait function given */
2381 if (this->waitfunc == NULL)
2382 this->waitfunc = nand_wait;
2383
2384 if (!this->select_chip)
2385 this->select_chip = nand_select_chip;
2386 if (!this->write_byte)
2387 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
2388 if (!this->read_byte)
2389 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2390 if (!this->write_word)
2391 this->write_word = nand_write_word;
2392 if (!this->read_word)
2393 this->read_word = nand_read_word;
2394 if (!this->block_bad)
2395 this->block_bad = nand_block_bad;
2396 if (!this->block_markbad)
2397 this->block_markbad = nand_default_block_markbad;
2398 if (!this->write_buf)
2399 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2400 if (!this->read_buf)
2401 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2402 if (!this->verify_buf)
2403 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2404 if (!this->scan_bbt)
2405 this->scan_bbt = nand_default_bbt;
2406
2407 /* Select the device */
2408 this->select_chip(mtd, 0);
2409
2410 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002411 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 /* Read manufacturer and device IDs */
2414 nand_maf_id = this->read_byte(mtd);
2415 nand_dev_id = this->read_byte(mtd);
2416
2417 /* Print and store flash device information */
2418 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002419
2420 if (nand_dev_id != nand_flash_ids[i].id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 continue;
2422
David Woodhousee0c7d762006-05-13 18:07:53 +01002423 if (!mtd->name)
2424 mtd->name = nand_flash_ids[i].name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 this->chipsize = nand_flash_ids[i].chipsize << 20;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002426
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 /* New devices have all the information in additional id bytes */
2428 if (!nand_flash_ids[i].pagesize) {
2429 int extid;
2430 /* The 3rd id byte contains non relevant data ATM */
2431 extid = this->read_byte(mtd);
2432 /* The 4th id byte is the important one */
2433 extid = this->read_byte(mtd);
2434 /* Calc pagesize */
2435 mtd->oobblock = 1024 << (extid & 0x3);
2436 extid >>= 2;
2437 /* Calc oobsize */
Thomas Gleixnerd4094662005-08-11 18:13:46 +01002438 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 extid >>= 2;
2440 /* Calc blocksize. Blocksize is multiples of 64KiB */
David Woodhousee0c7d762006-05-13 18:07:53 +01002441 mtd->erasesize = (64 * 1024) << (extid & 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 extid >>= 2;
2443 /* Get buswidth information */
2444 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002445
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 } else {
2447 /* Old devices have this data hardcoded in the
2448 * device id table */
2449 mtd->erasesize = nand_flash_ids[i].erasesize;
2450 mtd->oobblock = nand_flash_ids[i].pagesize;
2451 mtd->oobsize = mtd->oobblock / 32;
2452 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2453 }
2454
Kyungmin Park0ea4a752005-02-16 09:39:39 +00002455 /* Try to identify manufacturer */
2456 for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
2457 if (nand_manuf_ids[maf_id].id == nand_maf_id)
2458 break;
2459 }
2460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 /* Check, if buswidth is correct. Hardware drivers should set
2462 * this correct ! */
2463 if (busw != (this->options & NAND_BUSWIDTH_16)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002464 printk(KERN_INFO "NAND device: Manufacturer ID:"
2465 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2466 nand_manuf_ids[maf_id].name, mtd->name);
2467 printk(KERN_WARNING
2468 "NAND bus width %d instead %d bit\n",
2469 (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 this->select_chip(mtd, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002471 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002473
2474 /* Calculate the address shift from the page size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 this->page_shift = ffs(mtd->oobblock) - 1;
2476 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
2477 this->chip_shift = ffs(this->chipsize) - 1;
2478
2479 /* Set the bad block position */
David Woodhousee0c7d762006-05-13 18:07:53 +01002480 this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 /* Get chip options, preserve non chip based options */
2483 this->options &= ~NAND_CHIPOPTIONS_MSK;
2484 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
David Woodhousee0c7d762006-05-13 18:07:53 +01002485 /* Set this as a default. Board drivers can override it, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 this->options |= NAND_NO_AUTOINCR;
2487 /* Check if this is a not a samsung device. Do not clear the options
2488 * for chips which are not having an extended id.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002489 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2491 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002492
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 /* Check for AND chips with 4 page planes */
2494 if (this->options & NAND_4PAGE_ARRAY)
2495 this->erase_cmd = multi_erase_cmd;
2496 else
2497 this->erase_cmd = single_erase_cmd;
2498
2499 /* Do not replace user supplied command function ! */
2500 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
2501 this->cmdfunc = nand_command_lp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002502
David Woodhousee0c7d762006-05-13 18:07:53 +01002503 printk(KERN_INFO "NAND device: Manufacturer ID:"
2504 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2505 nand_manuf_ids[maf_id].name, nand_flash_ids[i].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 break;
2507 }
2508
2509 if (!nand_flash_ids[i].name) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002510 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 this->select_chip(mtd, -1);
2512 return 1;
2513 }
2514
David Woodhousee0c7d762006-05-13 18:07:53 +01002515 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 this->select_chip(mtd, i);
2517
2518 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002519 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 /* Read manufacturer and device IDs */
2522 if (nand_maf_id != this->read_byte(mtd) ||
2523 nand_dev_id != this->read_byte(mtd))
2524 break;
2525 }
2526 if (i > 1)
2527 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002528
David Woodhousee0c7d762006-05-13 18:07:53 +01002529 /* Allocate buffers, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 if (!this->oob_buf) {
2531 size_t len;
2532 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
David Woodhousee0c7d762006-05-13 18:07:53 +01002533 this->oob_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 if (!this->oob_buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002535 printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 return -ENOMEM;
2537 }
2538 this->options |= NAND_OOBBUF_ALLOC;
2539 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002540
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 if (!this->data_buf) {
2542 size_t len;
2543 len = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01002544 this->data_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 if (!this->data_buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002546 printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002547 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 return -ENOMEM;
2549 }
2550 this->options |= NAND_DATABUF_ALLOC;
2551 }
2552
2553 /* Store the number of chips and calc total size for mtd */
2554 this->numchips = i;
2555 mtd->size = i * this->chipsize;
2556 /* Convert chipsize to number of pages per chip -1. */
2557 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2558 /* Preset the internal oob buffer */
2559 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2560
2561 /* If no default placement scheme is given, select an
2562 * appropriate one */
2563 if (!this->autooob) {
2564 /* Select the appropriate default oob placement scheme for
2565 * placement agnostic filesystems */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002566 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 case 8:
2568 this->autooob = &nand_oob_8;
2569 break;
2570 case 16:
2571 this->autooob = &nand_oob_16;
2572 break;
2573 case 64:
2574 this->autooob = &nand_oob_64;
2575 break;
2576 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002577 printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 BUG();
2579 }
2580 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002581
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 /* The number of bytes available for the filesystem to place fs dependend
2583 * oob data */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002584 mtd->oobavail = 0;
2585 for (i = 0; this->autooob->oobfree[i][1]; i++)
2586 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002588 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 * check ECC mode, default to software
2590 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002591 * fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002592 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002593 this->eccsize = 256; /* set default eccsize */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 this->eccbytes = 3;
2595
2596 switch (this->eccmode) {
2597 case NAND_ECC_HW12_2048:
2598 if (mtd->oobblock < 2048) {
2599 printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
2600 mtd->oobblock);
2601 this->eccmode = NAND_ECC_SOFT;
2602 this->calculate_ecc = nand_calculate_ecc;
2603 this->correct_data = nand_correct_data;
2604 } else
2605 this->eccsize = 2048;
2606 break;
2607
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002608 case NAND_ECC_HW3_512:
2609 case NAND_ECC_HW6_512:
2610 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 if (mtd->oobblock == 256) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002612 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 -07002613 this->eccmode = NAND_ECC_SOFT;
2614 this->calculate_ecc = nand_calculate_ecc;
2615 this->correct_data = nand_correct_data;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002616 } else
David Woodhousee0c7d762006-05-13 18:07:53 +01002617 this->eccsize = 512; /* set eccsize to 512 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 case NAND_ECC_HW3_256:
2621 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002622
2623 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +01002624 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 this->eccmode = NAND_ECC_NONE;
2626 break;
2627
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002628 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 this->calculate_ecc = nand_calculate_ecc;
2630 this->correct_data = nand_correct_data;
2631 break;
2632
2633 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002634 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002635 BUG();
2636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002638 /* Check hardware ecc function availability and adjust number of ecc bytes per
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 * calculation step
David Woodhousee0c7d762006-05-13 18:07:53 +01002640 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 switch (this->eccmode) {
2642 case NAND_ECC_HW12_2048:
2643 this->eccbytes += 4;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002644 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 this->eccbytes += 2;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002646 case NAND_ECC_HW6_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 this->eccbytes += 3;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002648 case NAND_ECC_HW3_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 case NAND_ECC_HW3_256:
2650 if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
2651 break;
David Woodhousee0c7d762006-05-13 18:07:53 +01002652 printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002653 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 mtd->eccsize = this->eccsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /* Set the number of read / write steps for one page to ensure ECC generation */
2659 switch (this->eccmode) {
2660 case NAND_ECC_HW12_2048:
2661 this->eccsteps = mtd->oobblock / 2048;
2662 break;
2663 case NAND_ECC_HW3_512:
2664 case NAND_ECC_HW6_512:
2665 case NAND_ECC_HW8_512:
2666 this->eccsteps = mtd->oobblock / 512;
2667 break;
2668 case NAND_ECC_HW3_256:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002669 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 this->eccsteps = mtd->oobblock / 256;
2671 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002672
2673 case NAND_ECC_NONE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 this->eccsteps = 1;
2675 break;
2676 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 /* Initialize state, waitqueue and spinlock */
2679 this->state = FL_READY;
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002680 if (!this->controller) {
2681 this->controller = kzalloc(sizeof(struct nand_hw_control),
2682 GFP_KERNEL);
2683 if (!this->controller) {
2684 nand_free_kmem(this);
2685 return -ENOMEM;
2686 }
2687 this->options |= NAND_CONTROLLER_ALLOC;
2688 }
2689 init_waitqueue_head(&this->controller->wq);
2690 spin_lock_init(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692 /* De-select the device */
2693 this->select_chip(mtd, -1);
2694
2695 /* Invalidate the pagebuffer reference */
2696 this->pagebuf = -1;
2697
2698 /* Fill in remaining MTD driver data */
2699 mtd->type = MTD_NANDFLASH;
2700 mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
2701 mtd->ecctype = MTD_ECC_SW;
2702 mtd->erase = nand_erase;
2703 mtd->point = NULL;
2704 mtd->unpoint = NULL;
2705 mtd->read = nand_read;
2706 mtd->write = nand_write;
2707 mtd->read_ecc = nand_read_ecc;
2708 mtd->write_ecc = nand_write_ecc;
2709 mtd->read_oob = nand_read_oob;
2710 mtd->write_oob = nand_write_oob;
2711 mtd->readv = NULL;
2712 mtd->writev = nand_writev;
2713 mtd->writev_ecc = nand_writev_ecc;
2714 mtd->sync = nand_sync;
2715 mtd->lock = NULL;
2716 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002717 mtd->suspend = nand_suspend;
2718 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 mtd->block_isbad = nand_block_isbad;
2720 mtd->block_markbad = nand_block_markbad;
2721
2722 /* and make the autooob the default one */
2723 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2724
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002725 /* Check, if we should skip the bad block table scan */
2726 if (this->options & NAND_SKIP_BBTSCAN)
2727 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002730 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731}
2732
2733/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002734 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 * @mtd: MTD device structure
2736*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002737void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738{
2739 struct nand_chip *this = mtd->priv;
2740
2741#ifdef CONFIG_MTD_PARTITIONS
2742 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002743 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744#endif
2745 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002746 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Jesper Juhlfa671642005-11-07 01:01:27 -08002748 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002749 kfree(this->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002750 /* Free buffers */
2751 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752}
2753
David Woodhousee0c7d762006-05-13 18:07:53 +01002754EXPORT_SYMBOL_GPL(nand_scan);
2755EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002756
2757static int __init nand_base_init(void)
2758{
2759 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2760 return 0;
2761}
2762
2763static void __exit nand_base_exit(void)
2764{
2765 led_trigger_unregister_simple(nand_led_trigger);
2766}
2767
2768module_init(nand_base_init);
2769module_exit(nand_base_exit);
2770
David Woodhousee0c7d762006-05-13 18:07:53 +01002771MODULE_LICENSE("GPL");
2772MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2773MODULE_DESCRIPTION("Generic NAND flash driver code");