blob: 98792ec4c2dc34d7cf6a104c4c3fe38bab3b49e1 [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);
David Woodhousee0c7d762006-05-13 18:07:53 +0100142static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200143 size_t *retlen, uint8_t *buf, uint8_t *eccbuf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200144 struct nand_oobinfo *oobsel);
145static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200146 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200147static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200148 size_t *retlen, const uint8_t *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100149static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200150 size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200151 struct nand_oobinfo *oobsel);
152static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200153 size_t *retlen, const uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200154static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs,
155 unsigned long count, loff_t to, size_t *retlen);
David Woodhousee0c7d762006-05-13 18:07:53 +0100156static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200157 unsigned long count, loff_t to, size_t *retlen,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200158 uint8_t *eccbuf, struct nand_oobinfo *oobsel);
David Woodhousee0c7d762006-05-13 18:07:53 +0100159static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
160static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162/* Some internal functions */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200163static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200164 int page, uint8_t * oob_buf,
David Woodhousee0c7d762006-05-13 18:07:53 +0100165 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200167static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200168 int page, int numpages, uint8_t *oob_buf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200169 struct nand_oobinfo *oobsel, int chipnr,
170 int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171#else
172#define nand_verify_pages(...) (0)
173#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000174
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200175static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd,
176 int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178/**
179 * nand_release_device - [GENERIC] release chip
180 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000181 *
182 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100184static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct nand_chip *this = mtd->priv;
187
188 /* De-select the NAND device */
189 this->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100190
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200191 /* Release the controller and the chip */
192 spin_lock(&this->controller->lock);
193 this->controller->active = NULL;
194 this->state = FL_READY;
195 wake_up(&this->controller->wq);
196 spin_unlock(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199/**
200 * nand_read_byte - [DEFAULT] read one byte from the chip
201 * @mtd: MTD device structure
202 *
203 * Default read function for 8bit buswith
204 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200205static uint8_t nand_read_byte(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 struct nand_chip *this = mtd->priv;
208 return readb(this->IO_ADDR_R);
209}
210
211/**
212 * nand_write_byte - [DEFAULT] write one byte to the chip
213 * @mtd: MTD device structure
214 * @byte: pointer to data byte to write
215 *
216 * Default write function for 8it buswith
217 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200218static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
220 struct nand_chip *this = mtd->priv;
221 writeb(byte, this->IO_ADDR_W);
222}
223
224/**
225 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
226 * @mtd: MTD device structure
227 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000228 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 * endianess conversion
230 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200231static uint8_t nand_read_byte16(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200234 return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
236
237/**
238 * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
239 * @mtd: MTD device structure
240 * @byte: pointer to data byte to write
241 *
242 * Default write function for 16bit buswith with
243 * endianess conversion
244 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200245static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
247 struct nand_chip *this = mtd->priv;
248 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
249}
250
251/**
252 * nand_read_word - [DEFAULT] read one word from the chip
253 * @mtd: MTD device structure
254 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000255 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 * endianess conversion
257 */
258static u16 nand_read_word(struct mtd_info *mtd)
259{
260 struct nand_chip *this = mtd->priv;
261 return readw(this->IO_ADDR_R);
262}
263
264/**
265 * nand_write_word - [DEFAULT] write one word to the chip
266 * @mtd: MTD device structure
267 * @word: data word to write
268 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000269 * Default write function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 * endianess conversion
271 */
272static void nand_write_word(struct mtd_info *mtd, u16 word)
273{
274 struct nand_chip *this = mtd->priv;
275 writew(word, this->IO_ADDR_W);
276}
277
278/**
279 * nand_select_chip - [DEFAULT] control CE line
280 * @mtd: MTD device structure
281 * @chip: chipnumber to select, -1 for deselect
282 *
283 * Default select function for 1 chip devices.
284 */
285static void nand_select_chip(struct mtd_info *mtd, int chip)
286{
287 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100288 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 case -1:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000290 this->hwcontrol(mtd, NAND_CTL_CLRNCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
292 case 0:
293 this->hwcontrol(mtd, NAND_CTL_SETNCE);
294 break;
295
296 default:
297 BUG();
298 }
299}
300
301/**
302 * nand_write_buf - [DEFAULT] write buffer to chip
303 * @mtd: MTD device structure
304 * @buf: data buffer
305 * @len: number of bytes to write
306 *
307 * Default write function for 8bit buswith
308 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200309static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 int i;
312 struct nand_chip *this = mtd->priv;
313
David Woodhousee0c7d762006-05-13 18:07:53 +0100314 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 writeb(buf[i], this->IO_ADDR_W);
316}
317
318/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000319 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 * @mtd: MTD device structure
321 * @buf: buffer to store date
322 * @len: number of bytes to read
323 *
324 * Default read function for 8bit buswith
325 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200326static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 int i;
329 struct nand_chip *this = mtd->priv;
330
David Woodhousee0c7d762006-05-13 18:07:53 +0100331 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 buf[i] = readb(this->IO_ADDR_R);
333}
334
335/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000336 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 * @mtd: MTD device structure
338 * @buf: buffer containing the data to compare
339 * @len: number of bytes to compare
340 *
341 * Default verify function for 8bit buswith
342 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200343static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 int i;
346 struct nand_chip *this = mtd->priv;
347
David Woodhousee0c7d762006-05-13 18:07:53 +0100348 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 if (buf[i] != readb(this->IO_ADDR_R))
350 return -EFAULT;
351
352 return 0;
353}
354
355/**
356 * nand_write_buf16 - [DEFAULT] write buffer to chip
357 * @mtd: MTD device structure
358 * @buf: data buffer
359 * @len: number of bytes to write
360 *
361 * Default write function for 16bit buswith
362 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200363static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 int i;
366 struct nand_chip *this = mtd->priv;
367 u16 *p = (u16 *) buf;
368 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000369
David Woodhousee0c7d762006-05-13 18:07:53 +0100370 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000376 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 * @mtd: MTD device structure
378 * @buf: buffer to store date
379 * @len: number of bytes to read
380 *
381 * Default read function for 16bit buswith
382 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200383static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 int i;
386 struct nand_chip *this = mtd->priv;
387 u16 *p = (u16 *) buf;
388 len >>= 1;
389
David Woodhousee0c7d762006-05-13 18:07:53 +0100390 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 p[i] = readw(this->IO_ADDR_R);
392}
393
394/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000395 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 * @mtd: MTD device structure
397 * @buf: buffer containing the data to compare
398 * @len: number of bytes to compare
399 *
400 * Default verify function for 16bit buswith
401 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200402static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 int i;
405 struct nand_chip *this = mtd->priv;
406 u16 *p = (u16 *) buf;
407 len >>= 1;
408
David Woodhousee0c7d762006-05-13 18:07:53 +0100409 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (p[i] != readw(this->IO_ADDR_R))
411 return -EFAULT;
412
413 return 0;
414}
415
416/**
417 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
418 * @mtd: MTD device structure
419 * @ofs: offset from device start
420 * @getchip: 0, if the chip is already selected
421 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000422 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 */
424static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
425{
426 int page, chipnr, res = 0;
427 struct nand_chip *this = mtd->priv;
428 u16 bad;
429
430 if (getchip) {
431 page = (int)(ofs >> this->page_shift);
432 chipnr = (int)(ofs >> this->chip_shift);
433
434 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100435 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 /* Select the NAND device */
438 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000439 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100440 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 if (this->options & NAND_BUSWIDTH_16) {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200443 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
444 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 bad = cpu_to_le16(this->read_word(mtd));
446 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000447 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if ((bad & 0xFF) != 0xff)
449 res = 1;
450 } else {
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200451 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
452 page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (this->read_byte(mtd) != 0xff)
454 res = 1;
455 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (getchip) {
458 /* Deselect and wake up anyone waiting on the device */
459 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000460 }
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return res;
463}
464
465/**
466 * nand_default_block_markbad - [DEFAULT] mark a block bad
467 * @mtd: MTD device structure
468 * @ofs: offset from device start
469 *
470 * This is the default implementation, which can be overridden by
471 * a hardware specific driver.
472*/
473static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
474{
475 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200476 uint8_t buf[2] = { 0, 0 };
David Woodhousee0c7d762006-05-13 18:07:53 +0100477 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100481 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000482 if (this->bbt)
483 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
485 /* Do we have a flash based bad block table ? */
486 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100487 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 /* We write two bytes, so we dont have to mess with 16 bit access */
490 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100491 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000494/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 * nand_check_wp - [GENERIC] check if the chip is write protected
496 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000497 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000499 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100501static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
503 struct nand_chip *this = mtd->priv;
504 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100505 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000506 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507}
508
509/**
510 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
511 * @mtd: MTD device structure
512 * @ofs: offset from device start
513 * @getchip: 0, if the chip is already selected
514 * @allowbbt: 1, if its allowed to access the bbt area
515 *
516 * Check, if the block is bad. Either by reading the bad block table or
517 * calling of the scan function.
518 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200519static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
520 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (!this->bbt)
525 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100528 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529}
530
Richard Purdie8fe833c2006-03-31 02:31:14 -0800531DEFINE_LED_TRIGGER(nand_led_trigger);
532
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000533/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000534 * Wait for the ready pin, after a command
535 * The timeout is catched later.
536 */
537static void nand_wait_ready(struct mtd_info *mtd)
538{
539 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100540 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000541
Richard Purdie8fe833c2006-03-31 02:31:14 -0800542 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000543 /* wait until command is processed or timeout occures */
544 do {
545 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800546 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700547 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000548 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800549 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000550}
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552/**
553 * nand_command - [DEFAULT] Send command to NAND device
554 * @mtd: MTD device structure
555 * @command: the command to be sent
556 * @column: the column address for this command, -1 if none
557 * @page_addr: the page address for this command, -1 if none
558 *
559 * Send command to NAND device. This function is used for small page
560 * devices (256/512 Bytes per page)
561 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200562static void nand_command(struct mtd_info *mtd, unsigned command, int column,
563 int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 register struct nand_chip *this = mtd->priv;
566
567 /* Begin command latch cycle */
568 this->hwcontrol(mtd, NAND_CTL_SETCLE);
569 /*
570 * Write out the command to the device.
571 */
572 if (command == NAND_CMD_SEQIN) {
573 int readcmd;
574
575 if (column >= mtd->oobblock) {
576 /* OOB area */
577 column -= mtd->oobblock;
578 readcmd = NAND_CMD_READOOB;
579 } else if (column < 256) {
580 /* First 256 bytes --> READ0 */
581 readcmd = NAND_CMD_READ0;
582 } else {
583 column -= 256;
584 readcmd = NAND_CMD_READ1;
585 }
586 this->write_byte(mtd, readcmd);
587 }
588 this->write_byte(mtd, command);
589
590 /* Set ALE and clear CLE to start address cycle */
591 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
592
593 if (column != -1 || page_addr != -1) {
594 this->hwcontrol(mtd, NAND_CTL_SETALE);
595
596 /* Serially input address */
597 if (column != -1) {
598 /* Adjust columns for 16 bit buswidth */
599 if (this->options & NAND_BUSWIDTH_16)
600 column >>= 1;
601 this->write_byte(mtd, column);
602 }
603 if (page_addr != -1) {
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200604 this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
605 this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 /* One more address cycle for devices > 32MiB */
607 if (this->chipsize > (32 << 20))
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200608 this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610 /* Latch in address */
611 this->hwcontrol(mtd, NAND_CTL_CLRALE);
612 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000613
614 /*
615 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100617 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000619
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 case NAND_CMD_PAGEPROG:
621 case NAND_CMD_ERASE1:
622 case NAND_CMD_ERASE2:
623 case NAND_CMD_SEQIN:
624 case NAND_CMD_STATUS:
625 return;
626
627 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000628 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 break;
630 udelay(this->chip_delay);
631 this->hwcontrol(mtd, NAND_CTL_SETCLE);
632 this->write_byte(mtd, NAND_CMD_STATUS);
633 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100634 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return;
636
David Woodhousee0c7d762006-05-13 18:07:53 +0100637 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000639 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 * If we don't have access to the busy pin, we apply the given
641 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100642 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100644 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /* Apply this short delay always to ensure that we do wait tWB in
649 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100650 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000651
652 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
655/**
656 * nand_command_lp - [DEFAULT] Send command to NAND large page device
657 * @mtd: MTD device structure
658 * @command: the command to be sent
659 * @column: the column address for this command, -1 if none
660 * @page_addr: the page address for this command, -1 if none
661 *
662 * Send command to NAND device. This is the version for the new large page devices
David Woodhousee0c7d762006-05-13 18:07:53 +0100663 * We dont have the separate regions as we have in the small page devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 * We must emulate NAND_CMD_READOOB to keep the code compatible.
665 *
666 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100667static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
669 register struct nand_chip *this = mtd->priv;
670
671 /* Emulate NAND_CMD_READOOB */
672 if (command == NAND_CMD_READOOB) {
673 column += mtd->oobblock;
674 command = NAND_CMD_READ0;
675 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 /* Begin command latch cycle */
678 this->hwcontrol(mtd, NAND_CTL_SETCLE);
679 /* Write out the command to the device. */
David A. Marlin30f464b2005-01-17 18:35:25 +0000680 this->write_byte(mtd, (command & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /* End command latch cycle */
682 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
683
684 if (column != -1 || page_addr != -1) {
685 this->hwcontrol(mtd, NAND_CTL_SETALE);
686
687 /* Serially input address */
688 if (column != -1) {
689 /* Adjust columns for 16 bit buswidth */
690 if (this->options & NAND_BUSWIDTH_16)
691 column >>= 1;
692 this->write_byte(mtd, column & 0xff);
693 this->write_byte(mtd, column >> 8);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (page_addr != -1) {
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200696 this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
697 this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 /* One more address cycle for devices > 128MiB */
699 if (this->chipsize > (128 << 20))
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200700 this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
702 /* Latch in address */
703 this->hwcontrol(mtd, NAND_CTL_CLRALE);
704 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000705
706 /*
707 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000708 * status, sequential in, and deplete1 need no delay
709 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 case NAND_CMD_CACHEDPROG:
713 case NAND_CMD_PAGEPROG:
714 case NAND_CMD_ERASE1:
715 case NAND_CMD_ERASE2:
716 case NAND_CMD_SEQIN:
717 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000718 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return;
720
David Woodhousee0c7d762006-05-13 18:07:53 +0100721 /*
722 * read error status commands require only a short delay
723 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000724 case NAND_CMD_STATUS_ERROR:
725 case NAND_CMD_STATUS_ERROR0:
726 case NAND_CMD_STATUS_ERROR1:
727 case NAND_CMD_STATUS_ERROR2:
728 case NAND_CMD_STATUS_ERROR3:
729 udelay(this->chip_delay);
730 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000733 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 break;
735 udelay(this->chip_delay);
736 this->hwcontrol(mtd, NAND_CTL_SETCLE);
737 this->write_byte(mtd, NAND_CMD_STATUS);
738 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100739 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return;
741
742 case NAND_CMD_READ0:
743 /* Begin command latch cycle */
744 this->hwcontrol(mtd, NAND_CTL_SETCLE);
745 /* Write out the start read command */
746 this->write_byte(mtd, NAND_CMD_READSTART);
747 /* End command latch cycle */
748 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
749 /* Fall through into ready check */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000750
David Woodhousee0c7d762006-05-13 18:07:53 +0100751 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000753 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 * If we don't have access to the busy pin, we apply the given
755 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100756 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100758 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 /* Apply this short delay always to ensure that we do wait tWB in
764 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100765 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000766
767 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768}
769
770/**
771 * nand_get_device - [GENERIC] Get chip for selected access
772 * @this: the nand chip descriptor
773 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000774 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 *
776 * Get the device and lock it for exclusive access
777 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200778static int
779nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200781 spinlock_t *lock = &this->controller->lock;
782 wait_queue_head_t *wq = &this->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100783 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100784 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100785 spin_lock(lock);
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200788 /* Hardware controller shared among independend devices */
789 if (!this->controller->active)
790 this->controller->active = this;
791
792 if (this->controller->active == this && this->state == FL_READY) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100793 this->state = new_state;
794 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100795 return 0;
796 }
797 if (new_state == FL_PM_SUSPENDED) {
798 spin_unlock(lock);
799 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100800 }
801 set_current_state(TASK_UNINTERRUPTIBLE);
802 add_wait_queue(wq, &wait);
803 spin_unlock(lock);
804 schedule();
805 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 goto retry;
807}
808
809/**
810 * nand_wait - [DEFAULT] wait until the command is done
811 * @mtd: MTD device structure
812 * @this: NAND chip structure
813 * @state: state to select the max. timeout value
814 *
815 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000816 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 * general NAND and SmartMedia specs
818 *
819*/
820static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
821{
822
David Woodhousee0c7d762006-05-13 18:07:53 +0100823 unsigned long timeo = jiffies;
824 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100827 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100829 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Richard Purdie8fe833c2006-03-31 02:31:14 -0800831 led_trigger_event(nand_led_trigger, LED_FULL);
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 /* Apply this short delay always to ensure that we do wait tWB in
834 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100835 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100838 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000839 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100840 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000842 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* Check, if we were interrupted */
844 if (this->state != state)
845 return 0;
846
847 if (this->dev_ready) {
848 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000849 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 } else {
851 if (this->read_byte(mtd) & NAND_STATUS_READY)
852 break;
853 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000854 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800856 led_trigger_event(nand_led_trigger, LED_OFF);
857
David Woodhousee0c7d762006-05-13 18:07:53 +0100858 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 return status;
860}
861
862/**
863 * nand_write_page - [GENERIC] write one page
864 * @mtd: MTD device structure
865 * @this: NAND chip structure
866 * @page: startpage inside the chip, must be called with (page & this->pagemask)
867 * @oob_buf: out of band data buffer
868 * @oobsel: out of band selecttion structre
869 * @cached: 1 = enable cached programming if supported by chip
870 *
871 * Nand_page_program function is used for write and writev !
872 * This function will always program a full page of data
873 * If you call it with a non page aligned buffer, you're lost :)
874 *
875 * Cached programming is not supported yet.
876 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100877static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200878 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
David Woodhousee0c7d762006-05-13 18:07:53 +0100880 int i, status;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200881 uint8_t ecc_code[32];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200882 int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
David Woodhousee0c7d762006-05-13 18:07:53 +0100883 int *oob_config = oobsel->eccpos;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200884 int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100885 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 /* FIXME: Enable cached programming */
888 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100891 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 /* Write out complete page of data, take care of eccmode */
894 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100895 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100897 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 this->write_buf(mtd, this->data_poi, mtd->oobblock);
899 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000900
David Woodhousee0c7d762006-05-13 18:07:53 +0100901 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 case NAND_ECC_SOFT:
903 for (; eccsteps; eccsteps--) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200904 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 for (i = 0; i < 3; i++, eccidx++)
906 oob_buf[oob_config[eccidx]] = ecc_code[i];
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200907 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 this->write_buf(mtd, this->data_poi, mtd->oobblock);
910 break;
911 default:
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200912 eccbytes = this->ecc.bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 for (; eccsteps; eccsteps--) {
914 /* enable hardware ecc logic for write */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200915 this->ecc.hwctl(mtd, NAND_ECC_WRITE);
916 this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
917 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 for (i = 0; i < eccbytes; i++, eccidx++)
919 oob_buf[oob_config[eccidx]] = ecc_code[i];
920 /* If the hardware ecc provides syndromes then
921 * the ecc code must be written immidiately after
922 * the data bytes (words) */
923 if (this->options & NAND_HWECC_SYNDROME)
924 this->write_buf(mtd, ecc_code, eccbytes);
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +0200925 datidx += this->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
927 break;
928 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 /* Write out OOB data */
931 if (this->options & NAND_HWECC_SYNDROME)
932 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000933 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 this->write_buf(mtd, oob_buf, mtd->oobsize);
935
936 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100937 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
939 if (!cached) {
940 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100941 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000942
943 /* See if operation failed and additional status checks are available */
944 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
945 status = this->errstat(mtd, this, FL_WRITING, status, page);
946 }
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000949 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100950 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return -EIO;
952 }
953 } else {
954 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100955 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
957 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000958 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
961#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
962/**
963 * nand_verify_pages - [GENERIC] verify the chip contents after a write
964 * @mtd: MTD device structure
965 * @this: NAND chip structure
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200966 * @page: startpage inside the chip, must be called with (page & this->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 * @numpages: number of pages to verify
968 * @oob_buf: out of band data buffer
969 * @oobsel: out of band selecttion structre
970 * @chipnr: number of the current chip
971 * @oobmode: 1 = full buffer verify, 0 = ecc only
972 *
973 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000974 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000976 * byte by byte basis. It is possible that the page was not completely erased
977 * or the page is becoming unusable due to wear. The read with ECC would catch
978 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 * it early in the page write stage. Better to write no data than invalid data.
980 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100981static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200982 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
David Woodhousee0c7d762006-05-13 18:07:53 +0100984 int i, j, datidx = 0, oobofs = 0, res = -EIO;
985 int eccsteps = this->eccsteps;
986 int hweccbytes;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200987 uint8_t oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
990
991 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100992 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
David Woodhousee0c7d762006-05-13 18:07:53 +0100994 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 for (j = 0; j < eccsteps; j++) {
996 /* Loop through and verify the data */
997 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100998 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 goto out;
1000 }
1001 datidx += mtd->eccsize;
1002 /* Have we a hw generator layout ? */
1003 if (!hweccbytes)
1004 continue;
1005 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001006 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 goto out;
1008 }
1009 oobofs += hweccbytes;
1010 }
1011
1012 /* check, if we must compare all data or if we just have to
1013 * compare the ecc bytes
1014 */
1015 if (oobmode) {
1016 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001017 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 goto out;
1019 }
1020 } else {
1021 /* Read always, else autoincrement fails */
1022 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
1023
1024 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
1025 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 for (i = 0; i < ecccnt; i++) {
1028 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +01001029 if (oobdata[idx] != oob_buf[oobofs + idx]) {
1030 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
1031 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 goto out;
1033 }
1034 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 }
1037 oobofs += mtd->oobsize - hweccbytes * eccsteps;
1038 page++;
1039 numpages--;
1040
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001041 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 * Do this before the AUTOINCR check, so no problems
1043 * arise if a chip which does auto increment
1044 * is marked as NOAUTOINCR by the board driver.
1045 * Do this also before returning, so the chip is
1046 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +01001047 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001048 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001049 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001051 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 /* All done, return happy */
1054 if (!numpages)
1055 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001056
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001057 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001059 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001061 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 * Terminate the read command. We come here in case of an error
1063 * So we must issue a reset command.
1064 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001065 out:
1066 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return res;
1068}
1069#endif
1070
1071/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001072 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 * @mtd: MTD device structure
1074 * @from: offset to read from
1075 * @len: number of bytes to read
1076 * @retlen: pointer to variable to store the number of read bytes
1077 * @buf: the databuffer to put data
1078 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001079 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1080 * and flags = 0xff
1081 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001082static 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 -07001083{
David Woodhousee0c7d762006-05-13 18:07:53 +01001084 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001085}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001088 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 * @mtd: MTD device structure
1090 * @from: offset to read from
1091 * @len: number of bytes to read
1092 * @retlen: pointer to variable to store the number of read bytes
1093 * @buf: the databuffer to put data
1094 * @oob_buf: filesystem supplied oob data buffer
1095 * @oobsel: oob selection structure
1096 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001097 * This function simply calls nand_do_read_ecc with flags = 0xff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001099static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001100 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001102 /* use userspace supplied oobinfo, if zero */
1103 if (oobsel == NULL)
1104 oobsel = &mtd->oobinfo;
David A. Marlin068e3c02005-01-24 03:07:46 +00001105 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1106}
1107
David A. Marlin068e3c02005-01-24 03:07:46 +00001108/**
1109 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1110 * @mtd: MTD device structure
1111 * @from: offset to read from
1112 * @len: number of bytes to read
1113 * @retlen: pointer to variable to store the number of read bytes
1114 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001115 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001116 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001117 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1118 * and how many corrected error bits are acceptable:
1119 * bits 0..7 - number of tolerable errors
1120 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1121 *
1122 * NAND read with ECC
1123 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001124int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001125 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001126{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1129 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1130 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001131 uint8_t *data_poi, *oob_data = oob_buf;
1132 uint8_t ecc_calc[32];
1133 uint8_t ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001134 int eccmode, eccsteps;
1135 int *oob_config, datidx;
1136 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1137 int eccbytes;
1138 int compareecc = 1;
1139 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
David Woodhousee0c7d762006-05-13 18:07:53 +01001141 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 -07001142
1143 /* Do not allow reads past end of device */
1144 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001145 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 *retlen = 0;
1147 return -EINVAL;
1148 }
1149
1150 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001151 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001152 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 /* Autoplace of oob data ? Use the default placement scheme */
1155 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1156 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001157
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001158 eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 oob_config = oobsel->eccpos;
1160
1161 /* Select the NAND device */
1162 chipnr = (int)(from >> this->chip_shift);
1163 this->select_chip(mtd, chipnr);
1164
1165 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001166 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 page = realpage & this->pagemask;
1168
1169 /* Get raw starting column */
1170 col = from & (mtd->oobblock - 1);
1171
1172 end = mtd->oobblock;
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001173 ecc = this->ecc.size;
1174 eccbytes = this->ecc.bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1177 compareecc = 0;
1178
1179 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001180 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 oobreadlen -= oobsel->eccbytes;
1182
1183 /* Loop until all data read */
1184 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001187 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 * If the read is not page aligned, we have to read into data buffer
1189 * due to ecc, else we read into return buffer direct
1190 */
1191 if (aligned)
1192 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001193 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001195
1196 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 *
1198 * FIXME: Make it work when we must provide oob data too,
1199 * check the usage of data_buf oob field
1200 */
1201 if (realpage == this->pagebuf && !oob_buf) {
1202 /* aligned read ? */
1203 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001204 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 goto readdata;
1206 }
1207
1208 /* Check, if we must send the read command */
1209 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001210 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001215 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1216 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 oob_data = &this->data_buf[end];
1218
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001219 eccsteps = this->ecc.steps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001222 case NAND_ECC_NONE:{
1223 /* No ECC, Read in a page */
1224 static unsigned long lastwhinge = 0;
1225 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1226 printk(KERN_WARNING
1227 "Reading data from NAND FLASH without ECC is not recommended\n");
1228 lastwhinge = jiffies;
1229 }
1230 this->read_buf(mtd, data_poi, end);
1231 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1235 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001236 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001237 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001238 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001241 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001242 this->ecc.hwctl(mtd, NAND_ECC_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 this->read_buf(mtd, &data_poi[datidx], ecc);
1244
1245 /* HW ecc with syndrome calculation must read the
1246 * syndrome from flash immidiately after the data */
1247 if (!compareecc) {
1248 /* Some hw ecc generators need to know when the
1249 * syndrome is read from flash */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001250 this->ecc.hwctl(mtd, NAND_ECC_READSYN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 this->read_buf(mtd, &oob_data[i], eccbytes);
1252 /* We calc error correction directly, it checks the hw
1253 * generator for an error, reads back the syndrome and
1254 * does the error correction on the fly */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001255 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
David A. Marlin068e3c02005-01-24 03:07:46 +00001256 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001257 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1258 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 ecc_failed++;
1260 }
1261 } else {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001262 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 }
1267
1268 /* read oobdata */
1269 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1270
1271 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1272 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001273 goto readoob;
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 /* Pick the ECC bytes out of the oob data */
1276 for (j = 0; j < oobsel->eccbytes; j++)
1277 ecc_code[j] = oob_data[oob_config[j]];
1278
David Woodhousee0c7d762006-05-13 18:07:53 +01001279 /* correct data, if necessary */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001280 for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
1281 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 /* Get next chunk of ecc bytes */
1284 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001285
1286 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 * This is the legacy mode. Used by YAFFS1
1288 * Should go away some day
1289 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001290 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 int *p = (int *)(&oob_data[mtd->oobsize]);
1292 p[i] = ecc_status;
1293 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001294
1295 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001296 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 ecc_failed++;
1298 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
David Woodhousee0c7d762006-05-13 18:07:53 +01001301 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 /* check, if we have a fs supplied oob-buffer */
1303 if (oob_buf) {
1304 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001305 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001307 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001309 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 int from = oobsel->oobfree[i][0];
1311 int num = oobsel->oobfree[i][1];
1312 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001313 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 break;
1316 case MTD_NANDECC_PLACE:
1317 /* YAFFS1 legacy mode */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02001318 oob_data += this->ecc.steps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 default:
1320 oob_data += mtd->oobsize;
1321 }
1322 }
1323 readdata:
1324 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001325 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 for (j = col; j < end && read < len; j++)
1327 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001328 this->pagebuf = realpage;
1329 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 read += mtd->oobblock;
1331
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001332 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 * Do this before the AUTOINCR check, so no problems
1334 * arise if a chip which does auto increment
1335 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001336 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001337 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001338 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001340 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001343 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 /* For subsequent reads align to page boundary. */
1346 col = 0;
1347 /* Increment page address */
1348 realpage++;
1349
1350 page = realpage & this->pagemask;
1351 /* Check, if we cross a chip boundary */
1352 if (!page) {
1353 chipnr++;
1354 this->select_chip(mtd, -1);
1355 this->select_chip(mtd, chipnr);
1356 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001357 /* Check, if the chip supports auto page increment
1358 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001359 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001361 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 }
1363
1364 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001365 if (flags & NAND_GET_DEVICE)
1366 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 /*
1369 * Return success, if no ECC failures, else -EBADMSG
1370 * fs driver will take care of that, because
1371 * retlen == desired len and result == -EBADMSG
1372 */
1373 *retlen = read;
1374 return ecc_failed ? -EBADMSG : 0;
1375}
1376
1377/**
1378 * nand_read_oob - [MTD Interface] NAND read out-of-band
1379 * @mtd: MTD device structure
1380 * @from: offset to read from
1381 * @len: number of bytes to read
1382 * @retlen: pointer to variable to store the number of read bytes
1383 * @buf: the databuffer to put data
1384 *
1385 * NAND read out-of-band data from the spare area
1386 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001387static 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 -07001388{
1389 int i, col, page, chipnr;
1390 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001391 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
David Woodhousee0c7d762006-05-13 18:07:53 +01001393 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 -07001394
1395 /* Shift to get page */
1396 page = (int)(from >> this->page_shift);
1397 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 /* Mask to get column */
1400 col = from & (mtd->oobsize - 1);
1401
1402 /* Initialize return length value */
1403 *retlen = 0;
1404
1405 /* Do not allow reads past end of device */
1406 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001407 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 *retlen = 0;
1409 return -EINVAL;
1410 }
1411
1412 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001413 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 /* Select the NAND device */
1416 this->select_chip(mtd, chipnr);
1417
1418 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001419 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001420 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 * Read the data, if we read more than one page
1422 * oob data, let the device transfer the data !
1423 */
1424 i = 0;
1425 while (i < len) {
1426 int thislen = mtd->oobsize - col;
1427 thislen = min_t(int, thislen, len);
1428 this->read_buf(mtd, &buf[i], thislen);
1429 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 /* Read more ? */
1432 if (i < len) {
1433 page++;
1434 col = 0;
1435
1436 /* Check, if we cross a chip boundary */
1437 if (!(page & this->pagemask)) {
1438 chipnr++;
1439 this->select_chip(mtd, -1);
1440 this->select_chip(mtd, chipnr);
1441 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001442
1443 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001444 * Do this before the AUTOINCR check, so no problems
1445 * arise if a chip which does auto increment
1446 * is marked as NOAUTOINCR by the board driver.
1447 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001448 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001449 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001450 else
1451 nand_wait_ready(mtd);
1452
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001453 /* Check, if the chip supports auto page increment
1454 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001455 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1457 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001458 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 }
1460 }
1461 }
1462
1463 /* Deselect and wake up anyone waiting on the device */
1464 nand_release_device(mtd);
1465
1466 /* Return happy */
1467 *retlen = len;
1468 return 0;
1469}
1470
1471/**
1472 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1473 * @mtd: MTD device structure
1474 * @buf: temporary buffer
1475 * @from: offset to read from
1476 * @len: number of bytes to read
1477 * @ooblen: number of oob data bytes to read
1478 *
1479 * Read raw data including oob into buffer
1480 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001481int 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 -07001482{
1483 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001484 int page = (int)(from >> this->page_shift);
1485 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 int sndcmd = 1;
1487 int cnt = 0;
1488 int pagesize = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001489 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 /* Do not allow reads past end of device */
1492 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001493 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 return -EINVAL;
1495 }
1496
1497 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001498 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
David Woodhousee0c7d762006-05-13 18:07:53 +01001500 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001501
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 /* Add requested oob length */
1503 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 while (len) {
1506 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001507 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001508 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
David Woodhousee0c7d762006-05-13 18:07:53 +01001510 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 len -= pagesize;
1513 cnt += pagesize;
1514 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001515
1516 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001517 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001519 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001520
1521 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1523 sndcmd = 1;
1524 }
1525
1526 /* Deselect and wake up anyone waiting on the device */
1527 nand_release_device(mtd);
1528 return 0;
1529}
1530
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001531/**
1532 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 * @mtd: MTD device structure
1534 * @fsbuf: buffer given by fs driver
1535 * @oobsel: out of band selection structre
1536 * @autoplace: 1 = place given buffer into the oob bytes
1537 * @numpages: number of pages to prepare
1538 *
1539 * Return:
1540 * 1. Filesystem buffer available and autoplacement is off,
1541 * return filesystem buffer
1542 * 2. No filesystem buffer or autoplace is off, return internal
1543 * buffer
1544 * 3. Filesystem buffer is given and autoplace selected
1545 * put data from fs buffer into internal buffer and
1546 * retrun internal buffer
1547 *
1548 * Note: The internal buffer is filled with 0xff. This must
1549 * be done only once, when no autoplacement happens
1550 * Autoplacement sets the buffer dirty flag, which
1551 * forces the 0xff fill before using the buffer again.
1552 *
1553*/
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001554static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
David Woodhousee0c7d762006-05-13 18:07:53 +01001555 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556{
1557 struct nand_chip *this = mtd->priv;
1558 int i, len, ofs;
1559
1560 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001561 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 return fsbuf;
1563
1564 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001565 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001566 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001568 }
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 /* If we have no autoplacement or no fs buffer use the internal one */
1571 if (!autoplace || !fsbuf)
1572 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 /* Walk through the pages and place the data */
1575 this->oobdirty = 1;
1576 ofs = 0;
1577 while (numpages--) {
1578 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1579 int to = ofs + oobsel->oobfree[i][0];
1580 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001581 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 len += num;
1583 fsbuf += num;
1584 }
1585 ofs += mtd->oobavail;
1586 }
1587 return this->oob_buf;
1588}
1589
1590#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
1591
1592/**
1593 * nand_write - [MTD Interface] compability function for nand_write_ecc
1594 * @mtd: MTD device structure
1595 * @to: offset to write to
1596 * @len: number of bytes to write
1597 * @retlen: pointer to variable to store the number of written bytes
1598 * @buf: the data to write
1599 *
1600 * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
1601 *
1602*/
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001603static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604{
David Woodhousee0c7d762006-05-13 18:07:53 +01001605 return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608/**
1609 * nand_write_ecc - [MTD Interface] NAND write with ECC
1610 * @mtd: MTD device structure
1611 * @to: offset to write to
1612 * @len: number of bytes to write
1613 * @retlen: pointer to variable to store the number of written bytes
1614 * @buf: the data to write
1615 * @eccbuf: filesystem supplied oob data buffer
1616 * @oobsel: oob selection structure
1617 *
1618 * NAND write with ECC
1619 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001620static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001621 size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
David Woodhousee0c7d762006-05-13 18:07:53 +01001622 struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623{
1624 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1625 int autoplace = 0, numpages, totalpages;
1626 struct nand_chip *this = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001627 uint8_t *oobbuf, *bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001628 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
David Woodhousee0c7d762006-05-13 18:07:53 +01001630 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632 /* Initialize retlen, in case of early exit */
1633 *retlen = 0;
1634
1635 /* Do not allow write past end of device */
1636 if ((to + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001637 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 return -EINVAL;
1639 }
1640
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001641 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001642 if (NOTALIGNED(to) || NOTALIGNED(len)) {
1643 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 return -EINVAL;
1645 }
1646
1647 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001648 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 /* Calculate chipnr */
1651 chipnr = (int)(to >> this->chip_shift);
1652 /* Select the NAND device */
1653 this->select_chip(mtd, chipnr);
1654
1655 /* Check, if it is write protected */
1656 if (nand_check_wp(mtd))
1657 goto out;
1658
1659 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001660 if (oobsel == NULL)
1661 oobsel = &mtd->oobinfo;
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 /* Autoplace of oob data ? Use the default placement scheme */
1664 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1665 oobsel = this->autooob;
1666 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001667 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001668 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1669 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 /* Setup variables and oob buffer */
1672 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001673 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001675 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 /* Set it relative to chip */
1679 page &= this->pagemask;
1680 startpage = page;
1681 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001682 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1683 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001684 bufstart = (uint8_t *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
1686 /* Loop until all data is written */
1687 while (written < len) {
1688
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001689 this->data_poi = (uint8_t *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 /* Write one page. If this is the last page to write
1691 * or the last page in this block, then use the
1692 * real pageprogram command, else select cached programming
1693 * if supported by the chip.
1694 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001695 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001697 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* Next oob page */
1701 oob += mtd->oobsize;
1702 /* Update written bytes count */
1703 written += mtd->oobblock;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001704 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 /* Increment page address */
1708 page++;
1709
1710 /* Have we hit a block boundary ? Then we have to verify and
1711 * if verify is ok, we have to setup the oob buffer for
1712 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001713 */
1714 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 int ofs;
1716 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001717 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1718 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001720 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 *retlen = written;
1724
1725 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1726 if (eccbuf)
1727 eccbuf += (page - startpage) * ofs;
1728 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001729 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 page &= this->pagemask;
1731 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001732 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001733 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* Check, if we cross a chip boundary */
1735 if (!page) {
1736 chipnr++;
1737 this->select_chip(mtd, -1);
1738 this->select_chip(mtd, chipnr);
1739 }
1740 }
1741 }
1742 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001743 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001745 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (!ret)
1747 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001748 else
David Woodhousee0c7d762006-05-13 18:07:53 +01001749 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
David Woodhousee0c7d762006-05-13 18:07:53 +01001751 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 /* Deselect and wake up anyone waiting on the device */
1753 nand_release_device(mtd);
1754
1755 return ret;
1756}
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758/**
1759 * nand_write_oob - [MTD Interface] NAND write out-of-band
1760 * @mtd: MTD device structure
1761 * @to: offset to write to
1762 * @len: number of bytes to write
1763 * @retlen: pointer to variable to store the number of written bytes
1764 * @buf: the data to write
1765 *
1766 * NAND write out-of-band
1767 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001768static 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 -07001769{
1770 int column, page, status, ret = -EIO, chipnr;
1771 struct nand_chip *this = mtd->priv;
1772
David Woodhousee0c7d762006-05-13 18:07:53 +01001773 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 -07001774
1775 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001776 page = (int)(to >> this->page_shift);
1777 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
1779 /* Mask to get column */
1780 column = to & (mtd->oobsize - 1);
1781
1782 /* Initialize return length value */
1783 *retlen = 0;
1784
1785 /* Do not allow write past end of page */
1786 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001787 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 return -EINVAL;
1789 }
1790
1791 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001792 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 /* Select the NAND device */
1795 this->select_chip(mtd, chipnr);
1796
1797 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1798 in one of my DiskOnChip 2000 test units) will clear the whole
1799 data page too if we don't do this. I have no clue why, but
1800 I seem to have 'fixed' it in the doc2000 driver in
1801 August 1999. dwmw2. */
1802 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1803
1804 /* Check, if it is write protected */
1805 if (nand_check_wp(mtd))
1806 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* Invalidate the page cache, if we write to the cached page */
1809 if (page == this->pagebuf)
1810 this->pagebuf = -1;
1811
1812 if (NAND_MUST_PAD(this)) {
1813 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001814 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 /* prepad 0xff for partial programming */
1816 this->write_buf(mtd, ffchars, column);
1817 /* write data */
1818 this->write_buf(mtd, buf, len);
1819 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001820 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 } else {
1822 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001823 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 /* write data */
1825 this->write_buf(mtd, buf, len);
1826 }
1827 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001828 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
David Woodhousee0c7d762006-05-13 18:07:53 +01001830 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
1832 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001833 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001834 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 ret = -EIO;
1836 goto out;
1837 }
1838 /* Return happy */
1839 *retlen = len;
1840
1841#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1842 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001843 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001846 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 ret = -EIO;
1848 goto out;
1849 }
1850#endif
1851 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001852 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* Deselect and wake up anyone waiting on the device */
1854 nand_release_device(mtd);
1855
1856 return ret;
1857}
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859/**
1860 * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
1861 * @mtd: MTD device structure
1862 * @vecs: the iovectors to write
1863 * @count: number of vectors
1864 * @to: offset to write to
1865 * @retlen: pointer to variable to store the number of written bytes
1866 *
1867 * NAND write with kvec. This just calls the ecc function
1868 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001869static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1870 loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871{
David Woodhousee0c7d762006-05-13 18:07:53 +01001872 return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873}
1874
1875/**
1876 * nand_writev_ecc - [MTD Interface] write with iovec with ecc
1877 * @mtd: MTD device structure
1878 * @vecs: the iovectors to write
1879 * @count: number of vectors
1880 * @to: offset to write to
1881 * @retlen: pointer to variable to store the number of written bytes
1882 * @eccbuf: filesystem supplied oob data buffer
1883 * @oobsel: oob selection structure
1884 *
1885 * NAND write with iovec with ecc
1886 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001887static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001888 loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889{
1890 int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
1891 int oob, numpages, autoplace = 0, startpage;
1892 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001893 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001894 uint8_t *oobbuf, *bufstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 /* Preset written len for early exit */
1897 *retlen = 0;
1898
1899 /* Calculate total length of data */
1900 total_len = 0;
1901 for (i = 0; i < count; i++)
David Woodhousee0c7d762006-05-13 18:07:53 +01001902 total_len += (int)vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
David Woodhousee0c7d762006-05-13 18:07:53 +01001904 DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 /* Do not allow write past end of page */
1907 if ((to + total_len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001908 DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 return -EINVAL;
1910 }
1911
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001912 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001913 if (NOTALIGNED(to) || NOTALIGNED(total_len)) {
1914 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 return -EINVAL;
1916 }
1917
1918 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001919 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921 /* Get the current chip-nr */
David Woodhousee0c7d762006-05-13 18:07:53 +01001922 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 /* Select the NAND device */
1924 this->select_chip(mtd, chipnr);
1925
1926 /* Check, if it is write protected */
1927 if (nand_check_wp(mtd))
1928 goto out;
1929
1930 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001931 if (oobsel == NULL)
1932 oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
1934 /* Autoplace of oob data ? Use the default placement scheme */
1935 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1936 oobsel = this->autooob;
1937 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001938 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001939 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1940 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
1942 /* Setup start page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001943 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001945 if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 this->pagebuf = -1;
1947
1948 startpage = page & this->pagemask;
1949
1950 /* Loop until all kvec' data has been written */
1951 len = 0;
1952 while (count) {
1953 /* If the given tuple is >= pagesize then
1954 * write it out from the iov
1955 */
1956 if ((vecs->iov_len - len) >= mtd->oobblock) {
1957 /* Calc number of pages we can write
1958 * out of this iov in one go */
1959 numpages = (vecs->iov_len - len) >> this->page_shift;
1960 /* Do not cross block boundaries */
David Woodhousee0c7d762006-05-13 18:07:53 +01001961 numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
1962 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001963 bufstart = (uint8_t *) vecs->iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 bufstart += len;
1965 this->data_poi = bufstart;
1966 oob = 0;
1967 for (i = 1; i <= numpages; i++) {
1968 /* Write one page. If this is the last page to write
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001969 * then use the real pageprogram command, else select
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 * cached programming if supported by the chip.
1971 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001972 ret = nand_write_page(mtd, this, page & this->pagemask,
1973 &oobbuf[oob], oobsel, i != numpages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (ret)
1975 goto out;
1976 this->data_poi += mtd->oobblock;
1977 len += mtd->oobblock;
1978 oob += mtd->oobsize;
1979 page++;
1980 }
1981 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001982 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 vecs++;
1984 len = 0;
1985 count--;
1986 }
1987 } else {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001988 /* We must use the internal buffer, read data out of each
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 * tuple until we have a full page to write
1990 */
1991 int cnt = 0;
1992 while (cnt < mtd->oobblock) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001993 if (vecs->iov_base != NULL && vecs->iov_len)
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001994 this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001996 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 vecs++;
1998 len = 0;
1999 count--;
2000 }
2001 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002002 this->pagebuf = page;
2003 this->data_poi = this->data_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 bufstart = this->data_poi;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002005 numpages = 1;
David Woodhousee0c7d762006-05-13 18:07:53 +01002006 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
2007 ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (ret)
2009 goto out;
2010 page++;
2011 }
2012
2013 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01002014 ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 if (ret)
2016 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002017
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 written += mtd->oobblock * numpages;
2019 /* All done ? */
2020 if (!count)
2021 break;
2022
2023 startpage = page & this->pagemask;
2024 /* Check, if we cross a chip boundary */
2025 if (!startpage) {
2026 chipnr++;
2027 this->select_chip(mtd, -1);
2028 this->select_chip(mtd, chipnr);
2029 }
2030 }
2031 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002032 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 /* Deselect and wake up anyone waiting on the device */
2034 nand_release_device(mtd);
2035
2036 *retlen = written;
2037 return ret;
2038}
2039
2040/**
2041 * single_erease_cmd - [GENERIC] NAND standard block erase command function
2042 * @mtd: MTD device structure
2043 * @page: the page address of the block which will be erased
2044 *
2045 * Standard erase command for NAND chips
2046 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002047static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
2049 struct nand_chip *this = mtd->priv;
2050 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002051 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2052 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053}
2054
2055/**
2056 * multi_erease_cmd - [GENERIC] AND specific block erase command function
2057 * @mtd: MTD device structure
2058 * @page: the page address of the block which will be erased
2059 *
2060 * AND multi block erase command function
2061 * Erase 4 consecutive blocks
2062 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002063static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
2065 struct nand_chip *this = mtd->priv;
2066 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002067 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2068 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2069 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2070 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2071 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072}
2073
2074/**
2075 * nand_erase - [MTD Interface] erase block(s)
2076 * @mtd: MTD device structure
2077 * @instr: erase instruction
2078 *
2079 * Erase one ore more blocks
2080 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002081static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
David Woodhousee0c7d762006-05-13 18:07:53 +01002083 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002085
David A. Marlin30f464b2005-01-17 18:35:25 +00002086#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087/**
2088 * nand_erase_intern - [NAND Interface] erase block(s)
2089 * @mtd: MTD device structure
2090 * @instr: erase instruction
2091 * @allowbbt: allow erasing the bbt area
2092 *
2093 * Erase one ore more blocks
2094 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002095int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096{
2097 int page, len, status, pages_per_block, ret, chipnr;
2098 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00002099 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
2100 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
2101 /* It is used to see if the current page is in the same */
2102 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
David Woodhousee0c7d762006-05-13 18:07:53 +01002104 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 -07002105
2106 /* Start address must align on block boundary */
2107 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002108 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 return -EINVAL;
2110 }
2111
2112 /* Length must align on block boundary */
2113 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002114 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 return -EINVAL;
2116 }
2117
2118 /* Do not allow erase past end of device */
2119 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002120 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 return -EINVAL;
2122 }
2123
2124 instr->fail_addr = 0xffffffff;
2125
2126 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002127 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
2129 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01002130 page = (int)(instr->addr >> this->page_shift);
2131 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
2133 /* Calculate pages in each block */
2134 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
2135
2136 /* Select the NAND device */
2137 this->select_chip(mtd, chipnr);
2138
2139 /* Check the WP bit */
2140 /* Check, if it is write protected */
2141 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002142 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 instr->state = MTD_ERASE_FAILED;
2144 goto erase_exit;
2145 }
2146
David A. Marlin30f464b2005-01-17 18:35:25 +00002147 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
2148 if (this->options & BBT_AUTO_REFRESH) {
2149 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2150 } else {
2151 bbt_masked_page = 0xffffffff; /* should not match anything */
2152 }
2153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 /* Loop through the pages */
2155 len = instr->len;
2156
2157 instr->state = MTD_ERASING;
2158
2159 while (len) {
2160 /* Check if we have a bad block, we do not erase bad blocks ! */
2161 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002162 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 instr->state = MTD_ERASE_FAILED;
2164 goto erase_exit;
2165 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002166
2167 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 the current cached page */
2169 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
2170 this->pagebuf = -1;
2171
David Woodhousee0c7d762006-05-13 18:07:53 +01002172 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002173
David Woodhousee0c7d762006-05-13 18:07:53 +01002174 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
David A. Marlin068e3c02005-01-24 03:07:46 +00002176 /* See if operation failed and additional status checks are available */
2177 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2178 status = this->errstat(mtd, this, FL_ERASING, status, page);
2179 }
2180
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00002182 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002183 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 instr->state = MTD_ERASE_FAILED;
2185 instr->fail_addr = (page << this->page_shift);
2186 goto erase_exit;
2187 }
David A. Marlin30f464b2005-01-17 18:35:25 +00002188
2189 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
2190 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002191 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00002192 (page != this->bbt_td->pages[chipnr])) {
2193 rewrite_bbt[chipnr] = (page << this->page_shift);
2194 }
2195 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 /* Increment page address and decrement length */
2198 len -= (1 << this->phys_erase_shift);
2199 page += pages_per_block;
2200
2201 /* Check, if we cross a chip boundary */
2202 if (len && !(page & this->pagemask)) {
2203 chipnr++;
2204 this->select_chip(mtd, -1);
2205 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00002206
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002207 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00002208 * set the BBT page mask to see if this BBT should be rewritten */
2209 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
2210 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2211 }
2212
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 }
2214 }
2215 instr->state = MTD_ERASE_DONE;
2216
David Woodhousee0c7d762006-05-13 18:07:53 +01002217 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
2220 /* Do call back function */
2221 if (!ret)
2222 mtd_erase_callback(instr);
2223
2224 /* Deselect and wake up anyone waiting on the device */
2225 nand_release_device(mtd);
2226
David A. Marlin30f464b2005-01-17 18:35:25 +00002227 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
2228 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
2229 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
2230 if (rewrite_bbt[chipnr]) {
2231 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01002232 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2233 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2234 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002235 }
2236 }
2237 }
2238
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 /* Return more or less happy */
2240 return ret;
2241}
2242
2243/**
2244 * nand_sync - [MTD Interface] sync
2245 * @mtd: MTD device structure
2246 *
2247 * Sync is actually a wait for chip ready function
2248 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002249static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250{
2251 struct nand_chip *this = mtd->priv;
2252
David Woodhousee0c7d762006-05-13 18:07:53 +01002253 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002256 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002258 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259}
2260
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261/**
2262 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2263 * @mtd: MTD device structure
2264 * @ofs: offset relative to mtd start
2265 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002266static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267{
2268 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002269 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002271
David Woodhousee0c7d762006-05-13 18:07:53 +01002272 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273}
2274
2275/**
2276 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2277 * @mtd: MTD device structure
2278 * @ofs: offset relative to mtd start
2279 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002280static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281{
2282 struct nand_chip *this = mtd->priv;
2283 int ret;
2284
David Woodhousee0c7d762006-05-13 18:07:53 +01002285 if ((ret = nand_block_isbad(mtd, ofs))) {
2286 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 if (ret > 0)
2288 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002289 return ret;
2290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 return this->block_markbad(mtd, ofs);
2293}
2294
2295/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002296 * nand_suspend - [MTD Interface] Suspend the NAND flash
2297 * @mtd: MTD device structure
2298 */
2299static int nand_suspend(struct mtd_info *mtd)
2300{
2301 struct nand_chip *this = mtd->priv;
2302
David Woodhousee0c7d762006-05-13 18:07:53 +01002303 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002304}
2305
2306/**
2307 * nand_resume - [MTD Interface] Resume the NAND flash
2308 * @mtd: MTD device structure
2309 */
2310static void nand_resume(struct mtd_info *mtd)
2311{
2312 struct nand_chip *this = mtd->priv;
2313
2314 if (this->state == FL_PM_SUSPENDED)
2315 nand_release_device(mtd);
2316 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002317 printk(KERN_ERR "nand_resume() called for a chip which is not "
2318 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002319}
2320
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002321/*
2322 * Free allocated data structures
2323 */
2324static void nand_free_kmem(struct nand_chip *this)
2325{
2326 /* Buffer allocated by nand_scan ? */
2327 if (this->options & NAND_OOBBUF_ALLOC)
2328 kfree(this->oob_buf);
2329 /* Buffer allocated by nand_scan ? */
2330 if (this->options & NAND_DATABUF_ALLOC)
2331 kfree(this->data_buf);
2332 /* Controller allocated by nand_scan ? */
2333 if (this->options & NAND_CONTROLLER_ALLOC)
2334 kfree(this->controller);
2335}
2336
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002337/*
2338 * Allocate buffers and data structures
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002340static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002342 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002344 if (!this->oob_buf) {
2345 len = mtd->oobsize <<
2346 (this->phys_erase_shift - this->page_shift);
2347 this->oob_buf = kmalloc(len, GFP_KERNEL);
2348 if (!this->oob_buf)
2349 goto outerr;
2350 this->options |= NAND_OOBBUF_ALLOC;
David Woodhouse552d9202006-05-14 01:20:46 +01002351 }
2352
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002353 if (!this->data_buf) {
2354 len = mtd->oobblock + mtd->oobsize;
2355 this->data_buf = kmalloc(len, GFP_KERNEL);
2356 if (!this->data_buf)
2357 goto outerr;
2358 this->options |= NAND_DATABUF_ALLOC;
2359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002361 if (!this->controller) {
2362 this->controller = kzalloc(sizeof(struct nand_hw_control),
2363 GFP_KERNEL);
2364 if (!this->controller)
2365 goto outerr;
2366 this->options |= NAND_CONTROLLER_ALLOC;
2367 }
2368 return 0;
2369
2370 outerr:
2371 printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
2372 nand_free_kmem(this);
2373 return -ENOMEM;
2374}
2375
2376/*
2377 * Set default functions
2378 */
2379static void nand_set_defaults(struct nand_chip *this, int busw)
2380{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 /* check for proper chip_delay setup, set 20us if not */
2382 if (!this->chip_delay)
2383 this->chip_delay = 20;
2384
2385 /* check, if a user supplied command function given */
2386 if (this->cmdfunc == NULL)
2387 this->cmdfunc = nand_command;
2388
2389 /* check, if a user supplied wait function given */
2390 if (this->waitfunc == NULL)
2391 this->waitfunc = nand_wait;
2392
2393 if (!this->select_chip)
2394 this->select_chip = nand_select_chip;
2395 if (!this->write_byte)
2396 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
2397 if (!this->read_byte)
2398 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2399 if (!this->write_word)
2400 this->write_word = nand_write_word;
2401 if (!this->read_word)
2402 this->read_word = nand_read_word;
2403 if (!this->block_bad)
2404 this->block_bad = nand_block_bad;
2405 if (!this->block_markbad)
2406 this->block_markbad = nand_default_block_markbad;
2407 if (!this->write_buf)
2408 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2409 if (!this->read_buf)
2410 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2411 if (!this->verify_buf)
2412 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2413 if (!this->scan_bbt)
2414 this->scan_bbt = nand_default_bbt;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002415}
2416
2417/*
2418 * Get the flash and manufacturer id and lookup if the typ is supported
2419 */
2420static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2421 struct nand_chip *this,
2422 int busw, int *maf_id)
2423{
2424 struct nand_flash_dev *type = NULL;
2425 int i, dev_id, maf_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427 /* Select the device */
2428 this->select_chip(mtd, 0);
2429
2430 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002431 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
2433 /* Read manufacturer and device IDs */
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002434 *maf_id = this->read_byte(mtd);
2435 dev_id = this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002437 /* Lookup the flash id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002439 if (dev_id == nand_flash_ids[i].id) {
2440 type = &nand_flash_ids[i];
2441 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
2444
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002445 if (!type)
2446 return ERR_PTR(-ENODEV);
2447
2448 this->chipsize = nand_flash_ids[i].chipsize << 20;
2449
2450 /* Newer devices have all the information in additional id bytes */
2451 if (!nand_flash_ids[i].pagesize) {
2452 int extid;
2453 /* The 3rd id byte contains non relevant data ATM */
2454 extid = this->read_byte(mtd);
2455 /* The 4th id byte is the important one */
2456 extid = this->read_byte(mtd);
2457 /* Calc pagesize */
2458 mtd->oobblock = 1024 << (extid & 0x3);
2459 extid >>= 2;
2460 /* Calc oobsize */
2461 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
2462 extid >>= 2;
2463 /* Calc blocksize. Blocksize is multiples of 64KiB */
2464 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2465 extid >>= 2;
2466 /* Get buswidth information */
2467 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
2468
2469 } else {
2470 /*
2471 * Old devices have this data hardcoded in the device id table
2472 */
2473 mtd->erasesize = nand_flash_ids[i].erasesize;
2474 mtd->oobblock = nand_flash_ids[i].pagesize;
2475 mtd->oobsize = mtd->oobblock / 32;
2476 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2477 }
2478
2479 /* Try to identify manufacturer */
2480 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
2481 if (nand_manuf_ids[maf_idx].id == *maf_id)
2482 break;
2483 }
2484
2485 /*
2486 * Check, if buswidth is correct. Hardware drivers should set
2487 * this correct !
2488 */
2489 if (busw != (this->options & NAND_BUSWIDTH_16)) {
2490 printk(KERN_INFO "NAND device: Manufacturer ID:"
2491 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2492 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2493 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
2494 (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
2495 busw ? 16 : 8);
2496 return ERR_PTR(-EINVAL);
2497 }
2498
2499 /* Calculate the address shift from the page size */
2500 this->page_shift = ffs(mtd->oobblock) - 1;
2501 /* Convert chipsize to number of pages per chip -1. */
2502 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2503
2504 this->bbt_erase_shift = this->phys_erase_shift =
2505 ffs(mtd->erasesize) - 1;
2506 this->chip_shift = ffs(this->chipsize) - 1;
2507
2508 /* Set the bad block position */
2509 this->badblockpos = mtd->oobblock > 512 ?
2510 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2511
2512 /* Get chip options, preserve non chip based options */
2513 this->options &= ~NAND_CHIPOPTIONS_MSK;
2514 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
2515
2516 /*
2517 * Set this as a default. Board drivers can override it, if necessary
2518 */
2519 this->options |= NAND_NO_AUTOINCR;
2520
2521 /* Check if this is a not a samsung device. Do not clear the
2522 * options for chips which are not having an extended id.
2523 */
2524 if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2525 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
2526
2527 /* Check for AND chips with 4 page planes */
2528 if (this->options & NAND_4PAGE_ARRAY)
2529 this->erase_cmd = multi_erase_cmd;
2530 else
2531 this->erase_cmd = single_erase_cmd;
2532
2533 /* Do not replace user supplied command function ! */
2534 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
2535 this->cmdfunc = nand_command_lp;
2536
2537 printk(KERN_INFO "NAND device: Manufacturer ID:"
2538 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2539 nand_manuf_ids[maf_idx].name, type->name);
2540
2541 return type;
2542}
2543
2544/* module_text_address() isn't exported, and it's mostly a pointless
2545 test if this is a module _anyway_ -- they'd have to try _really_ hard
2546 to call us from in-kernel code if the core NAND support is modular. */
2547#ifdef MODULE
2548#define caller_is_module() (1)
2549#else
2550#define caller_is_module() \
2551 module_text_address((unsigned long)__builtin_return_address(0))
2552#endif
2553
2554/**
2555 * nand_scan - [NAND Interface] Scan for the NAND device
2556 * @mtd: MTD device structure
2557 * @maxchips: Number of chips to scan for
2558 *
2559 * This fills out all the uninitialized function pointers
2560 * with the defaults.
2561 * The flash ID is read and the mtd/chip structures are
2562 * filled with the appropriate values. Buffers are allocated if
2563 * they are not provided by the board driver
2564 * The mtd->owner field must be set to the module of the caller
2565 *
2566 */
2567int nand_scan(struct mtd_info *mtd, int maxchips)
2568{
2569 int i, busw, nand_maf_id;
2570 struct nand_chip *this = mtd->priv;
2571 struct nand_flash_dev *type;
2572
2573 /* Many callers got this wrong, so check for it for a while... */
2574 if (!mtd->owner && caller_is_module()) {
2575 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2576 BUG();
2577 }
2578
2579 /* Get buswidth to select the correct functions */
2580 busw = this->options & NAND_BUSWIDTH_16;
2581 /* Set the default functions */
2582 nand_set_defaults(this, busw);
2583
2584 /* Read the flash type */
2585 type = nand_get_flash_type(mtd, this, busw, &nand_maf_id);
2586
2587 if (IS_ERR(type)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002588 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 this->select_chip(mtd, -1);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002590 return PTR_ERR(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
2592
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002593 /* Check for a chip array */
David Woodhousee0c7d762006-05-13 18:07:53 +01002594 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 this->select_chip(mtd, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002597 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* Read manufacturer and device IDs */
2599 if (nand_maf_id != this->read_byte(mtd) ||
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002600 type->id != this->read_byte(mtd))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 break;
2602 }
2603 if (i > 1)
2604 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002605
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 /* Store the number of chips and calc total size for mtd */
2607 this->numchips = i;
2608 mtd->size = i * this->chipsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002610 /* Allocate buffers and data structures */
2611 if (nand_allocate_kmem(mtd, this))
2612 return -ENOMEM;
2613
2614 /* Preset the internal oob buffer */
2615 memset(this->oob_buf, 0xff,
2616 mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2617
2618 /*
2619 * If no default placement scheme is given, select an appropriate one
2620 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 if (!this->autooob) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002622 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 case 8:
2624 this->autooob = &nand_oob_8;
2625 break;
2626 case 16:
2627 this->autooob = &nand_oob_16;
2628 break;
2629 case 64:
2630 this->autooob = &nand_oob_64;
2631 break;
2632 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002633 printk(KERN_WARNING "No oob scheme defined for "
2634 "oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 BUG();
2636 }
2637 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002638
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002639 /*
2640 * The number of bytes available for the filesystem to place fs
2641 * dependend oob data
2642 */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002643 mtd->oobavail = 0;
2644 for (i = 0; this->autooob->oobfree[i][1]; i++)
2645 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002647 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002648 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2649 * selected and we have 256 byte pagesize fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002650 */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002651 switch (this->ecc.mode) {
2652 case NAND_ECC_HW:
2653 case NAND_ECC_HW_SYNDROME:
2654 if (!this->ecc.calculate || !this->ecc.correct ||
2655 !this->ecc.hwctl) {
2656 printk(KERN_WARNING "No ECC functions supplied, "
2657 "Hardware ECC not possible\n");
2658 BUG();
2659 }
2660 if (mtd->oobblock >= this->ecc.size)
2661 break;
2662 printk(KERN_WARNING "%d byte HW ECC not possible on "
2663 "%d byte page size, fallback to SW ECC\n",
2664 this->ecc.size, mtd->oobblock);
2665 this->ecc.mode = NAND_ECC_SOFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002667 case NAND_ECC_SOFT:
2668 this->ecc.calculate = nand_calculate_ecc;
2669 this->ecc.correct = nand_correct_data;
2670 this->ecc.size = 256;
2671 this->ecc.bytes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002673
2674 case NAND_ECC_NONE:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002675 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2676 "This is not recommended !!\n");
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002677 this->ecc.size = mtd->oobblock;
2678 this->ecc.bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002681 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002682 this->ecc.mode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002683 BUG();
2684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002686 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002687 * Set the number of read / write steps for one page depending on ECC
2688 * mode
2689 */
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002690 this->ecc.steps = mtd->oobblock / this->ecc.size;
2691 if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
2692 printk(KERN_WARNING "Invalid ecc parameters\n");
2693 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002695
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* Initialize state, waitqueue and spinlock */
2697 this->state = FL_READY;
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002698 init_waitqueue_head(&this->controller->wq);
2699 spin_lock_init(&this->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 /* De-select the device */
2702 this->select_chip(mtd, -1);
2703
2704 /* Invalidate the pagebuffer reference */
2705 this->pagebuf = -1;
2706
2707 /* Fill in remaining MTD driver data */
2708 mtd->type = MTD_NANDFLASH;
2709 mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
2710 mtd->ecctype = MTD_ECC_SW;
2711 mtd->erase = nand_erase;
2712 mtd->point = NULL;
2713 mtd->unpoint = NULL;
2714 mtd->read = nand_read;
2715 mtd->write = nand_write;
2716 mtd->read_ecc = nand_read_ecc;
2717 mtd->write_ecc = nand_write_ecc;
2718 mtd->read_oob = nand_read_oob;
2719 mtd->write_oob = nand_write_oob;
2720 mtd->readv = NULL;
2721 mtd->writev = nand_writev;
2722 mtd->writev_ecc = nand_writev_ecc;
2723 mtd->sync = nand_sync;
2724 mtd->lock = NULL;
2725 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002726 mtd->suspend = nand_suspend;
2727 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 mtd->block_isbad = nand_block_isbad;
2729 mtd->block_markbad = nand_block_markbad;
2730
2731 /* and make the autooob the default one */
2732 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2733
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002734 /* Check, if we should skip the bad block table scan */
2735 if (this->options & NAND_SKIP_BBTSCAN)
2736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
2738 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002739 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740}
2741
2742/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002743 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 * @mtd: MTD device structure
2745*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002746void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747{
2748 struct nand_chip *this = mtd->priv;
2749
2750#ifdef CONFIG_MTD_PARTITIONS
2751 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002752 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753#endif
2754 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002755 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756
Jesper Juhlfa671642005-11-07 01:01:27 -08002757 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002758 kfree(this->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002759 /* Free buffers */
2760 nand_free_kmem(this);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761}
2762
David Woodhousee0c7d762006-05-13 18:07:53 +01002763EXPORT_SYMBOL_GPL(nand_scan);
2764EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002765
2766static int __init nand_base_init(void)
2767{
2768 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2769 return 0;
2770}
2771
2772static void __exit nand_base_exit(void)
2773{
2774 led_trigger_unregister_simple(nand_led_trigger);
2775}
2776
2777module_init(nand_base_init);
2778module_exit(nand_base_exit);
2779
David Woodhousee0c7d762006-05-13 18:07:53 +01002780MODULE_LICENSE("GPL");
2781MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2782MODULE_DESCRIPTION("Generic NAND flash driver code");