blob: d796eb508b4f4ec6a26e1b71b704e35331d3e4c9 [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>
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +020079#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include <linux/sched.h>
81#include <linux/slab.h>
82#include <linux/types.h>
83#include <linux/mtd/mtd.h>
84#include <linux/mtd/nand.h>
85#include <linux/mtd/nand_ecc.h>
86#include <linux/mtd/compatmac.h>
87#include <linux/interrupt.h>
88#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080089#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <asm/io.h>
91
92#ifdef CONFIG_MTD_PARTITIONS
93#include <linux/mtd/partitions.h>
94#endif
95
96/* Define default oob placement schemes for large and small page devices */
97static struct nand_oobinfo nand_oob_8 = {
98 .useecc = MTD_NANDECC_AUTOPLACE,
99 .eccbytes = 3,
100 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +0100101 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
104static struct nand_oobinfo nand_oob_16 = {
105 .useecc = MTD_NANDECC_AUTOPLACE,
106 .eccbytes = 6,
107 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +0100108 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111static struct nand_oobinfo nand_oob_64 = {
112 .useecc = MTD_NANDECC_AUTOPLACE,
113 .eccbytes = 24,
114 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +0100115 40, 41, 42, 43, 44, 45, 46, 47,
116 48, 49, 50, 51, 52, 53, 54, 55,
117 56, 57, 58, 59, 60, 61, 62, 63},
118 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
121/* This is used for padding purposes in nand_write_oob */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200122static uint8_t ffchars[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131};
132
133/*
134 * NAND low-level MTD interface functions
135 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200136static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
137static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
138static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200140static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200141 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200142static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200143 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200144static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200145 size_t *retlen, const uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200146static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200147 size_t *retlen, const uint8_t *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100148static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
149static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151/* Some internal functions */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200152static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200153 int page, uint8_t * oob_buf,
David Woodhousee0c7d762006-05-13 18:07:53 +0100154 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200156static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200157 int page, int numpages, uint8_t *oob_buf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200158 struct nand_oobinfo *oobsel, int chipnr,
159 int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160#else
161#define nand_verify_pages(...) (0)
162#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000163
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200164static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd,
165 int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167/**
168 * nand_release_device - [GENERIC] release chip
169 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000170 *
171 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100173static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 struct nand_chip *this = mtd->priv;
176
177 /* De-select the NAND device */
178 this->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100179
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200180 /* Release the controller and the chip */
181 spin_lock(&this->controller->lock);
182 this->controller->active = NULL;
183 this->state = FL_READY;
184 wake_up(&this->controller->wq);
185 spin_unlock(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
188/**
189 * nand_read_byte - [DEFAULT] read one byte from the chip
190 * @mtd: MTD device structure
191 *
192 * Default read function for 8bit buswith
193 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200194static uint8_t nand_read_byte(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
196 struct nand_chip *this = mtd->priv;
197 return readb(this->IO_ADDR_R);
198}
199
200/**
201 * nand_write_byte - [DEFAULT] write one byte to the chip
202 * @mtd: MTD device structure
203 * @byte: pointer to data byte to write
204 *
205 * Default write function for 8it buswith
206 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200207static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 struct nand_chip *this = mtd->priv;
210 writeb(byte, this->IO_ADDR_W);
211}
212
213/**
214 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
215 * @mtd: MTD device structure
216 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000217 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 * endianess conversion
219 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200220static uint8_t nand_read_byte16(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200223 return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
226/**
227 * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
228 * @mtd: MTD device structure
229 * @byte: pointer to data byte to write
230 *
231 * Default write function for 16bit buswith with
232 * endianess conversion
233 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200234static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
236 struct nand_chip *this = mtd->priv;
237 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
238}
239
240/**
241 * nand_read_word - [DEFAULT] read one word from the chip
242 * @mtd: MTD device structure
243 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000244 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 * endianess conversion
246 */
247static u16 nand_read_word(struct mtd_info *mtd)
248{
249 struct nand_chip *this = mtd->priv;
250 return readw(this->IO_ADDR_R);
251}
252
253/**
254 * nand_write_word - [DEFAULT] write one word to the chip
255 * @mtd: MTD device structure
256 * @word: data word to write
257 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000258 * Default write function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * endianess conversion
260 */
261static void nand_write_word(struct mtd_info *mtd, u16 word)
262{
263 struct nand_chip *this = mtd->priv;
264 writew(word, this->IO_ADDR_W);
265}
266
267/**
268 * nand_select_chip - [DEFAULT] control CE line
269 * @mtd: MTD device structure
270 * @chip: chipnumber to select, -1 for deselect
271 *
272 * Default select function for 1 chip devices.
273 */
274static void nand_select_chip(struct mtd_info *mtd, int chip)
275{
276 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100277 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 case -1:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000279 this->hwcontrol(mtd, NAND_CTL_CLRNCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 break;
281 case 0:
282 this->hwcontrol(mtd, NAND_CTL_SETNCE);
283 break;
284
285 default:
286 BUG();
287 }
288}
289
290/**
291 * nand_write_buf - [DEFAULT] write buffer to chip
292 * @mtd: MTD device structure
293 * @buf: data buffer
294 * @len: number of bytes to write
295 *
296 * Default write function for 8bit buswith
297 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200298static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 int i;
301 struct nand_chip *this = mtd->priv;
302
David Woodhousee0c7d762006-05-13 18:07:53 +0100303 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 writeb(buf[i], this->IO_ADDR_W);
305}
306
307/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000308 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 * @mtd: MTD device structure
310 * @buf: buffer to store date
311 * @len: number of bytes to read
312 *
313 * Default read function for 8bit buswith
314 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200315static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 int i;
318 struct nand_chip *this = mtd->priv;
319
David Woodhousee0c7d762006-05-13 18:07:53 +0100320 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 buf[i] = readb(this->IO_ADDR_R);
322}
323
324/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000325 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 * @mtd: MTD device structure
327 * @buf: buffer containing the data to compare
328 * @len: number of bytes to compare
329 *
330 * Default verify function for 8bit buswith
331 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200332static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 int i;
335 struct nand_chip *this = mtd->priv;
336
David Woodhousee0c7d762006-05-13 18:07:53 +0100337 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (buf[i] != readb(this->IO_ADDR_R))
339 return -EFAULT;
340
341 return 0;
342}
343
344/**
345 * nand_write_buf16 - [DEFAULT] write buffer to chip
346 * @mtd: MTD device structure
347 * @buf: data buffer
348 * @len: number of bytes to write
349 *
350 * Default write function for 16bit buswith
351 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200352static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 int i;
355 struct nand_chip *this = mtd->priv;
356 u16 *p = (u16 *) buf;
357 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000358
David Woodhousee0c7d762006-05-13 18:07:53 +0100359 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
364/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000365 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 * @mtd: MTD device structure
367 * @buf: buffer to store date
368 * @len: number of bytes to read
369 *
370 * Default read function for 16bit buswith
371 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200372static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 int i;
375 struct nand_chip *this = mtd->priv;
376 u16 *p = (u16 *) buf;
377 len >>= 1;
378
David Woodhousee0c7d762006-05-13 18:07:53 +0100379 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 p[i] = readw(this->IO_ADDR_R);
381}
382
383/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000384 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 * @mtd: MTD device structure
386 * @buf: buffer containing the data to compare
387 * @len: number of bytes to compare
388 *
389 * Default verify function for 16bit buswith
390 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200391static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 int i;
394 struct nand_chip *this = mtd->priv;
395 u16 *p = (u16 *) buf;
396 len >>= 1;
397
David Woodhousee0c7d762006-05-13 18:07:53 +0100398 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (p[i] != readw(this->IO_ADDR_R))
400 return -EFAULT;
401
402 return 0;
403}
404
405/**
406 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
407 * @mtd: MTD device structure
408 * @ofs: offset from device start
409 * @getchip: 0, if the chip is already selected
410 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000411 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 */
413static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
414{
415 int page, chipnr, res = 0;
416 struct nand_chip *this = mtd->priv;
417 u16 bad;
418
419 if (getchip) {
420 page = (int)(ofs >> this->page_shift);
421 chipnr = (int)(ofs >> this->chip_shift);
422
423 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100424 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 /* Select the NAND device */
427 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000428 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100429 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 if (this->options & NAND_BUSWIDTH_16) {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200432 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
433 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 bad = cpu_to_le16(this->read_word(mtd));
435 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000436 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if ((bad & 0xFF) != 0xff)
438 res = 1;
439 } else {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200440 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
441 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 if (this->read_byte(mtd) != 0xff)
443 res = 1;
444 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (getchip) {
447 /* Deselect and wake up anyone waiting on the device */
448 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000449 }
450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return res;
452}
453
454/**
455 * nand_default_block_markbad - [DEFAULT] mark a block bad
456 * @mtd: MTD device structure
457 * @ofs: offset from device start
458 *
459 * This is the default implementation, which can be overridden by
460 * a hardware specific driver.
461*/
462static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
463{
464 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200465 uint8_t buf[2] = { 0, 0 };
David Woodhousee0c7d762006-05-13 18:07:53 +0100466 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100470 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000471 if (this->bbt)
472 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
474 /* Do we have a flash based bad block table ? */
475 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100476 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* We write two bytes, so we dont have to mess with 16 bit access */
479 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100480 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000483/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 * nand_check_wp - [GENERIC] check if the chip is write protected
485 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000486 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000488 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100490static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 struct nand_chip *this = mtd->priv;
493 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100494 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000495 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
498/**
499 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
500 * @mtd: MTD device structure
501 * @ofs: offset from device start
502 * @getchip: 0, if the chip is already selected
503 * @allowbbt: 1, if its allowed to access the bbt area
504 *
505 * Check, if the block is bad. Either by reading the bad block table or
506 * calling of the scan function.
507 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200508static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
509 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (!this->bbt)
514 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100517 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
Richard Purdie8fe833c2006-03-31 02:31:14 -0800520DEFINE_LED_TRIGGER(nand_led_trigger);
521
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000522/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000523 * Wait for the ready pin, after a command
524 * The timeout is catched later.
525 */
526static void nand_wait_ready(struct mtd_info *mtd)
527{
528 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100529 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000530
Richard Purdie8fe833c2006-03-31 02:31:14 -0800531 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000532 /* wait until command is processed or timeout occures */
533 do {
534 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800535 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700536 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000537 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800538 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000539}
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541/**
542 * nand_command - [DEFAULT] Send command to NAND device
543 * @mtd: MTD device structure
544 * @command: the command to be sent
545 * @column: the column address for this command, -1 if none
546 * @page_addr: the page address for this command, -1 if none
547 *
548 * Send command to NAND device. This function is used for small page
549 * devices (256/512 Bytes per page)
550 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200551static void nand_command(struct mtd_info *mtd, unsigned command, int column,
552 int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 register struct nand_chip *this = mtd->priv;
555
556 /* Begin command latch cycle */
557 this->hwcontrol(mtd, NAND_CTL_SETCLE);
558 /*
559 * Write out the command to the device.
560 */
561 if (command == NAND_CMD_SEQIN) {
562 int readcmd;
563
Joern Engel28318772006-05-22 23:18:05 +0200564 if (column >= mtd->writesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 /* OOB area */
Joern Engel28318772006-05-22 23:18:05 +0200566 column -= mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 readcmd = NAND_CMD_READOOB;
568 } else if (column < 256) {
569 /* First 256 bytes --> READ0 */
570 readcmd = NAND_CMD_READ0;
571 } else {
572 column -= 256;
573 readcmd = NAND_CMD_READ1;
574 }
575 this->write_byte(mtd, readcmd);
576 }
577 this->write_byte(mtd, command);
578
579 /* Set ALE and clear CLE to start address cycle */
580 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
581
582 if (column != -1 || page_addr != -1) {
583 this->hwcontrol(mtd, NAND_CTL_SETALE);
584
585 /* Serially input address */
586 if (column != -1) {
587 /* Adjust columns for 16 bit buswidth */
588 if (this->options & NAND_BUSWIDTH_16)
589 column >>= 1;
590 this->write_byte(mtd, column);
591 }
592 if (page_addr != -1) {
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200593 this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
594 this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* One more address cycle for devices > 32MiB */
596 if (this->chipsize > (32 << 20))
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200597 this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
599 /* Latch in address */
600 this->hwcontrol(mtd, NAND_CTL_CLRALE);
601 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000602
603 /*
604 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100606 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 case NAND_CMD_PAGEPROG:
610 case NAND_CMD_ERASE1:
611 case NAND_CMD_ERASE2:
612 case NAND_CMD_SEQIN:
613 case NAND_CMD_STATUS:
614 return;
615
616 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000617 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 break;
619 udelay(this->chip_delay);
620 this->hwcontrol(mtd, NAND_CTL_SETCLE);
621 this->write_byte(mtd, NAND_CMD_STATUS);
622 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100623 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return;
625
David Woodhousee0c7d762006-05-13 18:07:53 +0100626 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000628 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 * If we don't have access to the busy pin, we apply the given
630 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100631 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100633 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* Apply this short delay always to ensure that we do wait tWB in
638 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100639 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000640
641 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642}
643
644/**
645 * nand_command_lp - [DEFAULT] Send command to NAND large page device
646 * @mtd: MTD device structure
647 * @command: the command to be sent
648 * @column: the column address for this command, -1 if none
649 * @page_addr: the page address for this command, -1 if none
650 *
651 * Send command to NAND device. This is the version for the new large page devices
David Woodhousee0c7d762006-05-13 18:07:53 +0100652 * We dont have the separate regions as we have in the small page devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 * We must emulate NAND_CMD_READOOB to keep the code compatible.
654 *
655 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100656static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 register struct nand_chip *this = mtd->priv;
659
660 /* Emulate NAND_CMD_READOOB */
661 if (command == NAND_CMD_READOOB) {
Joern Engel28318772006-05-22 23:18:05 +0200662 column += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 command = NAND_CMD_READ0;
664 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /* Begin command latch cycle */
667 this->hwcontrol(mtd, NAND_CTL_SETCLE);
668 /* Write out the command to the device. */
David A. Marlin30f464b2005-01-17 18:35:25 +0000669 this->write_byte(mtd, (command & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /* End command latch cycle */
671 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
672
673 if (column != -1 || page_addr != -1) {
674 this->hwcontrol(mtd, NAND_CTL_SETALE);
675
676 /* Serially input address */
677 if (column != -1) {
678 /* Adjust columns for 16 bit buswidth */
679 if (this->options & NAND_BUSWIDTH_16)
680 column >>= 1;
681 this->write_byte(mtd, column & 0xff);
682 this->write_byte(mtd, column >> 8);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (page_addr != -1) {
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200685 this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
686 this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 /* One more address cycle for devices > 128MiB */
688 if (this->chipsize > (128 << 20))
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200689 this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
691 /* Latch in address */
692 this->hwcontrol(mtd, NAND_CTL_CLRALE);
693 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000694
695 /*
696 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000697 * status, sequential in, and deplete1 need no delay
698 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 case NAND_CMD_CACHEDPROG:
702 case NAND_CMD_PAGEPROG:
703 case NAND_CMD_ERASE1:
704 case NAND_CMD_ERASE2:
705 case NAND_CMD_SEQIN:
706 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000707 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
David Woodhousee0c7d762006-05-13 18:07:53 +0100710 /*
711 * read error status commands require only a short delay
712 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000713 case NAND_CMD_STATUS_ERROR:
714 case NAND_CMD_STATUS_ERROR0:
715 case NAND_CMD_STATUS_ERROR1:
716 case NAND_CMD_STATUS_ERROR2:
717 case NAND_CMD_STATUS_ERROR3:
718 udelay(this->chip_delay);
719 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000722 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 break;
724 udelay(this->chip_delay);
725 this->hwcontrol(mtd, NAND_CTL_SETCLE);
726 this->write_byte(mtd, NAND_CMD_STATUS);
727 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100728 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return;
730
731 case NAND_CMD_READ0:
732 /* Begin command latch cycle */
733 this->hwcontrol(mtd, NAND_CTL_SETCLE);
734 /* Write out the start read command */
735 this->write_byte(mtd, NAND_CMD_READSTART);
736 /* End command latch cycle */
737 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
738 /* Fall through into ready check */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000739
David Woodhousee0c7d762006-05-13 18:07:53 +0100740 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000742 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 * If we don't have access to the busy pin, we apply the given
744 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100747 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 /* Apply this short delay always to ensure that we do wait tWB in
753 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100754 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000755
756 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
759/**
760 * nand_get_device - [GENERIC] Get chip for selected access
761 * @this: the nand chip descriptor
762 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000763 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 *
765 * Get the device and lock it for exclusive access
766 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200767static int
768nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200770 spinlock_t *lock = &this->controller->lock;
771 wait_queue_head_t *wq = &this->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100772 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100773 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100774 spin_lock(lock);
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200777 /* Hardware controller shared among independend devices */
778 if (!this->controller->active)
779 this->controller->active = this;
780
781 if (this->controller->active == this && this->state == FL_READY) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100782 this->state = new_state;
783 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100784 return 0;
785 }
786 if (new_state == FL_PM_SUSPENDED) {
787 spin_unlock(lock);
788 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100789 }
790 set_current_state(TASK_UNINTERRUPTIBLE);
791 add_wait_queue(wq, &wait);
792 spin_unlock(lock);
793 schedule();
794 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 goto retry;
796}
797
798/**
799 * nand_wait - [DEFAULT] wait until the command is done
800 * @mtd: MTD device structure
801 * @this: NAND chip structure
802 * @state: state to select the max. timeout value
803 *
804 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000805 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 * general NAND and SmartMedia specs
807 *
808*/
809static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
810{
811
David Woodhousee0c7d762006-05-13 18:07:53 +0100812 unsigned long timeo = jiffies;
813 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100816 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100818 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Richard Purdie8fe833c2006-03-31 02:31:14 -0800820 led_trigger_event(nand_led_trigger, LED_FULL);
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* Apply this short delay always to ensure that we do wait tWB in
823 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100824 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100827 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000828 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100829 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000831 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 /* Check, if we were interrupted */
833 if (this->state != state)
834 return 0;
835
836 if (this->dev_ready) {
837 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000838 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 } else {
840 if (this->read_byte(mtd) & NAND_STATUS_READY)
841 break;
842 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000843 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800845 led_trigger_event(nand_led_trigger, LED_OFF);
846
David Woodhousee0c7d762006-05-13 18:07:53 +0100847 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 return status;
849}
850
851/**
852 * nand_write_page - [GENERIC] write one page
853 * @mtd: MTD device structure
854 * @this: NAND chip structure
855 * @page: startpage inside the chip, must be called with (page & this->pagemask)
856 * @oob_buf: out of band data buffer
857 * @oobsel: out of band selecttion structre
858 * @cached: 1 = enable cached programming if supported by chip
859 *
860 * Nand_page_program function is used for write and writev !
861 * This function will always program a full page of data
862 * If you call it with a non page aligned buffer, you're lost :)
863 *
864 * Cached programming is not supported yet.
865 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100866static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200867 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
David Woodhousee0c7d762006-05-13 18:07:53 +0100869 int i, status;
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200870 uint8_t ecc_code[32];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200871 int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
David Woodhousee0c7d762006-05-13 18:07:53 +0100872 int *oob_config = oobsel->eccpos;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200873 int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100874 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 /* FIXME: Enable cached programming */
877 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100880 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 /* Write out complete page of data, take care of eccmode */
883 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100884 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100886 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Joern Engel28318772006-05-22 23:18:05 +0200887 this->write_buf(mtd, this->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000889
David Woodhousee0c7d762006-05-13 18:07:53 +0100890 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 case NAND_ECC_SOFT:
892 for (; eccsteps; eccsteps--) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200893 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 for (i = 0; i < 3; i++, eccidx++)
895 oob_buf[oob_config[eccidx]] = ecc_code[i];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200896 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
Joern Engel28318772006-05-22 23:18:05 +0200898 this->write_buf(mtd, this->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 break;
900 default:
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200901 eccbytes = this->ecc.bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 for (; eccsteps; eccsteps--) {
903 /* enable hardware ecc logic for write */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200904 this->ecc.hwctl(mtd, NAND_ECC_WRITE);
905 this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
906 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 for (i = 0; i < eccbytes; i++, eccidx++)
908 oob_buf[oob_config[eccidx]] = ecc_code[i];
909 /* If the hardware ecc provides syndromes then
910 * the ecc code must be written immidiately after
911 * the data bytes (words) */
912 if (this->options & NAND_HWECC_SYNDROME)
913 this->write_buf(mtd, ecc_code, eccbytes);
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200914 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916 break;
917 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 /* Write out OOB data */
920 if (this->options & NAND_HWECC_SYNDROME)
921 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000922 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 this->write_buf(mtd, oob_buf, mtd->oobsize);
924
925 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100926 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 if (!cached) {
929 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100930 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000931
932 /* See if operation failed and additional status checks are available */
933 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
934 status = this->errstat(mtd, this, FL_WRITING, status, page);
935 }
936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000938 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100939 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 return -EIO;
941 }
942 } else {
943 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100944 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
946 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000947 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948}
949
950#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
951/**
952 * nand_verify_pages - [GENERIC] verify the chip contents after a write
953 * @mtd: MTD device structure
954 * @this: NAND chip structure
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200955 * @page: startpage inside the chip, must be called with (page & this->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 * @numpages: number of pages to verify
957 * @oob_buf: out of band data buffer
958 * @oobsel: out of band selecttion structre
959 * @chipnr: number of the current chip
960 * @oobmode: 1 = full buffer verify, 0 = ecc only
961 *
962 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000963 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000965 * byte by byte basis. It is possible that the page was not completely erased
966 * or the page is becoming unusable due to wear. The read with ECC would catch
967 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 * it early in the page write stage. Better to write no data than invalid data.
969 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100970static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200971 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
David Woodhousee0c7d762006-05-13 18:07:53 +0100973 int i, j, datidx = 0, oobofs = 0, res = -EIO;
974 int eccsteps = this->eccsteps;
975 int hweccbytes;
Thomas Gleixner58dd8f22006-05-23 11:52:35 +0200976 uint8_t oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
979
980 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100981 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
David Woodhousee0c7d762006-05-13 18:07:53 +0100983 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 for (j = 0; j < eccsteps; j++) {
985 /* Loop through and verify the data */
986 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100987 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 goto out;
989 }
990 datidx += mtd->eccsize;
991 /* Have we a hw generator layout ? */
992 if (!hweccbytes)
993 continue;
994 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100995 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto out;
997 }
998 oobofs += hweccbytes;
999 }
1000
1001 /* check, if we must compare all data or if we just have to
1002 * compare the ecc bytes
1003 */
1004 if (oobmode) {
1005 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001006 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 goto out;
1008 }
1009 } else {
1010 /* Read always, else autoincrement fails */
1011 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
1012
1013 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
1014 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 for (i = 0; i < ecccnt; i++) {
1017 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +01001018 if (oobdata[idx] != oob_buf[oobofs + idx]) {
1019 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
1020 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 goto out;
1022 }
1023 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
1026 oobofs += mtd->oobsize - hweccbytes * eccsteps;
1027 page++;
1028 numpages--;
1029
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001030 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 * Do this before the AUTOINCR check, so no problems
1032 * arise if a chip which does auto increment
1033 * is marked as NOAUTOINCR by the board driver.
1034 * Do this also before returning, so the chip is
1035 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +01001036 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001037 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001038 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001040 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* All done, return happy */
1043 if (!numpages)
1044 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001045
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001046 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001048 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001050 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 * Terminate the read command. We come here in case of an error
1052 * So we must issue a reset command.
1053 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001054 out:
1055 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return res;
1057}
1058#endif
1059
1060/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001061 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 * @mtd: MTD device structure
1063 * @from: offset to read from
1064 * @len: number of bytes to read
1065 * @retlen: pointer to variable to store the number of read bytes
1066 * @buf: the databuffer to put data
1067 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001068 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1069 * and flags = 0xff
1070 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001071static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
David Woodhousee0c7d762006-05-13 18:07:53 +01001073 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001074}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001077 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1078 * @mtd: MTD device structure
1079 * @from: offset to read from
1080 * @len: number of bytes to read
1081 * @retlen: pointer to variable to store the number of read bytes
1082 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001083 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001084 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001085 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1086 * and how many corrected error bits are acceptable:
1087 * bits 0..7 - number of tolerable errors
1088 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1089 *
1090 * NAND read with ECC
1091 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001092int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001093 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001094{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1097 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1098 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001099 uint8_t *data_poi, *oob_data = oob_buf;
1100 uint8_t ecc_calc[32];
1101 uint8_t ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001102 int eccmode, eccsteps;
1103 int *oob_config, datidx;
1104 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1105 int eccbytes;
1106 int compareecc = 1;
1107 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
David Woodhousee0c7d762006-05-13 18:07:53 +01001109 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 -07001110
1111 /* Do not allow reads past end of device */
1112 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001113 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 *retlen = 0;
1115 return -EINVAL;
1116 }
1117
1118 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001119 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001120 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 /* Autoplace of oob data ? Use the default placement scheme */
1123 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1124 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001125
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001126 eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 oob_config = oobsel->eccpos;
1128
1129 /* Select the NAND device */
1130 chipnr = (int)(from >> this->chip_shift);
1131 this->select_chip(mtd, chipnr);
1132
1133 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001134 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 page = realpage & this->pagemask;
1136
1137 /* Get raw starting column */
Joern Engel28318772006-05-22 23:18:05 +02001138 col = from & (mtd->writesize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Joern Engel28318772006-05-22 23:18:05 +02001140 end = mtd->writesize;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001141 ecc = this->ecc.size;
1142 eccbytes = this->ecc.bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1145 compareecc = 0;
1146
1147 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001148 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 oobreadlen -= oobsel->eccbytes;
1150
1151 /* Loop until all data read */
1152 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001155 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 * If the read is not page aligned, we have to read into data buffer
1157 * due to ecc, else we read into return buffer direct
1158 */
1159 if (aligned)
1160 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001161 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001163
1164 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 *
1166 * FIXME: Make it work when we must provide oob data too,
1167 * check the usage of data_buf oob field
1168 */
1169 if (realpage == this->pagebuf && !oob_buf) {
1170 /* aligned read ? */
1171 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001172 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 goto readdata;
1174 }
1175
1176 /* Check, if we must send the read command */
1177 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001178 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001183 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1184 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 oob_data = &this->data_buf[end];
1186
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001187 eccsteps = this->ecc.steps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001190 case NAND_ECC_NONE:{
1191 /* No ECC, Read in a page */
1192 static unsigned long lastwhinge = 0;
1193 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1194 printk(KERN_WARNING
1195 "Reading data from NAND FLASH without ECC is not recommended\n");
1196 lastwhinge = jiffies;
1197 }
1198 this->read_buf(mtd, data_poi, end);
1199 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1203 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001204 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001205 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001206 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001209 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001210 this->ecc.hwctl(mtd, NAND_ECC_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 this->read_buf(mtd, &data_poi[datidx], ecc);
1212
1213 /* HW ecc with syndrome calculation must read the
1214 * syndrome from flash immidiately after the data */
1215 if (!compareecc) {
1216 /* Some hw ecc generators need to know when the
1217 * syndrome is read from flash */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001218 this->ecc.hwctl(mtd, NAND_ECC_READSYN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 this->read_buf(mtd, &oob_data[i], eccbytes);
1220 /* We calc error correction directly, it checks the hw
1221 * generator for an error, reads back the syndrome and
1222 * does the error correction on the fly */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001223 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
David A. Marlin068e3c02005-01-24 03:07:46 +00001224 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001225 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1226 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 ecc_failed++;
1228 }
1229 } else {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001230 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001233 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235
1236 /* read oobdata */
1237 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1238
1239 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1240 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001241 goto readoob;
1242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 /* Pick the ECC bytes out of the oob data */
1244 for (j = 0; j < oobsel->eccbytes; j++)
1245 ecc_code[j] = oob_data[oob_config[j]];
1246
David Woodhousee0c7d762006-05-13 18:07:53 +01001247 /* correct data, if necessary */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001248 for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
1249 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 /* Get next chunk of ecc bytes */
1252 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001253
1254 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 * This is the legacy mode. Used by YAFFS1
1256 * Should go away some day
1257 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001258 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 int *p = (int *)(&oob_data[mtd->oobsize]);
1260 p[i] = ecc_status;
1261 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001262
1263 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001264 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 ecc_failed++;
1266 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
David Woodhousee0c7d762006-05-13 18:07:53 +01001269 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 /* check, if we have a fs supplied oob-buffer */
1271 if (oob_buf) {
1272 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001273 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001275 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001277 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 int from = oobsel->oobfree[i][0];
1279 int num = oobsel->oobfree[i][1];
1280 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001281 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 break;
1284 case MTD_NANDECC_PLACE:
1285 /* YAFFS1 legacy mode */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001286 oob_data += this->ecc.steps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 default:
1288 oob_data += mtd->oobsize;
1289 }
1290 }
1291 readdata:
1292 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001293 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 for (j = col; j < end && read < len; j++)
1295 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001296 this->pagebuf = realpage;
1297 } else
Joern Engel28318772006-05-22 23:18:05 +02001298 read += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001300 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 * Do this before the AUTOINCR check, so no problems
1302 * arise if a chip which does auto increment
1303 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001304 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001305 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001306 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001308 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001311 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 /* For subsequent reads align to page boundary. */
1314 col = 0;
1315 /* Increment page address */
1316 realpage++;
1317
1318 page = realpage & this->pagemask;
1319 /* Check, if we cross a chip boundary */
1320 if (!page) {
1321 chipnr++;
1322 this->select_chip(mtd, -1);
1323 this->select_chip(mtd, chipnr);
1324 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001325 /* Check, if the chip supports auto page increment
1326 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001327 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001329 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 }
1331
1332 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001333 if (flags & NAND_GET_DEVICE)
1334 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336 /*
1337 * Return success, if no ECC failures, else -EBADMSG
1338 * fs driver will take care of that, because
1339 * retlen == desired len and result == -EBADMSG
1340 */
1341 *retlen = read;
1342 return ecc_failed ? -EBADMSG : 0;
1343}
1344
1345/**
1346 * nand_read_oob - [MTD Interface] NAND read out-of-band
1347 * @mtd: MTD device structure
1348 * @from: offset to read from
1349 * @len: number of bytes to read
1350 * @retlen: pointer to variable to store the number of read bytes
1351 * @buf: the databuffer to put data
1352 *
1353 * NAND read out-of-band data from the spare area
1354 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001355static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356{
1357 int i, col, page, chipnr;
1358 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001359 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
David Woodhousee0c7d762006-05-13 18:07:53 +01001361 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 -07001362
1363 /* Shift to get page */
1364 page = (int)(from >> this->page_shift);
1365 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 /* Mask to get column */
1368 col = from & (mtd->oobsize - 1);
1369
1370 /* Initialize return length value */
1371 *retlen = 0;
1372
1373 /* Do not allow reads past end of device */
1374 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001375 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 *retlen = 0;
1377 return -EINVAL;
1378 }
1379
1380 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001381 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 /* Select the NAND device */
1384 this->select_chip(mtd, chipnr);
1385
1386 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001387 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001388 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 * Read the data, if we read more than one page
1390 * oob data, let the device transfer the data !
1391 */
1392 i = 0;
1393 while (i < len) {
1394 int thislen = mtd->oobsize - col;
1395 thislen = min_t(int, thislen, len);
1396 this->read_buf(mtd, &buf[i], thislen);
1397 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 /* Read more ? */
1400 if (i < len) {
1401 page++;
1402 col = 0;
1403
1404 /* Check, if we cross a chip boundary */
1405 if (!(page & this->pagemask)) {
1406 chipnr++;
1407 this->select_chip(mtd, -1);
1408 this->select_chip(mtd, chipnr);
1409 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001410
1411 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001412 * Do this before the AUTOINCR check, so no problems
1413 * arise if a chip which does auto increment
1414 * is marked as NOAUTOINCR by the board driver.
1415 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001416 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001417 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001418 else
1419 nand_wait_ready(mtd);
1420
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001421 /* Check, if the chip supports auto page increment
1422 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001423 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1425 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001426 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 }
1428 }
1429 }
1430
1431 /* Deselect and wake up anyone waiting on the device */
1432 nand_release_device(mtd);
1433
1434 /* Return happy */
1435 *retlen = len;
1436 return 0;
1437}
1438
1439/**
1440 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1441 * @mtd: MTD device structure
1442 * @buf: temporary buffer
1443 * @from: offset to read from
1444 * @len: number of bytes to read
1445 * @ooblen: number of oob data bytes to read
1446 *
1447 * Read raw data including oob into buffer
1448 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001449int 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 -07001450{
1451 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001452 int page = (int)(from >> this->page_shift);
1453 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 int sndcmd = 1;
1455 int cnt = 0;
Joern Engel28318772006-05-22 23:18:05 +02001456 int pagesize = mtd->writesize + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001457 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 /* Do not allow reads past end of device */
1460 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001461 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 return -EINVAL;
1463 }
1464
1465 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001466 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
David Woodhousee0c7d762006-05-13 18:07:53 +01001468 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 /* Add requested oob length */
1471 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 while (len) {
1474 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001475 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001476 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
David Woodhousee0c7d762006-05-13 18:07:53 +01001478 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 len -= pagesize;
1481 cnt += pagesize;
1482 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001483
1484 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001485 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001487 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001488
1489 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1491 sndcmd = 1;
1492 }
1493
1494 /* Deselect and wake up anyone waiting on the device */
1495 nand_release_device(mtd);
1496 return 0;
1497}
1498
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001499/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001500 * nand_write_raw - [GENERIC] Write raw data including oob
1501 * @mtd: MTD device structure
1502 * @buf: source buffer
1503 * @to: offset to write to
1504 * @len: number of bytes to write
1505 * @buf: source buffer
1506 * @oob: oob buffer
1507 *
1508 * Write raw data including oob
1509 */
1510int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1511 uint8_t *buf, uint8_t *oob)
1512{
1513 struct nand_chip *this = mtd->priv;
1514 int page = (int)(to >> this->page_shift);
1515 int chip = (int)(to >> this->chip_shift);
1516 int ret;
1517
1518 *retlen = 0;
1519
1520 /* Do not allow writes past end of device */
1521 if ((to + len) > mtd->size) {
1522 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
1523 "beyond end of device\n");
1524 return -EINVAL;
1525 }
1526
1527 /* Grab the lock and see if the device is available */
1528 nand_get_device(this, mtd, FL_WRITING);
1529
1530 this->select_chip(mtd, chip);
1531 this->data_poi = buf;
1532
1533 while (len != *retlen) {
1534 ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0);
1535 if (ret)
1536 return ret;
1537 page++;
1538 *retlen += mtd->writesize;
1539 this->data_poi += mtd->writesize;
1540 oob += mtd->oobsize;
1541 }
1542
1543 /* Deselect and wake up anyone waiting on the device */
1544 nand_release_device(mtd);
1545 return 0;
1546}
1547
1548/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001549 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 * @mtd: MTD device structure
1551 * @fsbuf: buffer given by fs driver
1552 * @oobsel: out of band selection structre
1553 * @autoplace: 1 = place given buffer into the oob bytes
1554 * @numpages: number of pages to prepare
1555 *
1556 * Return:
1557 * 1. Filesystem buffer available and autoplacement is off,
1558 * return filesystem buffer
1559 * 2. No filesystem buffer or autoplace is off, return internal
1560 * buffer
1561 * 3. Filesystem buffer is given and autoplace selected
1562 * put data from fs buffer into internal buffer and
1563 * retrun internal buffer
1564 *
1565 * Note: The internal buffer is filled with 0xff. This must
1566 * be done only once, when no autoplacement happens
1567 * Autoplacement sets the buffer dirty flag, which
1568 * forces the 0xff fill before using the buffer again.
1569 *
1570*/
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001571static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
David Woodhousee0c7d762006-05-13 18:07:53 +01001572 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
1574 struct nand_chip *this = mtd->priv;
1575 int i, len, ofs;
1576
1577 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001578 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return fsbuf;
1580
1581 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001582 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001583 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001585 }
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 /* If we have no autoplacement or no fs buffer use the internal one */
1588 if (!autoplace || !fsbuf)
1589 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001590
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 /* Walk through the pages and place the data */
1592 this->oobdirty = 1;
1593 ofs = 0;
1594 while (numpages--) {
1595 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1596 int to = ofs + oobsel->oobfree[i][0];
1597 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001598 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 len += num;
1600 fsbuf += num;
1601 }
1602 ofs += mtd->oobavail;
1603 }
1604 return this->oob_buf;
1605}
1606
Joern Engel28318772006-05-22 23:18:05 +02001607#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
1609/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001610 * nand_write - [MTD Interface] NAND write with ECC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 * @mtd: MTD device structure
1612 * @to: offset to write to
1613 * @len: number of bytes to write
1614 * @retlen: pointer to variable to store the number of written bytes
1615 * @buf: the data to write
1616 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 * NAND write with ECC
1618 */
Thomas Gleixner9223a452006-05-23 17:21:03 +02001619static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1620 size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621{
1622 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1623 int autoplace = 0, numpages, totalpages;
1624 struct nand_chip *this = mtd->priv;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001625 uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
David Woodhousee0c7d762006-05-13 18:07:53 +01001626 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Thomas Gleixner9223a452006-05-23 17:21:03 +02001627 struct nand_oobinfo *oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Thomas Gleixner9223a452006-05-23 17:21:03 +02001629 DEBUG(MTD_DEBUG_LEVEL3, "nand_write: 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) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001636 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: 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)) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001642 printk(KERN_NOTICE "nand_write: 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 /* Autoplace of oob data ? Use the default placement scheme */
1659 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1660 oobsel = this->autooob;
1661 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001662 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001663 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1664 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 /* Setup variables and oob buffer */
1667 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001668 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001670 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Set it relative to chip */
1674 page &= this->pagemask;
1675 startpage = page;
1676 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001677 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1678 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001679 bufstart = (uint8_t *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
1681 /* Loop until all data is written */
1682 while (written < len) {
1683
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001684 this->data_poi = (uint8_t *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 /* Write one page. If this is the last page to write
1686 * or the last page in this block, then use the
1687 * real pageprogram command, else select cached programming
1688 * if supported by the chip.
1689 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001690 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001692 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 /* Next oob page */
1696 oob += mtd->oobsize;
1697 /* Update written bytes count */
Joern Engel28318772006-05-22 23:18:05 +02001698 written += mtd->writesize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001699 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 /* Increment page address */
1703 page++;
1704
1705 /* Have we hit a block boundary ? Then we have to verify and
1706 * if verify is ok, we have to setup the oob buffer for
1707 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001708 */
1709 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 int ofs;
1711 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001712 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1713 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001715 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 *retlen = written;
1719
1720 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1721 if (eccbuf)
1722 eccbuf += (page - startpage) * ofs;
1723 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001724 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 page &= this->pagemask;
1726 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001727 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001728 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* Check, if we cross a chip boundary */
1730 if (!page) {
1731 chipnr++;
1732 this->select_chip(mtd, -1);
1733 this->select_chip(mtd, chipnr);
1734 }
1735 }
1736 }
1737 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001738 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001740 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (!ret)
1742 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001743 else
Thomas Gleixner9223a452006-05-23 17:21:03 +02001744 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
David Woodhousee0c7d762006-05-13 18:07:53 +01001746 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 /* Deselect and wake up anyone waiting on the device */
1748 nand_release_device(mtd);
1749
1750 return ret;
1751}
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753/**
1754 * nand_write_oob - [MTD Interface] NAND write out-of-band
1755 * @mtd: MTD device structure
1756 * @to: offset to write to
1757 * @len: number of bytes to write
1758 * @retlen: pointer to variable to store the number of written bytes
1759 * @buf: the data to write
1760 *
1761 * NAND write out-of-band
1762 */
Thomas Gleixner58dd8f22006-05-23 11:52:35 +02001763static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764{
1765 int column, page, status, ret = -EIO, chipnr;
1766 struct nand_chip *this = mtd->priv;
1767
David Woodhousee0c7d762006-05-13 18:07:53 +01001768 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 -07001769
1770 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001771 page = (int)(to >> this->page_shift);
1772 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 /* Mask to get column */
1775 column = to & (mtd->oobsize - 1);
1776
1777 /* Initialize return length value */
1778 *retlen = 0;
1779
1780 /* Do not allow write past end of page */
1781 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001782 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 return -EINVAL;
1784 }
1785
1786 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001787 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
1789 /* Select the NAND device */
1790 this->select_chip(mtd, chipnr);
1791
1792 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1793 in one of my DiskOnChip 2000 test units) will clear the whole
1794 data page too if we don't do this. I have no clue why, but
1795 I seem to have 'fixed' it in the doc2000 driver in
1796 August 1999. dwmw2. */
1797 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1798
1799 /* Check, if it is write protected */
1800 if (nand_check_wp(mtd))
1801 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 /* Invalidate the page cache, if we write to the cached page */
1804 if (page == this->pagebuf)
1805 this->pagebuf = -1;
1806
1807 if (NAND_MUST_PAD(this)) {
1808 /* Write out desired data */
Joern Engel28318772006-05-22 23:18:05 +02001809 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 /* prepad 0xff for partial programming */
1811 this->write_buf(mtd, ffchars, column);
1812 /* write data */
1813 this->write_buf(mtd, buf, len);
1814 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001815 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 } else {
1817 /* Write out desired data */
Joern Engel28318772006-05-22 23:18:05 +02001818 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* write data */
1820 this->write_buf(mtd, buf, len);
1821 }
1822 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001823 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
David Woodhousee0c7d762006-05-13 18:07:53 +01001825 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001828 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001829 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 ret = -EIO;
1831 goto out;
1832 }
1833 /* Return happy */
1834 *retlen = len;
1835
1836#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1837 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001838 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001841 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ret = -EIO;
1843 goto out;
1844 }
1845#endif
1846 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001847 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 /* Deselect and wake up anyone waiting on the device */
1849 nand_release_device(mtd);
1850
1851 return ret;
1852}
1853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 * single_erease_cmd - [GENERIC] NAND standard block erase command function
1856 * @mtd: MTD device structure
1857 * @page: the page address of the block which will be erased
1858 *
1859 * Standard erase command for NAND chips
1860 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001861static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862{
1863 struct nand_chip *this = mtd->priv;
1864 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01001865 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1866 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867}
1868
1869/**
1870 * multi_erease_cmd - [GENERIC] AND specific block erase command function
1871 * @mtd: MTD device structure
1872 * @page: the page address of the block which will be erased
1873 *
1874 * AND multi block erase command function
1875 * Erase 4 consecutive blocks
1876 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001877static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878{
1879 struct nand_chip *this = mtd->priv;
1880 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01001881 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1882 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1883 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1884 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1885 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886}
1887
1888/**
1889 * nand_erase - [MTD Interface] erase block(s)
1890 * @mtd: MTD device structure
1891 * @instr: erase instruction
1892 *
1893 * Erase one ore more blocks
1894 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001895static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896{
David Woodhousee0c7d762006-05-13 18:07:53 +01001897 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001899
David A. Marlin30f464b2005-01-17 18:35:25 +00001900#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901/**
1902 * nand_erase_intern - [NAND Interface] erase block(s)
1903 * @mtd: MTD device structure
1904 * @instr: erase instruction
1905 * @allowbbt: allow erasing the bbt area
1906 *
1907 * Erase one ore more blocks
1908 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001909int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910{
1911 int page, len, status, pages_per_block, ret, chipnr;
1912 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00001913 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
1914 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
1915 /* It is used to see if the current page is in the same */
1916 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
David Woodhousee0c7d762006-05-13 18:07:53 +01001918 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 -07001919
1920 /* Start address must align on block boundary */
1921 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001922 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 return -EINVAL;
1924 }
1925
1926 /* Length must align on block boundary */
1927 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001928 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 return -EINVAL;
1930 }
1931
1932 /* Do not allow erase past end of device */
1933 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001934 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 return -EINVAL;
1936 }
1937
1938 instr->fail_addr = 0xffffffff;
1939
1940 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001941 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001944 page = (int)(instr->addr >> this->page_shift);
1945 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
1947 /* Calculate pages in each block */
1948 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
1949
1950 /* Select the NAND device */
1951 this->select_chip(mtd, chipnr);
1952
1953 /* Check the WP bit */
1954 /* Check, if it is write protected */
1955 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001956 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 instr->state = MTD_ERASE_FAILED;
1958 goto erase_exit;
1959 }
1960
David A. Marlin30f464b2005-01-17 18:35:25 +00001961 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
1962 if (this->options & BBT_AUTO_REFRESH) {
1963 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
1964 } else {
1965 bbt_masked_page = 0xffffffff; /* should not match anything */
1966 }
1967
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 /* Loop through the pages */
1969 len = instr->len;
1970
1971 instr->state = MTD_ERASING;
1972
1973 while (len) {
1974 /* Check if we have a bad block, we do not erase bad blocks ! */
1975 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001976 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 instr->state = MTD_ERASE_FAILED;
1978 goto erase_exit;
1979 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001980
1981 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 the current cached page */
1983 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
1984 this->pagebuf = -1;
1985
David Woodhousee0c7d762006-05-13 18:07:53 +01001986 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001987
David Woodhousee0c7d762006-05-13 18:07:53 +01001988 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
David A. Marlin068e3c02005-01-24 03:07:46 +00001990 /* See if operation failed and additional status checks are available */
1991 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
1992 status = this->errstat(mtd, this, FL_ERASING, status, page);
1993 }
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001996 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001997 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 instr->state = MTD_ERASE_FAILED;
1999 instr->fail_addr = (page << this->page_shift);
2000 goto erase_exit;
2001 }
David A. Marlin30f464b2005-01-17 18:35:25 +00002002
2003 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
2004 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002005 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00002006 (page != this->bbt_td->pages[chipnr])) {
2007 rewrite_bbt[chipnr] = (page << this->page_shift);
2008 }
2009 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 /* Increment page address and decrement length */
2012 len -= (1 << this->phys_erase_shift);
2013 page += pages_per_block;
2014
2015 /* Check, if we cross a chip boundary */
2016 if (len && !(page & this->pagemask)) {
2017 chipnr++;
2018 this->select_chip(mtd, -1);
2019 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00002020
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002021 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00002022 * set the BBT page mask to see if this BBT should be rewritten */
2023 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
2024 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2025 }
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 }
2028 }
2029 instr->state = MTD_ERASE_DONE;
2030
David Woodhousee0c7d762006-05-13 18:07:53 +01002031 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
2034 /* Do call back function */
2035 if (!ret)
2036 mtd_erase_callback(instr);
2037
2038 /* Deselect and wake up anyone waiting on the device */
2039 nand_release_device(mtd);
2040
David A. Marlin30f464b2005-01-17 18:35:25 +00002041 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
2042 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
2043 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
2044 if (rewrite_bbt[chipnr]) {
2045 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01002046 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2047 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2048 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002049 }
2050 }
2051 }
2052
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 /* Return more or less happy */
2054 return ret;
2055}
2056
2057/**
2058 * nand_sync - [MTD Interface] sync
2059 * @mtd: MTD device structure
2060 *
2061 * Sync is actually a wait for chip ready function
2062 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002063static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
2065 struct nand_chip *this = mtd->priv;
2066
David Woodhousee0c7d762006-05-13 18:07:53 +01002067 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002070 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002072 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073}
2074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075/**
2076 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2077 * @mtd: MTD device structure
2078 * @ofs: offset relative to mtd start
2079 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002080static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081{
2082 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002083 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002085
David Woodhousee0c7d762006-05-13 18:07:53 +01002086 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087}
2088
2089/**
2090 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2091 * @mtd: MTD device structure
2092 * @ofs: offset relative to mtd start
2093 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002094static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095{
2096 struct nand_chip *this = mtd->priv;
2097 int ret;
2098
David Woodhousee0c7d762006-05-13 18:07:53 +01002099 if ((ret = nand_block_isbad(mtd, ofs))) {
2100 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 if (ret > 0)
2102 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002103 return ret;
2104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
2106 return this->block_markbad(mtd, ofs);
2107}
2108
2109/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002110 * nand_suspend - [MTD Interface] Suspend the NAND flash
2111 * @mtd: MTD device structure
2112 */
2113static int nand_suspend(struct mtd_info *mtd)
2114{
2115 struct nand_chip *this = mtd->priv;
2116
David Woodhousee0c7d762006-05-13 18:07:53 +01002117 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002118}
2119
2120/**
2121 * nand_resume - [MTD Interface] Resume the NAND flash
2122 * @mtd: MTD device structure
2123 */
2124static void nand_resume(struct mtd_info *mtd)
2125{
2126 struct nand_chip *this = mtd->priv;
2127
2128 if (this->state == FL_PM_SUSPENDED)
2129 nand_release_device(mtd);
2130 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002131 printk(KERN_ERR "nand_resume() called for a chip which is not "
2132 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002133}
2134
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002135/*
2136 * Free allocated data structures
2137 */
2138static void nand_free_kmem(struct nand_chip *this)
2139{
2140 /* Buffer allocated by nand_scan ? */
2141 if (this->options & NAND_OOBBUF_ALLOC)
2142 kfree(this->oob_buf);
2143 /* Buffer allocated by nand_scan ? */
2144 if (this->options & NAND_DATABUF_ALLOC)
2145 kfree(this->data_buf);
2146 /* Controller allocated by nand_scan ? */
2147 if (this->options & NAND_CONTROLLER_ALLOC)
2148 kfree(this->controller);
2149}
2150
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002151/*
2152 * Allocate buffers and data structures
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002154static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155{
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002156 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002158 if (!this->oob_buf) {
2159 len = mtd->oobsize <<
2160 (this->phys_erase_shift - this->page_shift);
2161 this->oob_buf = kmalloc(len, GFP_KERNEL);
2162 if (!this->oob_buf)
2163 goto outerr;
2164 this->options |= NAND_OOBBUF_ALLOC;
David Woodhouse552d9202006-05-14 01:20:46 +01002165 }
2166
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002167 if (!this->data_buf) {
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002168 len = mtd->writesize + mtd->oobsize;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002169 this->data_buf = kmalloc(len, GFP_KERNEL);
2170 if (!this->data_buf)
2171 goto outerr;
2172 this->options |= NAND_DATABUF_ALLOC;
2173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002175 if (!this->controller) {
2176 this->controller = kzalloc(sizeof(struct nand_hw_control),
2177 GFP_KERNEL);
2178 if (!this->controller)
2179 goto outerr;
2180 this->options |= NAND_CONTROLLER_ALLOC;
2181 }
2182 return 0;
2183
2184 outerr:
2185 printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
2186 nand_free_kmem(this);
2187 return -ENOMEM;
2188}
2189
2190/*
2191 * Set default functions
2192 */
2193static void nand_set_defaults(struct nand_chip *this, int busw)
2194{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 /* check for proper chip_delay setup, set 20us if not */
2196 if (!this->chip_delay)
2197 this->chip_delay = 20;
2198
2199 /* check, if a user supplied command function given */
2200 if (this->cmdfunc == NULL)
2201 this->cmdfunc = nand_command;
2202
2203 /* check, if a user supplied wait function given */
2204 if (this->waitfunc == NULL)
2205 this->waitfunc = nand_wait;
2206
2207 if (!this->select_chip)
2208 this->select_chip = nand_select_chip;
2209 if (!this->write_byte)
2210 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
2211 if (!this->read_byte)
2212 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2213 if (!this->write_word)
2214 this->write_word = nand_write_word;
2215 if (!this->read_word)
2216 this->read_word = nand_read_word;
2217 if (!this->block_bad)
2218 this->block_bad = nand_block_bad;
2219 if (!this->block_markbad)
2220 this->block_markbad = nand_default_block_markbad;
2221 if (!this->write_buf)
2222 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2223 if (!this->read_buf)
2224 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2225 if (!this->verify_buf)
2226 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2227 if (!this->scan_bbt)
2228 this->scan_bbt = nand_default_bbt;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002229}
2230
2231/*
2232 * Get the flash and manufacturer id and lookup if the typ is supported
2233 */
2234static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2235 struct nand_chip *this,
2236 int busw, int *maf_id)
2237{
2238 struct nand_flash_dev *type = NULL;
2239 int i, dev_id, maf_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
2241 /* Select the device */
2242 this->select_chip(mtd, 0);
2243
2244 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002245 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 /* Read manufacturer and device IDs */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002248 *maf_id = this->read_byte(mtd);
2249 dev_id = this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002251 /* Lookup the flash id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002253 if (dev_id == nand_flash_ids[i].id) {
2254 type = &nand_flash_ids[i];
2255 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
2258
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002259 if (!type)
2260 return ERR_PTR(-ENODEV);
2261
2262 this->chipsize = nand_flash_ids[i].chipsize << 20;
2263
2264 /* Newer devices have all the information in additional id bytes */
2265 if (!nand_flash_ids[i].pagesize) {
2266 int extid;
2267 /* The 3rd id byte contains non relevant data ATM */
2268 extid = this->read_byte(mtd);
2269 /* The 4th id byte is the important one */
2270 extid = this->read_byte(mtd);
2271 /* Calc pagesize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002272 mtd->writesize = 1024 << (extid & 0x3);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002273 extid >>= 2;
2274 /* Calc oobsize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002275 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002276 extid >>= 2;
2277 /* Calc blocksize. Blocksize is multiples of 64KiB */
2278 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2279 extid >>= 2;
2280 /* Get buswidth information */
2281 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
2282
2283 } else {
2284 /*
2285 * Old devices have this data hardcoded in the device id table
2286 */
2287 mtd->erasesize = nand_flash_ids[i].erasesize;
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002288 mtd->writesize = nand_flash_ids[i].pagesize;
2289 mtd->oobsize = mtd->writesize / 32;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002290 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2291 }
2292
2293 /* Try to identify manufacturer */
2294 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
2295 if (nand_manuf_ids[maf_idx].id == *maf_id)
2296 break;
2297 }
2298
2299 /*
2300 * Check, if buswidth is correct. Hardware drivers should set
2301 * this correct !
2302 */
2303 if (busw != (this->options & NAND_BUSWIDTH_16)) {
2304 printk(KERN_INFO "NAND device: Manufacturer ID:"
2305 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2306 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2307 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
2308 (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
2309 busw ? 16 : 8);
2310 return ERR_PTR(-EINVAL);
2311 }
2312
2313 /* Calculate the address shift from the page size */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002314 this->page_shift = ffs(mtd->writesize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002315 /* Convert chipsize to number of pages per chip -1. */
2316 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2317
2318 this->bbt_erase_shift = this->phys_erase_shift =
2319 ffs(mtd->erasesize) - 1;
2320 this->chip_shift = ffs(this->chipsize) - 1;
2321
2322 /* Set the bad block position */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002323 this->badblockpos = mtd->writesize > 512 ?
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002324 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2325
2326 /* Get chip options, preserve non chip based options */
2327 this->options &= ~NAND_CHIPOPTIONS_MSK;
2328 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
2329
2330 /*
2331 * Set this as a default. Board drivers can override it, if necessary
2332 */
2333 this->options |= NAND_NO_AUTOINCR;
2334
2335 /* Check if this is a not a samsung device. Do not clear the
2336 * options for chips which are not having an extended id.
2337 */
2338 if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2339 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
2340
2341 /* Check for AND chips with 4 page planes */
2342 if (this->options & NAND_4PAGE_ARRAY)
2343 this->erase_cmd = multi_erase_cmd;
2344 else
2345 this->erase_cmd = single_erase_cmd;
2346
2347 /* Do not replace user supplied command function ! */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002348 if (mtd->writesize > 512 && this->cmdfunc == nand_command)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002349 this->cmdfunc = nand_command_lp;
2350
2351 printk(KERN_INFO "NAND device: Manufacturer ID:"
2352 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2353 nand_manuf_ids[maf_idx].name, type->name);
2354
2355 return type;
2356}
2357
2358/* module_text_address() isn't exported, and it's mostly a pointless
2359 test if this is a module _anyway_ -- they'd have to try _really_ hard
2360 to call us from in-kernel code if the core NAND support is modular. */
2361#ifdef MODULE
2362#define caller_is_module() (1)
2363#else
2364#define caller_is_module() \
2365 module_text_address((unsigned long)__builtin_return_address(0))
2366#endif
2367
2368/**
2369 * nand_scan - [NAND Interface] Scan for the NAND device
2370 * @mtd: MTD device structure
2371 * @maxchips: Number of chips to scan for
2372 *
2373 * This fills out all the uninitialized function pointers
2374 * with the defaults.
2375 * The flash ID is read and the mtd/chip structures are
2376 * filled with the appropriate values. Buffers are allocated if
2377 * they are not provided by the board driver
2378 * The mtd->owner field must be set to the module of the caller
2379 *
2380 */
2381int nand_scan(struct mtd_info *mtd, int maxchips)
2382{
2383 int i, busw, nand_maf_id;
2384 struct nand_chip *this = mtd->priv;
2385 struct nand_flash_dev *type;
2386
2387 /* Many callers got this wrong, so check for it for a while... */
2388 if (!mtd->owner && caller_is_module()) {
2389 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2390 BUG();
2391 }
2392
2393 /* Get buswidth to select the correct functions */
2394 busw = this->options & NAND_BUSWIDTH_16;
2395 /* Set the default functions */
2396 nand_set_defaults(this, busw);
2397
2398 /* Read the flash type */
2399 type = nand_get_flash_type(mtd, this, busw, &nand_maf_id);
2400
2401 if (IS_ERR(type)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002402 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 this->select_chip(mtd, -1);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002404 return PTR_ERR(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002407 /* Check for a chip array */
David Woodhousee0c7d762006-05-13 18:07:53 +01002408 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 this->select_chip(mtd, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 /* 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 /* Read manufacturer and device IDs */
2413 if (nand_maf_id != this->read_byte(mtd) ||
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002414 type->id != this->read_byte(mtd))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 break;
2416 }
2417 if (i > 1)
2418 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002419
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 /* Store the number of chips and calc total size for mtd */
2421 this->numchips = i;
2422 mtd->size = i * this->chipsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002424 /* Allocate buffers and data structures */
2425 if (nand_allocate_kmem(mtd, this))
2426 return -ENOMEM;
2427
2428 /* Preset the internal oob buffer */
2429 memset(this->oob_buf, 0xff,
2430 mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2431
2432 /*
2433 * If no default placement scheme is given, select an appropriate one
2434 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 if (!this->autooob) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002436 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 case 8:
2438 this->autooob = &nand_oob_8;
2439 break;
2440 case 16:
2441 this->autooob = &nand_oob_16;
2442 break;
2443 case 64:
2444 this->autooob = &nand_oob_64;
2445 break;
2446 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002447 printk(KERN_WARNING "No oob scheme defined for "
2448 "oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 BUG();
2450 }
2451 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002452
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002453 /*
2454 * The number of bytes available for the filesystem to place fs
2455 * dependend oob data
2456 */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002457 mtd->oobavail = 0;
2458 for (i = 0; this->autooob->oobfree[i][1]; i++)
2459 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002461 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002462 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2463 * selected and we have 256 byte pagesize fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002464 */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002465 switch (this->ecc.mode) {
2466 case NAND_ECC_HW:
2467 case NAND_ECC_HW_SYNDROME:
2468 if (!this->ecc.calculate || !this->ecc.correct ||
2469 !this->ecc.hwctl) {
2470 printk(KERN_WARNING "No ECC functions supplied, "
2471 "Hardware ECC not possible\n");
2472 BUG();
2473 }
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002474 if (mtd->writesize >= this->ecc.size)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002475 break;
2476 printk(KERN_WARNING "%d byte HW ECC not possible on "
2477 "%d byte page size, fallback to SW ECC\n",
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002478 this->ecc.size, mtd->writesize);
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002479 this->ecc.mode = NAND_ECC_SOFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002481 case NAND_ECC_SOFT:
2482 this->ecc.calculate = nand_calculate_ecc;
2483 this->ecc.correct = nand_correct_data;
2484 this->ecc.size = 256;
2485 this->ecc.bytes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002487
2488 case NAND_ECC_NONE:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002489 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2490 "This is not recommended !!\n");
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002491 this->ecc.size = mtd->writesize;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002492 this->ecc.bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002495 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002496 this->ecc.mode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002497 BUG();
2498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002500 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002501 * Set the number of read / write steps for one page depending on ECC
2502 * mode
2503 */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002504 this->ecc.steps = mtd->writesize / this->ecc.size;
2505 if(this->ecc.steps * this->ecc.size != mtd->writesize) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002506 printk(KERN_WARNING "Invalid ecc parameters\n");
2507 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 /* Initialize state, waitqueue and spinlock */
2511 this->state = FL_READY;
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002512 init_waitqueue_head(&this->controller->wq);
2513 spin_lock_init(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 /* De-select the device */
2516 this->select_chip(mtd, -1);
2517
2518 /* Invalidate the pagebuffer reference */
2519 this->pagebuf = -1;
2520
2521 /* Fill in remaining MTD driver data */
2522 mtd->type = MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02002523 mtd->flags = MTD_CAP_NANDFLASH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 mtd->ecctype = MTD_ECC_SW;
2525 mtd->erase = nand_erase;
2526 mtd->point = NULL;
2527 mtd->unpoint = NULL;
2528 mtd->read = nand_read;
2529 mtd->write = nand_write;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 mtd->read_oob = nand_read_oob;
2531 mtd->write_oob = nand_write_oob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 mtd->sync = nand_sync;
2533 mtd->lock = NULL;
2534 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002535 mtd->suspend = nand_suspend;
2536 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 mtd->block_isbad = nand_block_isbad;
2538 mtd->block_markbad = nand_block_markbad;
2539
2540 /* and make the autooob the default one */
2541 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2542
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002543 /* Check, if we should skip the bad block table scan */
2544 if (this->options & NAND_SKIP_BBTSCAN)
2545 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
2547 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002548 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549}
2550
2551/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002552 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 * @mtd: MTD device structure
2554*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002555void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557 struct nand_chip *this = mtd->priv;
2558
2559#ifdef CONFIG_MTD_PARTITIONS
2560 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002561 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562#endif
2563 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002564 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
Jesper Juhlfa671642005-11-07 01:01:27 -08002566 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002567 kfree(this->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002568 /* Free buffers */
2569 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570}
2571
David Woodhousee0c7d762006-05-13 18:07:53 +01002572EXPORT_SYMBOL_GPL(nand_scan);
2573EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002574
2575static int __init nand_base_init(void)
2576{
2577 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2578 return 0;
2579}
2580
2581static void __exit nand_base_exit(void)
2582{
2583 led_trigger_unregister_simple(nand_led_trigger);
2584}
2585
2586module_init(nand_base_init);
2587module_exit(nand_base_exit);
2588
David Woodhousee0c7d762006-05-13 18:07:53 +01002589MODULE_LICENSE("GPL");
2590MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2591MODULE_DESCRIPTION("Generic NAND flash driver code");