blob: 4f387c8388d701f7f2290983432f3c0a07278979 [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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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 Gleixner58dd8f2b2006-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/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
202 * @mtd: MTD device structure
203 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000204 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 * endianess conversion
206 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200207static uint8_t nand_read_byte16(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200210 return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
213/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 * nand_read_word - [DEFAULT] read one word from the chip
215 * @mtd: MTD device structure
216 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000217 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 * endianess conversion
219 */
220static u16 nand_read_word(struct mtd_info *mtd)
221{
222 struct nand_chip *this = mtd->priv;
223 return readw(this->IO_ADDR_R);
224}
225
226/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 * nand_select_chip - [DEFAULT] control CE line
228 * @mtd: MTD device structure
229 * @chip: chipnumber to select, -1 for deselect
230 *
231 * Default select function for 1 chip devices.
232 */
233static void nand_select_chip(struct mtd_info *mtd, int chip)
234{
235 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100236 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 case -1:
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200238 this->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 break;
240 case 0:
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200241 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 break;
243
244 default:
245 BUG();
246 }
247}
248
249/**
250 * nand_write_buf - [DEFAULT] write buffer to chip
251 * @mtd: MTD device structure
252 * @buf: data buffer
253 * @len: number of bytes to write
254 *
255 * Default write function for 8bit buswith
256 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200257static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 int i;
260 struct nand_chip *this = mtd->priv;
261
David Woodhousee0c7d762006-05-13 18:07:53 +0100262 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 writeb(buf[i], this->IO_ADDR_W);
264}
265
266/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000267 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 * @mtd: MTD device structure
269 * @buf: buffer to store date
270 * @len: number of bytes to read
271 *
272 * Default read function for 8bit buswith
273 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200274static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
276 int i;
277 struct nand_chip *this = mtd->priv;
278
David Woodhousee0c7d762006-05-13 18:07:53 +0100279 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 buf[i] = readb(this->IO_ADDR_R);
281}
282
283/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000284 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 * @mtd: MTD device structure
286 * @buf: buffer containing the data to compare
287 * @len: number of bytes to compare
288 *
289 * Default verify function for 8bit buswith
290 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200291static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
293 int i;
294 struct nand_chip *this = mtd->priv;
295
David Woodhousee0c7d762006-05-13 18:07:53 +0100296 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (buf[i] != readb(this->IO_ADDR_R))
298 return -EFAULT;
299
300 return 0;
301}
302
303/**
304 * nand_write_buf16 - [DEFAULT] write buffer to chip
305 * @mtd: MTD device structure
306 * @buf: data buffer
307 * @len: number of bytes to write
308 *
309 * Default write function for 16bit buswith
310 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200311static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
313 int i;
314 struct nand_chip *this = mtd->priv;
315 u16 *p = (u16 *) buf;
316 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000317
David Woodhousee0c7d762006-05-13 18:07:53 +0100318 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
322
323/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000324 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 * @mtd: MTD device structure
326 * @buf: buffer to store date
327 * @len: number of bytes to read
328 *
329 * Default read function for 16bit buswith
330 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200331static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 int i;
334 struct nand_chip *this = mtd->priv;
335 u16 *p = (u16 *) buf;
336 len >>= 1;
337
David Woodhousee0c7d762006-05-13 18:07:53 +0100338 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 p[i] = readw(this->IO_ADDR_R);
340}
341
342/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000343 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 * @mtd: MTD device structure
345 * @buf: buffer containing the data to compare
346 * @len: number of bytes to compare
347 *
348 * Default verify function for 16bit buswith
349 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200350static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
352 int i;
353 struct nand_chip *this = mtd->priv;
354 u16 *p = (u16 *) buf;
355 len >>= 1;
356
David Woodhousee0c7d762006-05-13 18:07:53 +0100357 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (p[i] != readw(this->IO_ADDR_R))
359 return -EFAULT;
360
361 return 0;
362}
363
364/**
365 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
366 * @mtd: MTD device structure
367 * @ofs: offset from device start
368 * @getchip: 0, if the chip is already selected
369 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000370 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 */
372static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
373{
374 int page, chipnr, res = 0;
375 struct nand_chip *this = mtd->priv;
376 u16 bad;
377
378 if (getchip) {
379 page = (int)(ofs >> this->page_shift);
380 chipnr = (int)(ofs >> this->chip_shift);
381
382 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100383 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 /* Select the NAND device */
386 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000387 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100388 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 if (this->options & NAND_BUSWIDTH_16) {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200391 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
392 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 bad = cpu_to_le16(this->read_word(mtd));
394 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000395 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if ((bad & 0xFF) != 0xff)
397 res = 1;
398 } else {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200399 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
400 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (this->read_byte(mtd) != 0xff)
402 res = 1;
403 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (getchip) {
406 /* Deselect and wake up anyone waiting on the device */
407 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000408 }
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return res;
411}
412
413/**
414 * nand_default_block_markbad - [DEFAULT] mark a block bad
415 * @mtd: MTD device structure
416 * @ofs: offset from device start
417 *
418 * This is the default implementation, which can be overridden by
419 * a hardware specific driver.
420*/
421static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
422{
423 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200424 uint8_t buf[2] = { 0, 0 };
David Woodhousee0c7d762006-05-13 18:07:53 +0100425 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100429 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000430 if (this->bbt)
431 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 /* Do we have a flash based bad block table ? */
434 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100435 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /* We write two bytes, so we dont have to mess with 16 bit access */
438 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100439 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000442/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 * nand_check_wp - [GENERIC] check if the chip is write protected
444 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000445 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000447 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100449static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct nand_chip *this = mtd->priv;
452 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100453 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000454 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
457/**
458 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
459 * @mtd: MTD device structure
460 * @ofs: offset from device start
461 * @getchip: 0, if the chip is already selected
462 * @allowbbt: 1, if its allowed to access the bbt area
463 *
464 * Check, if the block is bad. Either by reading the bad block table or
465 * calling of the scan function.
466 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200467static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
468 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (!this->bbt)
473 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100476 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477}
478
Richard Purdie8fe833c2006-03-31 02:31:14 -0800479DEFINE_LED_TRIGGER(nand_led_trigger);
480
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000481/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000482 * Wait for the ready pin, after a command
483 * The timeout is catched later.
484 */
485static void nand_wait_ready(struct mtd_info *mtd)
486{
487 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100488 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000489
Richard Purdie8fe833c2006-03-31 02:31:14 -0800490 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000491 /* wait until command is processed or timeout occures */
492 do {
493 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800494 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700495 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000496 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800497 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000498}
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500/**
501 * nand_command - [DEFAULT] Send command to NAND device
502 * @mtd: MTD device structure
503 * @command: the command to be sent
504 * @column: the column address for this command, -1 if none
505 * @page_addr: the page address for this command, -1 if none
506 *
507 * Send command to NAND device. This function is used for small page
508 * devices (256/512 Bytes per page)
509 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200510static void nand_command(struct mtd_info *mtd, unsigned int command,
511 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 register struct nand_chip *this = mtd->priv;
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200514 int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 /*
517 * Write out the command to the device.
518 */
519 if (command == NAND_CMD_SEQIN) {
520 int readcmd;
521
Joern Engel28318772006-05-22 23:18:05 +0200522 if (column >= mtd->writesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 /* OOB area */
Joern Engel28318772006-05-22 23:18:05 +0200524 column -= mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 readcmd = NAND_CMD_READOOB;
526 } else if (column < 256) {
527 /* First 256 bytes --> READ0 */
528 readcmd = NAND_CMD_READ0;
529 } else {
530 column -= 256;
531 readcmd = NAND_CMD_READ1;
532 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200533 this->cmd_ctrl(mtd, readcmd, ctrl);
534 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200536 this->cmd_ctrl(mtd, command, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200538 /*
539 * Address cycle, when necessary
540 */
541 ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
542 /* Serially input address */
543 if (column != -1) {
544 /* Adjust columns for 16 bit buswidth */
545 if (this->options & NAND_BUSWIDTH_16)
546 column >>= 1;
547 this->cmd_ctrl(mtd, column, ctrl);
548 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200550 if (page_addr != -1) {
551 this->cmd_ctrl(mtd, page_addr, ctrl);
552 ctrl &= ~NAND_CTRL_CHANGE;
553 this->cmd_ctrl(mtd, page_addr >> 8, ctrl);
554 /* One more address cycle for devices > 32MiB */
555 if (this->chipsize > (32 << 20))
556 this->cmd_ctrl(mtd, page_addr >> 16, ctrl);
557 }
558 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000559
560 /*
561 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100563 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 case NAND_CMD_PAGEPROG:
567 case NAND_CMD_ERASE1:
568 case NAND_CMD_ERASE2:
569 case NAND_CMD_SEQIN:
570 case NAND_CMD_STATUS:
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200571 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return;
573
574 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000575 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 break;
577 udelay(this->chip_delay);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200578 this->cmd_ctrl(mtd, NAND_CMD_STATUS,
579 NAND_CTRL_CLE | NAND_CTRL_CHANGE);
580 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100581 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return;
583
David Woodhousee0c7d762006-05-13 18:07:53 +0100584 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000586 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 * If we don't have access to the busy pin, we apply the given
588 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100589 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100591 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* Apply this short delay always to ensure that we do wait tWB in
596 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100597 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000598
599 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
602/**
603 * nand_command_lp - [DEFAULT] Send command to NAND large page device
604 * @mtd: MTD device structure
605 * @command: the command to be sent
606 * @column: the column address for this command, -1 if none
607 * @page_addr: the page address for this command, -1 if none
608 *
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200609 * Send command to NAND device. This is the version for the new large page
610 * devices We dont have the separate regions as we have in the small page
611 * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 *
613 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200614static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
615 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 register struct nand_chip *this = mtd->priv;
618
619 /* Emulate NAND_CMD_READOOB */
620 if (command == NAND_CMD_READOOB) {
Joern Engel28318772006-05-22 23:18:05 +0200621 column += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 command = NAND_CMD_READ0;
623 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000624
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200625 /* Command latch cycle */
626 this->cmd_ctrl(mtd, command & 0xff,
627 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 if (column != -1 || page_addr != -1) {
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200630 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 /* Serially input address */
633 if (column != -1) {
634 /* Adjust columns for 16 bit buswidth */
635 if (this->options & NAND_BUSWIDTH_16)
636 column >>= 1;
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200637 this->cmd_ctrl(mtd, column, ctrl);
638 ctrl &= ~NAND_CTRL_CHANGE;
639 this->cmd_ctrl(mtd, column >> 8, ctrl);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (page_addr != -1) {
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200642 this->cmd_ctrl(mtd, page_addr, ctrl);
643 this->cmd_ctrl(mtd, page_addr >> 8,
644 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /* One more address cycle for devices > 128MiB */
646 if (this->chipsize > (128 << 20))
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200647 this->cmd_ctrl(mtd, page_addr >> 16,
648 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200651 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000652
653 /*
654 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000655 * status, sequential in, and deplete1 need no delay
656 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 case NAND_CMD_CACHEDPROG:
660 case NAND_CMD_PAGEPROG:
661 case NAND_CMD_ERASE1:
662 case NAND_CMD_ERASE2:
663 case NAND_CMD_SEQIN:
664 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000665 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return;
667
David Woodhousee0c7d762006-05-13 18:07:53 +0100668 /*
669 * read error status commands require only a short delay
670 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000671 case NAND_CMD_STATUS_ERROR:
672 case NAND_CMD_STATUS_ERROR0:
673 case NAND_CMD_STATUS_ERROR1:
674 case NAND_CMD_STATUS_ERROR2:
675 case NAND_CMD_STATUS_ERROR3:
676 udelay(this->chip_delay);
677 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000680 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 break;
682 udelay(this->chip_delay);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200683 this->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE);
684 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100685 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return;
687
688 case NAND_CMD_READ0:
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200689 this->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE);
690 this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000691
David Woodhousee0c7d762006-05-13 18:07:53 +0100692 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000694 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 * If we don't have access to the busy pin, we apply the given
696 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100697 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100699 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 /* Apply this short delay always to ensure that we do wait tWB in
705 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100706 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000707
708 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711/**
712 * nand_get_device - [GENERIC] Get chip for selected access
713 * @this: the nand chip descriptor
714 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000715 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 *
717 * Get the device and lock it for exclusive access
718 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200719static int
720nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200722 spinlock_t *lock = &this->controller->lock;
723 wait_queue_head_t *wq = &this->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100724 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100725 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100726 spin_lock(lock);
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200729 /* Hardware controller shared among independend devices */
730 if (!this->controller->active)
731 this->controller->active = this;
732
733 if (this->controller->active == this && this->state == FL_READY) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100734 this->state = new_state;
735 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100736 return 0;
737 }
738 if (new_state == FL_PM_SUSPENDED) {
739 spin_unlock(lock);
740 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100741 }
742 set_current_state(TASK_UNINTERRUPTIBLE);
743 add_wait_queue(wq, &wait);
744 spin_unlock(lock);
745 schedule();
746 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 goto retry;
748}
749
750/**
751 * nand_wait - [DEFAULT] wait until the command is done
752 * @mtd: MTD device structure
753 * @this: NAND chip structure
754 * @state: state to select the max. timeout value
755 *
756 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000757 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 * general NAND and SmartMedia specs
759 *
760*/
761static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
762{
763
David Woodhousee0c7d762006-05-13 18:07:53 +0100764 unsigned long timeo = jiffies;
765 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100768 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100770 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Richard Purdie8fe833c2006-03-31 02:31:14 -0800772 led_trigger_event(nand_led_trigger, LED_FULL);
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 /* Apply this short delay always to ensure that we do wait tWB in
775 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100776 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100779 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000780 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100781 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000783 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 /* Check, if we were interrupted */
785 if (this->state != state)
786 return 0;
787
788 if (this->dev_ready) {
789 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000790 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 } else {
792 if (this->read_byte(mtd) & NAND_STATUS_READY)
793 break;
794 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000795 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800797 led_trigger_event(nand_led_trigger, LED_OFF);
798
David Woodhousee0c7d762006-05-13 18:07:53 +0100799 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return status;
801}
802
803/**
804 * nand_write_page - [GENERIC] write one page
805 * @mtd: MTD device structure
806 * @this: NAND chip structure
807 * @page: startpage inside the chip, must be called with (page & this->pagemask)
808 * @oob_buf: out of band data buffer
809 * @oobsel: out of band selecttion structre
810 * @cached: 1 = enable cached programming if supported by chip
811 *
812 * Nand_page_program function is used for write and writev !
813 * This function will always program a full page of data
814 * If you call it with a non page aligned buffer, you're lost :)
815 *
816 * Cached programming is not supported yet.
817 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100818static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200819 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
David Woodhousee0c7d762006-05-13 18:07:53 +0100821 int i, status;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200822 uint8_t ecc_code[32];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200823 int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
David Woodhousee0c7d762006-05-13 18:07:53 +0100824 int *oob_config = oobsel->eccpos;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200825 int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100826 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 /* FIXME: Enable cached programming */
829 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100832 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 /* Write out complete page of data, take care of eccmode */
835 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100836 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100838 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Joern Engel28318772006-05-22 23:18:05 +0200839 this->write_buf(mtd, this->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000841
David Woodhousee0c7d762006-05-13 18:07:53 +0100842 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 case NAND_ECC_SOFT:
844 for (; eccsteps; eccsteps--) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200845 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 for (i = 0; i < 3; i++, eccidx++)
847 oob_buf[oob_config[eccidx]] = ecc_code[i];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200848 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 }
Joern Engel28318772006-05-22 23:18:05 +0200850 this->write_buf(mtd, this->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 break;
852 default:
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200853 eccbytes = this->ecc.bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 for (; eccsteps; eccsteps--) {
855 /* enable hardware ecc logic for write */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200856 this->ecc.hwctl(mtd, NAND_ECC_WRITE);
857 this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
858 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 for (i = 0; i < eccbytes; i++, eccidx++)
860 oob_buf[oob_config[eccidx]] = ecc_code[i];
861 /* If the hardware ecc provides syndromes then
862 * the ecc code must be written immidiately after
863 * the data bytes (words) */
864 if (this->options & NAND_HWECC_SYNDROME)
865 this->write_buf(mtd, ecc_code, eccbytes);
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200866 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 break;
869 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 /* Write out OOB data */
872 if (this->options & NAND_HWECC_SYNDROME)
873 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000874 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 this->write_buf(mtd, oob_buf, mtd->oobsize);
876
877 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100878 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 if (!cached) {
881 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100882 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000883
884 /* See if operation failed and additional status checks are available */
885 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
886 status = this->errstat(mtd, this, FL_WRITING, status, page);
887 }
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000890 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100891 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return -EIO;
893 }
894 } else {
895 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100896 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
898 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000899 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900}
901
902#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
903/**
904 * nand_verify_pages - [GENERIC] verify the chip contents after a write
905 * @mtd: MTD device structure
906 * @this: NAND chip structure
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200907 * @page: startpage inside the chip, must be called with (page & this->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 * @numpages: number of pages to verify
909 * @oob_buf: out of band data buffer
910 * @oobsel: out of band selecttion structre
911 * @chipnr: number of the current chip
912 * @oobmode: 1 = full buffer verify, 0 = ecc only
913 *
914 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000915 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000917 * byte by byte basis. It is possible that the page was not completely erased
918 * or the page is becoming unusable due to wear. The read with ECC would catch
919 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 * it early in the page write stage. Better to write no data than invalid data.
921 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100922static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200923 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
David Woodhousee0c7d762006-05-13 18:07:53 +0100925 int i, j, datidx = 0, oobofs = 0, res = -EIO;
926 int eccsteps = this->eccsteps;
927 int hweccbytes;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200928 uint8_t oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
931
932 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100933 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
David Woodhousee0c7d762006-05-13 18:07:53 +0100935 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 for (j = 0; j < eccsteps; j++) {
937 /* Loop through and verify the data */
938 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100939 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 goto out;
941 }
942 datidx += mtd->eccsize;
943 /* Have we a hw generator layout ? */
944 if (!hweccbytes)
945 continue;
946 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100947 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 goto out;
949 }
950 oobofs += hweccbytes;
951 }
952
953 /* check, if we must compare all data or if we just have to
954 * compare the ecc bytes
955 */
956 if (oobmode) {
957 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100958 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto out;
960 }
961 } else {
962 /* Read always, else autoincrement fails */
963 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
964
965 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
966 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 for (i = 0; i < ecccnt; i++) {
969 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +0100970 if (oobdata[idx] != oob_buf[oobofs + idx]) {
971 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
972 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 goto out;
974 }
975 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978 oobofs += mtd->oobsize - hweccbytes * eccsteps;
979 page++;
980 numpages--;
981
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000982 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 * Do this before the AUTOINCR check, so no problems
984 * arise if a chip which does auto increment
985 * is marked as NOAUTOINCR by the board driver.
986 * Do this also before returning, so the chip is
987 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +0100988 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000989 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +0100990 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 else
Thomas Gleixner3b887752005-02-22 21:56:49 +0000992 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 /* All done, return happy */
995 if (!numpages)
996 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000997
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000998 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001000 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001002 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 * Terminate the read command. We come here in case of an error
1004 * So we must issue a reset command.
1005 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001006 out:
1007 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return res;
1009}
1010#endif
1011
1012/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001013 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 * @mtd: MTD device structure
1015 * @from: offset to read from
1016 * @len: number of bytes to read
1017 * @retlen: pointer to variable to store the number of read bytes
1018 * @buf: the databuffer to put data
1019 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001020 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1021 * and flags = 0xff
1022 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001023static 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 -07001024{
David Woodhousee0c7d762006-05-13 18:07:53 +01001025 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001026}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001029 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1030 * @mtd: MTD device structure
1031 * @from: offset to read from
1032 * @len: number of bytes to read
1033 * @retlen: pointer to variable to store the number of read bytes
1034 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001035 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001036 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001037 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1038 * and how many corrected error bits are acceptable:
1039 * bits 0..7 - number of tolerable errors
1040 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1041 *
1042 * NAND read with ECC
1043 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001044int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001045 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001046{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1049 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1050 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001051 uint8_t *data_poi, *oob_data = oob_buf;
1052 uint8_t ecc_calc[32];
1053 uint8_t ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001054 int eccmode, eccsteps;
1055 int *oob_config, datidx;
1056 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1057 int eccbytes;
1058 int compareecc = 1;
1059 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
David Woodhousee0c7d762006-05-13 18:07:53 +01001061 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 -07001062
1063 /* Do not allow reads past end of device */
1064 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001065 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 *retlen = 0;
1067 return -EINVAL;
1068 }
1069
1070 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001071 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001072 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 /* Autoplace of oob data ? Use the default placement scheme */
1075 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1076 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001077
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001078 eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 oob_config = oobsel->eccpos;
1080
1081 /* Select the NAND device */
1082 chipnr = (int)(from >> this->chip_shift);
1083 this->select_chip(mtd, chipnr);
1084
1085 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001086 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 page = realpage & this->pagemask;
1088
1089 /* Get raw starting column */
Joern Engel28318772006-05-22 23:18:05 +02001090 col = from & (mtd->writesize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Joern Engel28318772006-05-22 23:18:05 +02001092 end = mtd->writesize;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001093 ecc = this->ecc.size;
1094 eccbytes = this->ecc.bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1097 compareecc = 0;
1098
1099 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001100 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 oobreadlen -= oobsel->eccbytes;
1102
1103 /* Loop until all data read */
1104 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001107 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 * If the read is not page aligned, we have to read into data buffer
1109 * due to ecc, else we read into return buffer direct
1110 */
1111 if (aligned)
1112 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001113 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001115
1116 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 *
1118 * FIXME: Make it work when we must provide oob data too,
1119 * check the usage of data_buf oob field
1120 */
1121 if (realpage == this->pagebuf && !oob_buf) {
1122 /* aligned read ? */
1123 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001124 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 goto readdata;
1126 }
1127
1128 /* Check, if we must send the read command */
1129 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001130 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001135 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1136 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 oob_data = &this->data_buf[end];
1138
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001139 eccsteps = this->ecc.steps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001142 case NAND_ECC_NONE:{
1143 /* No ECC, Read in a page */
1144 static unsigned long lastwhinge = 0;
1145 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1146 printk(KERN_WARNING
1147 "Reading data from NAND FLASH without ECC is not recommended\n");
1148 lastwhinge = jiffies;
1149 }
1150 this->read_buf(mtd, data_poi, end);
1151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1155 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001156 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001157 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001158 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001161 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001162 this->ecc.hwctl(mtd, NAND_ECC_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 this->read_buf(mtd, &data_poi[datidx], ecc);
1164
1165 /* HW ecc with syndrome calculation must read the
1166 * syndrome from flash immidiately after the data */
1167 if (!compareecc) {
1168 /* Some hw ecc generators need to know when the
1169 * syndrome is read from flash */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001170 this->ecc.hwctl(mtd, NAND_ECC_READSYN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 this->read_buf(mtd, &oob_data[i], eccbytes);
1172 /* We calc error correction directly, it checks the hw
1173 * generator for an error, reads back the syndrome and
1174 * does the error correction on the fly */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001175 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
David A. Marlin068e3c02005-01-24 03:07:46 +00001176 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001177 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1178 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 ecc_failed++;
1180 }
1181 } else {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001182 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001185 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 }
1187
1188 /* read oobdata */
1189 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1190
1191 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1192 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001193 goto readoob;
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 /* Pick the ECC bytes out of the oob data */
1196 for (j = 0; j < oobsel->eccbytes; j++)
1197 ecc_code[j] = oob_data[oob_config[j]];
1198
David Woodhousee0c7d762006-05-13 18:07:53 +01001199 /* correct data, if necessary */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001200 for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
1201 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 /* Get next chunk of ecc bytes */
1204 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001205
1206 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 * This is the legacy mode. Used by YAFFS1
1208 * Should go away some day
1209 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001210 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 int *p = (int *)(&oob_data[mtd->oobsize]);
1212 p[i] = ecc_status;
1213 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001214
1215 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001216 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 ecc_failed++;
1218 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
David Woodhousee0c7d762006-05-13 18:07:53 +01001221 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 /* check, if we have a fs supplied oob-buffer */
1223 if (oob_buf) {
1224 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001225 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001227 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001229 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 int from = oobsel->oobfree[i][0];
1231 int num = oobsel->oobfree[i][1];
1232 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001233 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 break;
1236 case MTD_NANDECC_PLACE:
1237 /* YAFFS1 legacy mode */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001238 oob_data += this->ecc.steps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 default:
1240 oob_data += mtd->oobsize;
1241 }
1242 }
1243 readdata:
1244 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001245 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 for (j = col; j < end && read < len; j++)
1247 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001248 this->pagebuf = realpage;
1249 } else
Joern Engel28318772006-05-22 23:18:05 +02001250 read += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001252 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 * Do this before the AUTOINCR check, so no problems
1254 * arise if a chip which does auto increment
1255 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001256 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001257 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001258 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001260 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001263 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 /* For subsequent reads align to page boundary. */
1266 col = 0;
1267 /* Increment page address */
1268 realpage++;
1269
1270 page = realpage & this->pagemask;
1271 /* Check, if we cross a chip boundary */
1272 if (!page) {
1273 chipnr++;
1274 this->select_chip(mtd, -1);
1275 this->select_chip(mtd, chipnr);
1276 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001277 /* Check, if the chip supports auto page increment
1278 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001279 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001281 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
1283
1284 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001285 if (flags & NAND_GET_DEVICE)
1286 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
1288 /*
1289 * Return success, if no ECC failures, else -EBADMSG
1290 * fs driver will take care of that, because
1291 * retlen == desired len and result == -EBADMSG
1292 */
1293 *retlen = read;
1294 return ecc_failed ? -EBADMSG : 0;
1295}
1296
1297/**
1298 * nand_read_oob - [MTD Interface] NAND read out-of-band
1299 * @mtd: MTD device structure
1300 * @from: offset to read from
1301 * @len: number of bytes to read
1302 * @retlen: pointer to variable to store the number of read bytes
1303 * @buf: the databuffer to put data
1304 *
1305 * NAND read out-of-band data from the spare area
1306 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001307static 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 -07001308{
1309 int i, col, page, chipnr;
1310 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001311 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
David Woodhousee0c7d762006-05-13 18:07:53 +01001313 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 -07001314
1315 /* Shift to get page */
1316 page = (int)(from >> this->page_shift);
1317 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001318
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 /* Mask to get column */
1320 col = from & (mtd->oobsize - 1);
1321
1322 /* Initialize return length value */
1323 *retlen = 0;
1324
1325 /* Do not allow reads past end of device */
1326 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001327 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 *retlen = 0;
1329 return -EINVAL;
1330 }
1331
1332 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001333 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
1335 /* Select the NAND device */
1336 this->select_chip(mtd, chipnr);
1337
1338 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001339 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001340 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 * Read the data, if we read more than one page
1342 * oob data, let the device transfer the data !
1343 */
1344 i = 0;
1345 while (i < len) {
1346 int thislen = mtd->oobsize - col;
1347 thislen = min_t(int, thislen, len);
1348 this->read_buf(mtd, &buf[i], thislen);
1349 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 /* Read more ? */
1352 if (i < len) {
1353 page++;
1354 col = 0;
1355
1356 /* Check, if we cross a chip boundary */
1357 if (!(page & this->pagemask)) {
1358 chipnr++;
1359 this->select_chip(mtd, -1);
1360 this->select_chip(mtd, chipnr);
1361 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001362
1363 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001364 * Do this before the AUTOINCR check, so no problems
1365 * arise if a chip which does auto increment
1366 * is marked as NOAUTOINCR by the board driver.
1367 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001368 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001369 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001370 else
1371 nand_wait_ready(mtd);
1372
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001373 /* Check, if the chip supports auto page increment
1374 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001375 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1377 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001378 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 }
1380 }
1381 }
1382
1383 /* Deselect and wake up anyone waiting on the device */
1384 nand_release_device(mtd);
1385
1386 /* Return happy */
1387 *retlen = len;
1388 return 0;
1389}
1390
1391/**
1392 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1393 * @mtd: MTD device structure
1394 * @buf: temporary buffer
1395 * @from: offset to read from
1396 * @len: number of bytes to read
1397 * @ooblen: number of oob data bytes to read
1398 *
1399 * Read raw data including oob into buffer
1400 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001401int 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 -07001402{
1403 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001404 int page = (int)(from >> this->page_shift);
1405 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 int sndcmd = 1;
1407 int cnt = 0;
Joern Engel28318772006-05-22 23:18:05 +02001408 int pagesize = mtd->writesize + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001409 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 /* Do not allow reads past end of device */
1412 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001413 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return -EINVAL;
1415 }
1416
1417 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001418 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
David Woodhousee0c7d762006-05-13 18:07:53 +01001420 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 /* Add requested oob length */
1423 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 while (len) {
1426 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001427 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001428 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
David Woodhousee0c7d762006-05-13 18:07:53 +01001430 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 len -= pagesize;
1433 cnt += pagesize;
1434 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001435
1436 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001437 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001439 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001440
1441 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1443 sndcmd = 1;
1444 }
1445
1446 /* Deselect and wake up anyone waiting on the device */
1447 nand_release_device(mtd);
1448 return 0;
1449}
1450
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001451/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001452 * nand_write_raw - [GENERIC] Write raw data including oob
1453 * @mtd: MTD device structure
1454 * @buf: source buffer
1455 * @to: offset to write to
1456 * @len: number of bytes to write
1457 * @buf: source buffer
1458 * @oob: oob buffer
1459 *
1460 * Write raw data including oob
1461 */
1462int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1463 uint8_t *buf, uint8_t *oob)
1464{
1465 struct nand_chip *this = mtd->priv;
1466 int page = (int)(to >> this->page_shift);
1467 int chip = (int)(to >> this->chip_shift);
1468 int ret;
1469
1470 *retlen = 0;
1471
1472 /* Do not allow writes past end of device */
1473 if ((to + len) > mtd->size) {
1474 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
1475 "beyond end of device\n");
1476 return -EINVAL;
1477 }
1478
1479 /* Grab the lock and see if the device is available */
1480 nand_get_device(this, mtd, FL_WRITING);
1481
1482 this->select_chip(mtd, chip);
1483 this->data_poi = buf;
1484
1485 while (len != *retlen) {
1486 ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0);
1487 if (ret)
1488 return ret;
1489 page++;
1490 *retlen += mtd->writesize;
1491 this->data_poi += mtd->writesize;
1492 oob += mtd->oobsize;
1493 }
1494
1495 /* Deselect and wake up anyone waiting on the device */
1496 nand_release_device(mtd);
1497 return 0;
1498}
Thomas Gleixner38217202006-05-23 22:33:52 +02001499EXPORT_SYMBOL_GPL(nand_write_raw);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001500
1501/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001502 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 * @mtd: MTD device structure
1504 * @fsbuf: buffer given by fs driver
1505 * @oobsel: out of band selection structre
1506 * @autoplace: 1 = place given buffer into the oob bytes
1507 * @numpages: number of pages to prepare
1508 *
1509 * Return:
1510 * 1. Filesystem buffer available and autoplacement is off,
1511 * return filesystem buffer
1512 * 2. No filesystem buffer or autoplace is off, return internal
1513 * buffer
1514 * 3. Filesystem buffer is given and autoplace selected
1515 * put data from fs buffer into internal buffer and
1516 * retrun internal buffer
1517 *
1518 * Note: The internal buffer is filled with 0xff. This must
1519 * be done only once, when no autoplacement happens
1520 * Autoplacement sets the buffer dirty flag, which
1521 * forces the 0xff fill before using the buffer again.
1522 *
1523*/
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001524static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
David Woodhousee0c7d762006-05-13 18:07:53 +01001525 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526{
1527 struct nand_chip *this = mtd->priv;
1528 int i, len, ofs;
1529
1530 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001531 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 return fsbuf;
1533
1534 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001535 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001536 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001538 }
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 /* If we have no autoplacement or no fs buffer use the internal one */
1541 if (!autoplace || !fsbuf)
1542 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 /* Walk through the pages and place the data */
1545 this->oobdirty = 1;
1546 ofs = 0;
1547 while (numpages--) {
1548 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1549 int to = ofs + oobsel->oobfree[i][0];
1550 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001551 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 len += num;
1553 fsbuf += num;
1554 }
1555 ofs += mtd->oobavail;
1556 }
1557 return this->oob_buf;
1558}
1559
Joern Engel28318772006-05-22 23:18:05 +02001560#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001563 * nand_write - [MTD Interface] NAND write with ECC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 * @mtd: MTD device structure
1565 * @to: offset to write to
1566 * @len: number of bytes to write
1567 * @retlen: pointer to variable to store the number of written bytes
1568 * @buf: the data to write
1569 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 * NAND write with ECC
1571 */
Thomas Gleixner9223a452006-05-23 17:21:03 +02001572static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1573 size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
1575 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1576 int autoplace = 0, numpages, totalpages;
1577 struct nand_chip *this = mtd->priv;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001578 uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
David Woodhousee0c7d762006-05-13 18:07:53 +01001579 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Thomas Gleixner9223a452006-05-23 17:21:03 +02001580 struct nand_oobinfo *oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Thomas Gleixner9223a452006-05-23 17:21:03 +02001582 DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 /* Initialize retlen, in case of early exit */
1585 *retlen = 0;
1586
1587 /* Do not allow write past end of device */
1588 if ((to + len) > mtd->size) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001589 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return -EINVAL;
1591 }
1592
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001593 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001594 if (NOTALIGNED(to) || NOTALIGNED(len)) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001595 printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 return -EINVAL;
1597 }
1598
1599 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001600 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 /* Calculate chipnr */
1603 chipnr = (int)(to >> this->chip_shift);
1604 /* Select the NAND device */
1605 this->select_chip(mtd, chipnr);
1606
1607 /* Check, if it is write protected */
1608 if (nand_check_wp(mtd))
1609 goto out;
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 /* Autoplace of oob data ? Use the default placement scheme */
1612 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1613 oobsel = this->autooob;
1614 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001615 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001616 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1617 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 /* Setup variables and oob buffer */
1620 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001621 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001623 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001625
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 /* Set it relative to chip */
1627 page &= this->pagemask;
1628 startpage = page;
1629 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001630 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1631 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001632 bufstart = (uint8_t *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 /* Loop until all data is written */
1635 while (written < len) {
1636
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001637 this->data_poi = (uint8_t *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 /* Write one page. If this is the last page to write
1639 * or the last page in this block, then use the
1640 * real pageprogram command, else select cached programming
1641 * if supported by the chip.
1642 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001643 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001645 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 /* Next oob page */
1649 oob += mtd->oobsize;
1650 /* Update written bytes count */
Joern Engel28318772006-05-22 23:18:05 +02001651 written += mtd->writesize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001652 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* Increment page address */
1656 page++;
1657
1658 /* Have we hit a block boundary ? Then we have to verify and
1659 * if verify is ok, we have to setup the oob buffer for
1660 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001661 */
1662 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 int ofs;
1664 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001665 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1666 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001668 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 *retlen = written;
1672
1673 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1674 if (eccbuf)
1675 eccbuf += (page - startpage) * ofs;
1676 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001677 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 page &= this->pagemask;
1679 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001680 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001681 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 /* Check, if we cross a chip boundary */
1683 if (!page) {
1684 chipnr++;
1685 this->select_chip(mtd, -1);
1686 this->select_chip(mtd, chipnr);
1687 }
1688 }
1689 }
1690 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001691 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001693 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (!ret)
1695 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001696 else
Thomas Gleixner9223a452006-05-23 17:21:03 +02001697 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
David Woodhousee0c7d762006-05-13 18:07:53 +01001699 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* Deselect and wake up anyone waiting on the device */
1701 nand_release_device(mtd);
1702
1703 return ret;
1704}
1705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706/**
1707 * nand_write_oob - [MTD Interface] NAND write out-of-band
1708 * @mtd: MTD device structure
1709 * @to: offset to write to
1710 * @len: number of bytes to write
1711 * @retlen: pointer to variable to store the number of written bytes
1712 * @buf: the data to write
1713 *
1714 * NAND write out-of-band
1715 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001716static 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 -07001717{
1718 int column, page, status, ret = -EIO, chipnr;
1719 struct nand_chip *this = mtd->priv;
1720
David Woodhousee0c7d762006-05-13 18:07:53 +01001721 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 -07001722
1723 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001724 page = (int)(to >> this->page_shift);
1725 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 /* Mask to get column */
1728 column = to & (mtd->oobsize - 1);
1729
1730 /* Initialize return length value */
1731 *retlen = 0;
1732
1733 /* Do not allow write past end of page */
1734 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001735 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 return -EINVAL;
1737 }
1738
1739 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001740 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
1742 /* Select the NAND device */
1743 this->select_chip(mtd, chipnr);
1744
1745 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1746 in one of my DiskOnChip 2000 test units) will clear the whole
1747 data page too if we don't do this. I have no clue why, but
1748 I seem to have 'fixed' it in the doc2000 driver in
1749 August 1999. dwmw2. */
1750 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1751
1752 /* Check, if it is write protected */
1753 if (nand_check_wp(mtd))
1754 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 /* Invalidate the page cache, if we write to the cached page */
1757 if (page == this->pagebuf)
1758 this->pagebuf = -1;
1759
1760 if (NAND_MUST_PAD(this)) {
1761 /* Write out desired data */
Joern Engel28318772006-05-22 23:18:05 +02001762 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 /* prepad 0xff for partial programming */
1764 this->write_buf(mtd, ffchars, column);
1765 /* write data */
1766 this->write_buf(mtd, buf, len);
1767 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001768 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 } else {
1770 /* Write out desired data */
Joern Engel28318772006-05-22 23:18:05 +02001771 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 /* write data */
1773 this->write_buf(mtd, buf, len);
1774 }
1775 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001776 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
David Woodhousee0c7d762006-05-13 18:07:53 +01001778 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
1780 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001781 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001782 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 ret = -EIO;
1784 goto out;
1785 }
1786 /* Return happy */
1787 *retlen = len;
1788
1789#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1790 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001791 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001794 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ret = -EIO;
1796 goto out;
1797 }
1798#endif
1799 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001800 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 /* Deselect and wake up anyone waiting on the device */
1802 nand_release_device(mtd);
1803
1804 return ret;
1805}
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 * single_erease_cmd - [GENERIC] NAND standard block erase command function
1809 * @mtd: MTD device structure
1810 * @page: the page address of the block which will be erased
1811 *
1812 * Standard erase command for NAND chips
1813 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001814static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815{
1816 struct nand_chip *this = mtd->priv;
1817 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01001818 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1819 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820}
1821
1822/**
1823 * multi_erease_cmd - [GENERIC] AND specific block erase command function
1824 * @mtd: MTD device structure
1825 * @page: the page address of the block which will be erased
1826 *
1827 * AND multi block erase command function
1828 * Erase 4 consecutive blocks
1829 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001830static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831{
1832 struct nand_chip *this = mtd->priv;
1833 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01001834 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1835 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1836 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1837 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1838 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839}
1840
1841/**
1842 * nand_erase - [MTD Interface] erase block(s)
1843 * @mtd: MTD device structure
1844 * @instr: erase instruction
1845 *
1846 * Erase one ore more blocks
1847 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001848static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
David Woodhousee0c7d762006-05-13 18:07:53 +01001850 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001852
David A. Marlin30f464b2005-01-17 18:35:25 +00001853#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854/**
1855 * nand_erase_intern - [NAND Interface] erase block(s)
1856 * @mtd: MTD device structure
1857 * @instr: erase instruction
1858 * @allowbbt: allow erasing the bbt area
1859 *
1860 * Erase one ore more blocks
1861 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001862int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
1864 int page, len, status, pages_per_block, ret, chipnr;
1865 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00001866 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
1867 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
1868 /* It is used to see if the current page is in the same */
1869 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
David Woodhousee0c7d762006-05-13 18:07:53 +01001871 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 -07001872
1873 /* Start address must align on block boundary */
1874 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001875 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 return -EINVAL;
1877 }
1878
1879 /* Length must align on block boundary */
1880 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001881 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 return -EINVAL;
1883 }
1884
1885 /* Do not allow erase past end of device */
1886 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001887 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return -EINVAL;
1889 }
1890
1891 instr->fail_addr = 0xffffffff;
1892
1893 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001894 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001897 page = (int)(instr->addr >> this->page_shift);
1898 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* Calculate pages in each block */
1901 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
1902
1903 /* Select the NAND device */
1904 this->select_chip(mtd, chipnr);
1905
1906 /* Check the WP bit */
1907 /* Check, if it is write protected */
1908 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001909 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 instr->state = MTD_ERASE_FAILED;
1911 goto erase_exit;
1912 }
1913
David A. Marlin30f464b2005-01-17 18:35:25 +00001914 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
1915 if (this->options & BBT_AUTO_REFRESH) {
1916 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
1917 } else {
1918 bbt_masked_page = 0xffffffff; /* should not match anything */
1919 }
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 /* Loop through the pages */
1922 len = instr->len;
1923
1924 instr->state = MTD_ERASING;
1925
1926 while (len) {
1927 /* Check if we have a bad block, we do not erase bad blocks ! */
1928 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001929 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 instr->state = MTD_ERASE_FAILED;
1931 goto erase_exit;
1932 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001933
1934 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 the current cached page */
1936 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
1937 this->pagebuf = -1;
1938
David Woodhousee0c7d762006-05-13 18:07:53 +01001939 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001940
David Woodhousee0c7d762006-05-13 18:07:53 +01001941 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
David A. Marlin068e3c02005-01-24 03:07:46 +00001943 /* See if operation failed and additional status checks are available */
1944 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
1945 status = this->errstat(mtd, this, FL_ERASING, status, page);
1946 }
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001949 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001950 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 instr->state = MTD_ERASE_FAILED;
1952 instr->fail_addr = (page << this->page_shift);
1953 goto erase_exit;
1954 }
David A. Marlin30f464b2005-01-17 18:35:25 +00001955
1956 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
1957 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001958 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00001959 (page != this->bbt_td->pages[chipnr])) {
1960 rewrite_bbt[chipnr] = (page << this->page_shift);
1961 }
1962 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 /* Increment page address and decrement length */
1965 len -= (1 << this->phys_erase_shift);
1966 page += pages_per_block;
1967
1968 /* Check, if we cross a chip boundary */
1969 if (len && !(page & this->pagemask)) {
1970 chipnr++;
1971 this->select_chip(mtd, -1);
1972 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00001973
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001974 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00001975 * set the BBT page mask to see if this BBT should be rewritten */
1976 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
1977 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
1978 }
1979
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981 }
1982 instr->state = MTD_ERASE_DONE;
1983
David Woodhousee0c7d762006-05-13 18:07:53 +01001984 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1987 /* Do call back function */
1988 if (!ret)
1989 mtd_erase_callback(instr);
1990
1991 /* Deselect and wake up anyone waiting on the device */
1992 nand_release_device(mtd);
1993
David A. Marlin30f464b2005-01-17 18:35:25 +00001994 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
1995 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
1996 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
1997 if (rewrite_bbt[chipnr]) {
1998 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01001999 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2000 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2001 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002002 }
2003 }
2004 }
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 /* Return more or less happy */
2007 return ret;
2008}
2009
2010/**
2011 * nand_sync - [MTD Interface] sync
2012 * @mtd: MTD device structure
2013 *
2014 * Sync is actually a wait for chip ready function
2015 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002016static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017{
2018 struct nand_chip *this = mtd->priv;
2019
David Woodhousee0c7d762006-05-13 18:07:53 +01002020 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
2022 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002023 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002025 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026}
2027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028/**
2029 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2030 * @mtd: MTD device structure
2031 * @ofs: offset relative to mtd start
2032 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002033static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{
2035 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002036 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002038
David Woodhousee0c7d762006-05-13 18:07:53 +01002039 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040}
2041
2042/**
2043 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2044 * @mtd: MTD device structure
2045 * @ofs: offset relative to mtd start
2046 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002047static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
2049 struct nand_chip *this = mtd->priv;
2050 int ret;
2051
David Woodhousee0c7d762006-05-13 18:07:53 +01002052 if ((ret = nand_block_isbad(mtd, ofs))) {
2053 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 if (ret > 0)
2055 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002056 return ret;
2057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
2059 return this->block_markbad(mtd, ofs);
2060}
2061
2062/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002063 * nand_suspend - [MTD Interface] Suspend the NAND flash
2064 * @mtd: MTD device structure
2065 */
2066static int nand_suspend(struct mtd_info *mtd)
2067{
2068 struct nand_chip *this = mtd->priv;
2069
David Woodhousee0c7d762006-05-13 18:07:53 +01002070 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002071}
2072
2073/**
2074 * nand_resume - [MTD Interface] Resume the NAND flash
2075 * @mtd: MTD device structure
2076 */
2077static void nand_resume(struct mtd_info *mtd)
2078{
2079 struct nand_chip *this = mtd->priv;
2080
2081 if (this->state == FL_PM_SUSPENDED)
2082 nand_release_device(mtd);
2083 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002084 printk(KERN_ERR "nand_resume() called for a chip which is not "
2085 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002086}
2087
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002088/*
2089 * Free allocated data structures
2090 */
2091static void nand_free_kmem(struct nand_chip *this)
2092{
2093 /* Buffer allocated by nand_scan ? */
2094 if (this->options & NAND_OOBBUF_ALLOC)
2095 kfree(this->oob_buf);
2096 /* Buffer allocated by nand_scan ? */
2097 if (this->options & NAND_DATABUF_ALLOC)
2098 kfree(this->data_buf);
2099 /* Controller allocated by nand_scan ? */
2100 if (this->options & NAND_CONTROLLER_ALLOC)
2101 kfree(this->controller);
2102}
2103
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002104/*
2105 * Allocate buffers and data structures
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002107static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002109 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002111 if (!this->oob_buf) {
2112 len = mtd->oobsize <<
2113 (this->phys_erase_shift - this->page_shift);
2114 this->oob_buf = kmalloc(len, GFP_KERNEL);
2115 if (!this->oob_buf)
2116 goto outerr;
2117 this->options |= NAND_OOBBUF_ALLOC;
David Woodhouse552d9202006-05-14 01:20:46 +01002118 }
2119
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002120 if (!this->data_buf) {
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002121 len = mtd->writesize + mtd->oobsize;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002122 this->data_buf = kmalloc(len, GFP_KERNEL);
2123 if (!this->data_buf)
2124 goto outerr;
2125 this->options |= NAND_DATABUF_ALLOC;
2126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002128 if (!this->controller) {
2129 this->controller = kzalloc(sizeof(struct nand_hw_control),
2130 GFP_KERNEL);
2131 if (!this->controller)
2132 goto outerr;
2133 this->options |= NAND_CONTROLLER_ALLOC;
2134 }
2135 return 0;
2136
2137 outerr:
2138 printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
2139 nand_free_kmem(this);
2140 return -ENOMEM;
2141}
2142
2143/*
2144 * Set default functions
2145 */
2146static void nand_set_defaults(struct nand_chip *this, int busw)
2147{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 /* check for proper chip_delay setup, set 20us if not */
2149 if (!this->chip_delay)
2150 this->chip_delay = 20;
2151
2152 /* check, if a user supplied command function given */
2153 if (this->cmdfunc == NULL)
2154 this->cmdfunc = nand_command;
2155
2156 /* check, if a user supplied wait function given */
2157 if (this->waitfunc == NULL)
2158 this->waitfunc = nand_wait;
2159
2160 if (!this->select_chip)
2161 this->select_chip = nand_select_chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 if (!this->read_byte)
2163 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (!this->read_word)
2165 this->read_word = nand_read_word;
2166 if (!this->block_bad)
2167 this->block_bad = nand_block_bad;
2168 if (!this->block_markbad)
2169 this->block_markbad = nand_default_block_markbad;
2170 if (!this->write_buf)
2171 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2172 if (!this->read_buf)
2173 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2174 if (!this->verify_buf)
2175 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2176 if (!this->scan_bbt)
2177 this->scan_bbt = nand_default_bbt;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002178}
2179
2180/*
2181 * Get the flash and manufacturer id and lookup if the typ is supported
2182 */
2183static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2184 struct nand_chip *this,
2185 int busw, int *maf_id)
2186{
2187 struct nand_flash_dev *type = NULL;
2188 int i, dev_id, maf_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
2190 /* Select the device */
2191 this->select_chip(mtd, 0);
2192
2193 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002194 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196 /* Read manufacturer and device IDs */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002197 *maf_id = this->read_byte(mtd);
2198 dev_id = this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002200 /* Lookup the flash id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002202 if (dev_id == nand_flash_ids[i].id) {
2203 type = &nand_flash_ids[i];
2204 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002208 if (!type)
2209 return ERR_PTR(-ENODEV);
2210
2211 this->chipsize = nand_flash_ids[i].chipsize << 20;
2212
2213 /* Newer devices have all the information in additional id bytes */
2214 if (!nand_flash_ids[i].pagesize) {
2215 int extid;
2216 /* The 3rd id byte contains non relevant data ATM */
2217 extid = this->read_byte(mtd);
2218 /* The 4th id byte is the important one */
2219 extid = this->read_byte(mtd);
2220 /* Calc pagesize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002221 mtd->writesize = 1024 << (extid & 0x3);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002222 extid >>= 2;
2223 /* Calc oobsize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002224 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002225 extid >>= 2;
2226 /* Calc blocksize. Blocksize is multiples of 64KiB */
2227 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2228 extid >>= 2;
2229 /* Get buswidth information */
2230 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
2231
2232 } else {
2233 /*
2234 * Old devices have this data hardcoded in the device id table
2235 */
2236 mtd->erasesize = nand_flash_ids[i].erasesize;
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002237 mtd->writesize = nand_flash_ids[i].pagesize;
2238 mtd->oobsize = mtd->writesize / 32;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002239 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2240 }
2241
2242 /* Try to identify manufacturer */
2243 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
2244 if (nand_manuf_ids[maf_idx].id == *maf_id)
2245 break;
2246 }
2247
2248 /*
2249 * Check, if buswidth is correct. Hardware drivers should set
2250 * this correct !
2251 */
2252 if (busw != (this->options & NAND_BUSWIDTH_16)) {
2253 printk(KERN_INFO "NAND device: Manufacturer ID:"
2254 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2255 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2256 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
2257 (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
2258 busw ? 16 : 8);
2259 return ERR_PTR(-EINVAL);
2260 }
2261
2262 /* Calculate the address shift from the page size */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002263 this->page_shift = ffs(mtd->writesize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002264 /* Convert chipsize to number of pages per chip -1. */
2265 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2266
2267 this->bbt_erase_shift = this->phys_erase_shift =
2268 ffs(mtd->erasesize) - 1;
2269 this->chip_shift = ffs(this->chipsize) - 1;
2270
2271 /* Set the bad block position */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002272 this->badblockpos = mtd->writesize > 512 ?
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002273 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2274
2275 /* Get chip options, preserve non chip based options */
2276 this->options &= ~NAND_CHIPOPTIONS_MSK;
2277 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
2278
2279 /*
2280 * Set this as a default. Board drivers can override it, if necessary
2281 */
2282 this->options |= NAND_NO_AUTOINCR;
2283
2284 /* Check if this is a not a samsung device. Do not clear the
2285 * options for chips which are not having an extended id.
2286 */
2287 if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2288 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
2289
2290 /* Check for AND chips with 4 page planes */
2291 if (this->options & NAND_4PAGE_ARRAY)
2292 this->erase_cmd = multi_erase_cmd;
2293 else
2294 this->erase_cmd = single_erase_cmd;
2295
2296 /* Do not replace user supplied command function ! */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002297 if (mtd->writesize > 512 && this->cmdfunc == nand_command)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002298 this->cmdfunc = nand_command_lp;
2299
2300 printk(KERN_INFO "NAND device: Manufacturer ID:"
2301 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2302 nand_manuf_ids[maf_idx].name, type->name);
2303
2304 return type;
2305}
2306
2307/* module_text_address() isn't exported, and it's mostly a pointless
2308 test if this is a module _anyway_ -- they'd have to try _really_ hard
2309 to call us from in-kernel code if the core NAND support is modular. */
2310#ifdef MODULE
2311#define caller_is_module() (1)
2312#else
2313#define caller_is_module() \
2314 module_text_address((unsigned long)__builtin_return_address(0))
2315#endif
2316
2317/**
2318 * nand_scan - [NAND Interface] Scan for the NAND device
2319 * @mtd: MTD device structure
2320 * @maxchips: Number of chips to scan for
2321 *
2322 * This fills out all the uninitialized function pointers
2323 * with the defaults.
2324 * The flash ID is read and the mtd/chip structures are
2325 * filled with the appropriate values. Buffers are allocated if
2326 * they are not provided by the board driver
2327 * The mtd->owner field must be set to the module of the caller
2328 *
2329 */
2330int nand_scan(struct mtd_info *mtd, int maxchips)
2331{
2332 int i, busw, nand_maf_id;
2333 struct nand_chip *this = mtd->priv;
2334 struct nand_flash_dev *type;
2335
2336 /* Many callers got this wrong, so check for it for a while... */
2337 if (!mtd->owner && caller_is_module()) {
2338 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2339 BUG();
2340 }
2341
2342 /* Get buswidth to select the correct functions */
2343 busw = this->options & NAND_BUSWIDTH_16;
2344 /* Set the default functions */
2345 nand_set_defaults(this, busw);
2346
2347 /* Read the flash type */
2348 type = nand_get_flash_type(mtd, this, busw, &nand_maf_id);
2349
2350 if (IS_ERR(type)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002351 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 this->select_chip(mtd, -1);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002353 return PTR_ERR(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
2355
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002356 /* Check for a chip array */
David Woodhousee0c7d762006-05-13 18:07:53 +01002357 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 this->select_chip(mtd, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002360 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 /* Read manufacturer and device IDs */
2362 if (nand_maf_id != this->read_byte(mtd) ||
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002363 type->id != this->read_byte(mtd))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 break;
2365 }
2366 if (i > 1)
2367 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 /* Store the number of chips and calc total size for mtd */
2370 this->numchips = i;
2371 mtd->size = i * this->chipsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002373 /* Allocate buffers and data structures */
2374 if (nand_allocate_kmem(mtd, this))
2375 return -ENOMEM;
2376
2377 /* Preset the internal oob buffer */
2378 memset(this->oob_buf, 0xff,
2379 mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2380
2381 /*
2382 * If no default placement scheme is given, select an appropriate one
2383 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 if (!this->autooob) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002385 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 case 8:
2387 this->autooob = &nand_oob_8;
2388 break;
2389 case 16:
2390 this->autooob = &nand_oob_16;
2391 break;
2392 case 64:
2393 this->autooob = &nand_oob_64;
2394 break;
2395 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002396 printk(KERN_WARNING "No oob scheme defined for "
2397 "oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 BUG();
2399 }
2400 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002401
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002402 /*
2403 * The number of bytes available for the filesystem to place fs
2404 * dependend oob data
2405 */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002406 mtd->oobavail = 0;
2407 for (i = 0; this->autooob->oobfree[i][1]; i++)
2408 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002410 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002411 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2412 * selected and we have 256 byte pagesize fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002413 */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002414 switch (this->ecc.mode) {
2415 case NAND_ECC_HW:
2416 case NAND_ECC_HW_SYNDROME:
2417 if (!this->ecc.calculate || !this->ecc.correct ||
2418 !this->ecc.hwctl) {
2419 printk(KERN_WARNING "No ECC functions supplied, "
2420 "Hardware ECC not possible\n");
2421 BUG();
2422 }
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002423 if (mtd->writesize >= this->ecc.size)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002424 break;
2425 printk(KERN_WARNING "%d byte HW ECC not possible on "
2426 "%d byte page size, fallback to SW ECC\n",
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002427 this->ecc.size, mtd->writesize);
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002428 this->ecc.mode = NAND_ECC_SOFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002430 case NAND_ECC_SOFT:
2431 this->ecc.calculate = nand_calculate_ecc;
2432 this->ecc.correct = nand_correct_data;
2433 this->ecc.size = 256;
2434 this->ecc.bytes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002436
2437 case NAND_ECC_NONE:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002438 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2439 "This is not recommended !!\n");
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002440 this->ecc.size = mtd->writesize;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002441 this->ecc.bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002444 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002445 this->ecc.mode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002446 BUG();
2447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002449 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002450 * Set the number of read / write steps for one page depending on ECC
2451 * mode
2452 */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002453 this->ecc.steps = mtd->writesize / this->ecc.size;
2454 if(this->ecc.steps * this->ecc.size != mtd->writesize) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002455 printk(KERN_WARNING "Invalid ecc parameters\n");
2456 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 /* Initialize state, waitqueue and spinlock */
2460 this->state = FL_READY;
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002461 init_waitqueue_head(&this->controller->wq);
2462 spin_lock_init(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464 /* De-select the device */
2465 this->select_chip(mtd, -1);
2466
2467 /* Invalidate the pagebuffer reference */
2468 this->pagebuf = -1;
2469
2470 /* Fill in remaining MTD driver data */
2471 mtd->type = MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02002472 mtd->flags = MTD_CAP_NANDFLASH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 mtd->ecctype = MTD_ECC_SW;
2474 mtd->erase = nand_erase;
2475 mtd->point = NULL;
2476 mtd->unpoint = NULL;
2477 mtd->read = nand_read;
2478 mtd->write = nand_write;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 mtd->read_oob = nand_read_oob;
2480 mtd->write_oob = nand_write_oob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 mtd->sync = nand_sync;
2482 mtd->lock = NULL;
2483 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002484 mtd->suspend = nand_suspend;
2485 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 mtd->block_isbad = nand_block_isbad;
2487 mtd->block_markbad = nand_block_markbad;
2488
2489 /* and make the autooob the default one */
2490 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2491
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002492 /* Check, if we should skip the bad block table scan */
2493 if (this->options & NAND_SKIP_BBTSCAN)
2494 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
2496 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002497 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498}
2499
2500/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002501 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 * @mtd: MTD device structure
2503*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002504void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505{
2506 struct nand_chip *this = mtd->priv;
2507
2508#ifdef CONFIG_MTD_PARTITIONS
2509 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002510 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511#endif
2512 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002513 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
Jesper Juhlfa671642005-11-07 01:01:27 -08002515 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002516 kfree(this->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002517 /* Free buffers */
2518 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519}
2520
David Woodhousee0c7d762006-05-13 18:07:53 +01002521EXPORT_SYMBOL_GPL(nand_scan);
2522EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002523
2524static int __init nand_base_init(void)
2525{
2526 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2527 return 0;
2528}
2529
2530static void __exit nand_base_exit(void)
2531{
2532 led_trigger_unregister_simple(nand_led_trigger);
2533}
2534
2535module_init(nand_base_init);
2536module_exit(nand_base_exit);
2537
David Woodhousee0c7d762006-05-13 18:07:53 +01002538MODULE_LICENSE("GPL");
2539MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2540MODULE_DESCRIPTION("Generic NAND flash driver code");