blob: fdaf32083ada3eb53fac0e0f9e43c9ff26d06d54 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/mtd/nand.c
3 *
4 * Overview:
5 * This is the generic MTD driver for NAND flash devices. It should be
6 * capable of working with almost all NAND chips currently available.
7 * Basic support for AG-AND chips is provided.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Additional technical information is available on
10 * http://www.linux-mtd.infradead.org/tech/nand.html
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000011 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
13 * 2002 Thomas Gleixner (tglx@linutronix.de)
14 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000015 * 02-08-2004 tglx: support for strange chips, which cannot auto increment
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * pages on read / read_oob
17 *
18 * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes
19 * pointed this out, as he marked an auto increment capable chip
20 * as NOAUTOINCR in the board driver.
21 * Make reads over block boundaries work too
22 *
23 * 04-14-2004 tglx: first working version for 2k page size chips
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000024 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 * 05-19-2004 tglx: Basic support for Renesas AG-AND chips
26 *
27 * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared
28 * among multiple independend devices. Suggestions and initial patch
29 * from Ben Dooks <ben-mtd@fluff.org>
30 *
David A. Marlin30f464b2005-01-17 18:35:25 +000031 * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
32 * Basically, any block not rewritten may lose data when surrounding blocks
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000033 * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
David A. Marlin30f464b2005-01-17 18:35:25 +000034 * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
35 * do not lose data, force them to be rewritten when some of the surrounding
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000036 * blocks are erased. Rather than tracking a specific nearby block (which
37 * could itself go bad), use a page address 'mask' to select several blocks
David A. Marlin30f464b2005-01-17 18:35:25 +000038 * in the same area, and rewrite the BBT when any of them are erased.
39 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000040 * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
David A. Marlin30f464b2005-01-17 18:35:25 +000041 * AG-AND chips. If there was a sudden loss of power during an erase operation,
42 * a "device recovery" operation must be performed when power is restored
43 * to ensure correct operation.
44 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000045 * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
David A. Marlin068e3c02005-01-24 03:07:46 +000046 * perform extra error status checks on erase and write failures. This required
47 * adding a wrapper function for nand_read_ecc.
48 *
Vitaly Wool962034f2005-09-15 14:58:53 +010049 * 08-20-2005 vwool: suspend/resume added
50 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * Credits:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000052 * David Woodhouse for adding multichip support
53 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
55 * rework for 2K page size chips
56 *
57 * TODO:
58 * Enable cached programming for 2k page size chips
59 * Check, if mtd->ecctype should be set to MTD_ECC_HW
60 * if we have HW ecc support.
61 * The AG-AND chips have nice features for speed improvement,
62 * which are not supported yet. Read / program 4 pages in one go.
63 *
Vitaly Wool962034f2005-09-15 14:58:53 +010064 * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 *
66 * This program is free software; you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License version 2 as
68 * published by the Free Software Foundation.
69 *
70 */
71
72#include <linux/delay.h>
73#include <linux/errno.h>
74#include <linux/sched.h>
75#include <linux/slab.h>
76#include <linux/types.h>
77#include <linux/mtd/mtd.h>
78#include <linux/mtd/nand.h>
79#include <linux/mtd/nand_ecc.h>
80#include <linux/mtd/compatmac.h>
81#include <linux/interrupt.h>
82#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080083#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#include <asm/io.h>
85
86#ifdef CONFIG_MTD_PARTITIONS
87#include <linux/mtd/partitions.h>
88#endif
89
90/* Define default oob placement schemes for large and small page devices */
91static struct nand_oobinfo nand_oob_8 = {
92 .useecc = MTD_NANDECC_AUTOPLACE,
93 .eccbytes = 3,
94 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +010095 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070096};
97
98static struct nand_oobinfo nand_oob_16 = {
99 .useecc = MTD_NANDECC_AUTOPLACE,
100 .eccbytes = 6,
101 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +0100102 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
105static struct nand_oobinfo nand_oob_64 = {
106 .useecc = MTD_NANDECC_AUTOPLACE,
107 .eccbytes = 24,
108 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +0100109 40, 41, 42, 43, 44, 45, 46, 47,
110 48, 49, 50, 51, 52, 53, 54, 55,
111 56, 57, 58, 59, 60, 61, 62, 63},
112 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
115/* This is used for padding purposes in nand_write_oob */
116static u_char ffchars[] = {
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
125};
126
127/*
128 * NAND low-level MTD interface functions
129 */
130static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
131static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
132static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
133
David Woodhousee0c7d762006-05-13 18:07:53 +0100134static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
135static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
136 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
137static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
138static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
139static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
140 size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
141static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
142static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
143static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
144 unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf,
145 struct nand_oobinfo *oobsel);
146static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
147static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149/* Some internal functions */
David Woodhousee0c7d762006-05-13 18:07:53 +0100150static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page, u_char * oob_buf,
151 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
David Woodhousee0c7d762006-05-13 18:07:53 +0100153static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
154 u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155#else
156#define nand_verify_pages(...) (0)
157#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000158
David Woodhousee0c7d762006-05-13 18:07:53 +0100159static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161/**
162 * nand_release_device - [GENERIC] release chip
163 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000164 *
165 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100167static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
169 struct nand_chip *this = mtd->priv;
170
171 /* De-select the NAND device */
172 this->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (this->controller) {
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100175 /* Release the controller and the chip */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 spin_lock(&this->controller->lock);
177 this->controller->active = NULL;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100178 this->state = FL_READY;
179 wake_up(&this->controller->wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 spin_unlock(&this->controller->lock);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100181 } else {
182 /* Release the chip */
183 spin_lock(&this->chip_lock);
184 this->state = FL_READY;
185 wake_up(&this->wq);
186 spin_unlock(&this->chip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
190/**
191 * nand_read_byte - [DEFAULT] read one byte from the chip
192 * @mtd: MTD device structure
193 *
194 * Default read function for 8bit buswith
195 */
196static u_char nand_read_byte(struct mtd_info *mtd)
197{
198 struct nand_chip *this = mtd->priv;
199 return readb(this->IO_ADDR_R);
200}
201
202/**
203 * nand_write_byte - [DEFAULT] write one byte to the chip
204 * @mtd: MTD device structure
205 * @byte: pointer to data byte to write
206 *
207 * Default write function for 8it buswith
208 */
209static void nand_write_byte(struct mtd_info *mtd, u_char byte)
210{
211 struct nand_chip *this = mtd->priv;
212 writeb(byte, this->IO_ADDR_W);
213}
214
215/**
216 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
217 * @mtd: MTD device structure
218 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000219 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 * endianess conversion
221 */
222static u_char nand_read_byte16(struct mtd_info *mtd)
223{
224 struct nand_chip *this = mtd->priv;
225 return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
226}
227
228/**
229 * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
230 * @mtd: MTD device structure
231 * @byte: pointer to data byte to write
232 *
233 * Default write function for 16bit buswith with
234 * endianess conversion
235 */
236static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
237{
238 struct nand_chip *this = mtd->priv;
239 writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
240}
241
242/**
243 * nand_read_word - [DEFAULT] read one word from the chip
244 * @mtd: MTD device structure
245 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000246 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 * endianess conversion
248 */
249static u16 nand_read_word(struct mtd_info *mtd)
250{
251 struct nand_chip *this = mtd->priv;
252 return readw(this->IO_ADDR_R);
253}
254
255/**
256 * nand_write_word - [DEFAULT] write one word to the chip
257 * @mtd: MTD device structure
258 * @word: data word to write
259 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000260 * Default write function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 * endianess conversion
262 */
263static void nand_write_word(struct mtd_info *mtd, u16 word)
264{
265 struct nand_chip *this = mtd->priv;
266 writew(word, this->IO_ADDR_W);
267}
268
269/**
270 * nand_select_chip - [DEFAULT] control CE line
271 * @mtd: MTD device structure
272 * @chip: chipnumber to select, -1 for deselect
273 *
274 * Default select function for 1 chip devices.
275 */
276static void nand_select_chip(struct mtd_info *mtd, int chip)
277{
278 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100279 switch (chip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 case -1:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000281 this->hwcontrol(mtd, NAND_CTL_CLRNCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 break;
283 case 0:
284 this->hwcontrol(mtd, NAND_CTL_SETNCE);
285 break;
286
287 default:
288 BUG();
289 }
290}
291
292/**
293 * nand_write_buf - [DEFAULT] write buffer to chip
294 * @mtd: MTD device structure
295 * @buf: data buffer
296 * @len: number of bytes to write
297 *
298 * Default write function for 8bit buswith
299 */
300static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
301{
302 int i;
303 struct nand_chip *this = mtd->priv;
304
David Woodhousee0c7d762006-05-13 18:07:53 +0100305 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 writeb(buf[i], this->IO_ADDR_W);
307}
308
309/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000310 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 * @mtd: MTD device structure
312 * @buf: buffer to store date
313 * @len: number of bytes to read
314 *
315 * Default read function for 8bit buswith
316 */
317static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
318{
319 int i;
320 struct nand_chip *this = mtd->priv;
321
David Woodhousee0c7d762006-05-13 18:07:53 +0100322 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 buf[i] = readb(this->IO_ADDR_R);
324}
325
326/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000327 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 * @mtd: MTD device structure
329 * @buf: buffer containing the data to compare
330 * @len: number of bytes to compare
331 *
332 * Default verify function for 8bit buswith
333 */
334static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
335{
336 int i;
337 struct nand_chip *this = mtd->priv;
338
David Woodhousee0c7d762006-05-13 18:07:53 +0100339 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 if (buf[i] != readb(this->IO_ADDR_R))
341 return -EFAULT;
342
343 return 0;
344}
345
346/**
347 * nand_write_buf16 - [DEFAULT] write buffer to chip
348 * @mtd: MTD device structure
349 * @buf: data buffer
350 * @len: number of bytes to write
351 *
352 * Default write function for 16bit buswith
353 */
354static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
355{
356 int i;
357 struct nand_chip *this = mtd->priv;
358 u16 *p = (u16 *) buf;
359 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000360
David Woodhousee0c7d762006-05-13 18:07:53 +0100361 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 writew(p[i], this->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
366/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000367 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 * @mtd: MTD device structure
369 * @buf: buffer to store date
370 * @len: number of bytes to read
371 *
372 * Default read function for 16bit buswith
373 */
374static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
375{
376 int i;
377 struct nand_chip *this = mtd->priv;
378 u16 *p = (u16 *) buf;
379 len >>= 1;
380
David Woodhousee0c7d762006-05-13 18:07:53 +0100381 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 p[i] = readw(this->IO_ADDR_R);
383}
384
385/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000386 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 * @mtd: MTD device structure
388 * @buf: buffer containing the data to compare
389 * @len: number of bytes to compare
390 *
391 * Default verify function for 16bit buswith
392 */
393static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
394{
395 int i;
396 struct nand_chip *this = mtd->priv;
397 u16 *p = (u16 *) buf;
398 len >>= 1;
399
David Woodhousee0c7d762006-05-13 18:07:53 +0100400 for (i = 0; i < len; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (p[i] != readw(this->IO_ADDR_R))
402 return -EFAULT;
403
404 return 0;
405}
406
407/**
408 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
409 * @mtd: MTD device structure
410 * @ofs: offset from device start
411 * @getchip: 0, if the chip is already selected
412 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000413 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 */
415static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
416{
417 int page, chipnr, res = 0;
418 struct nand_chip *this = mtd->priv;
419 u16 bad;
420
421 if (getchip) {
422 page = (int)(ofs >> this->page_shift);
423 chipnr = (int)(ofs >> this->chip_shift);
424
425 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +0100426 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 /* Select the NAND device */
429 this->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000430 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100431 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 if (this->options & NAND_BUSWIDTH_16) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100434 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 bad = cpu_to_le16(this->read_word(mtd));
436 if (this->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000437 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 if ((bad & 0xFF) != 0xff)
439 res = 1;
440 } else {
David Woodhousee0c7d762006-05-13 18:07:53 +0100441 this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 if (this->read_byte(mtd) != 0xff)
443 res = 1;
444 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (getchip) {
447 /* Deselect and wake up anyone waiting on the device */
448 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000449 }
450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return res;
452}
453
454/**
455 * nand_default_block_markbad - [DEFAULT] mark a block bad
456 * @mtd: MTD device structure
457 * @ofs: offset from device start
458 *
459 * This is the default implementation, which can be overridden by
460 * a hardware specific driver.
461*/
462static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
463{
464 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100465 u_char buf[2] = { 0, 0 };
466 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /* Get block number */
David Woodhousee0c7d762006-05-13 18:07:53 +0100470 block = ((int)ofs) >> this->bbt_erase_shift;
Artem B. Bityuckiy41ce9212005-02-09 14:50:00 +0000471 if (this->bbt)
472 this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
474 /* Do we have a flash based bad block table ? */
475 if (this->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100476 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* We write two bytes, so we dont have to mess with 16 bit access */
479 ofs += mtd->oobsize + (this->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100480 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000483/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 * nand_check_wp - [GENERIC] check if the chip is write protected
485 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000486 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000488 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100490static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 struct nand_chip *this = mtd->priv;
493 /* Check the WP bit */
David Woodhousee0c7d762006-05-13 18:07:53 +0100494 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000495 return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
498/**
499 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
500 * @mtd: MTD device structure
501 * @ofs: offset from device start
502 * @getchip: 0, if the chip is already selected
503 * @allowbbt: 1, if its allowed to access the bbt area
504 *
505 * Check, if the block is bad. Either by reading the bad block table or
506 * calling of the scan function.
507 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100508static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!this->bbt)
513 return this->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100516 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
Richard Purdie8fe833c2006-03-31 02:31:14 -0800519DEFINE_LED_TRIGGER(nand_led_trigger);
520
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000521/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000522 * Wait for the ready pin, after a command
523 * The timeout is catched later.
524 */
525static void nand_wait_ready(struct mtd_info *mtd)
526{
527 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100528 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000529
Richard Purdie8fe833c2006-03-31 02:31:14 -0800530 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000531 /* wait until command is processed or timeout occures */
532 do {
533 if (this->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800534 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700535 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000536 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800537 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000538}
539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540/**
541 * nand_command - [DEFAULT] Send command to NAND device
542 * @mtd: MTD device structure
543 * @command: the command to be sent
544 * @column: the column address for this command, -1 if none
545 * @page_addr: the page address for this command, -1 if none
546 *
547 * Send command to NAND device. This function is used for small page
548 * devices (256/512 Bytes per page)
549 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100550static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 register struct nand_chip *this = mtd->priv;
553
554 /* Begin command latch cycle */
555 this->hwcontrol(mtd, NAND_CTL_SETCLE);
556 /*
557 * Write out the command to the device.
558 */
559 if (command == NAND_CMD_SEQIN) {
560 int readcmd;
561
562 if (column >= mtd->oobblock) {
563 /* OOB area */
564 column -= mtd->oobblock;
565 readcmd = NAND_CMD_READOOB;
566 } else if (column < 256) {
567 /* First 256 bytes --> READ0 */
568 readcmd = NAND_CMD_READ0;
569 } else {
570 column -= 256;
571 readcmd = NAND_CMD_READ1;
572 }
573 this->write_byte(mtd, readcmd);
574 }
575 this->write_byte(mtd, command);
576
577 /* Set ALE and clear CLE to start address cycle */
578 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
579
580 if (column != -1 || page_addr != -1) {
581 this->hwcontrol(mtd, NAND_CTL_SETALE);
582
583 /* Serially input address */
584 if (column != -1) {
585 /* Adjust columns for 16 bit buswidth */
586 if (this->options & NAND_BUSWIDTH_16)
587 column >>= 1;
588 this->write_byte(mtd, column);
589 }
590 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100591 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
592 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 /* One more address cycle for devices > 32MiB */
594 if (this->chipsize > (32 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100595 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
597 /* Latch in address */
598 this->hwcontrol(mtd, NAND_CTL_CLRALE);
599 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000600
601 /*
602 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100604 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 case NAND_CMD_PAGEPROG:
608 case NAND_CMD_ERASE1:
609 case NAND_CMD_ERASE2:
610 case NAND_CMD_SEQIN:
611 case NAND_CMD_STATUS:
612 return;
613
614 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000615 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 break;
617 udelay(this->chip_delay);
618 this->hwcontrol(mtd, NAND_CTL_SETCLE);
619 this->write_byte(mtd, NAND_CMD_STATUS);
620 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100621 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return;
623
David Woodhousee0c7d762006-05-13 18:07:53 +0100624 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000626 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 * If we don't have access to the busy pin, we apply the given
628 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100629 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100631 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 /* Apply this short delay always to ensure that we do wait tWB in
636 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100637 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000638
639 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642/**
643 * nand_command_lp - [DEFAULT] Send command to NAND large page device
644 * @mtd: MTD device structure
645 * @command: the command to be sent
646 * @column: the column address for this command, -1 if none
647 * @page_addr: the page address for this command, -1 if none
648 *
649 * Send command to NAND device. This is the version for the new large page devices
David Woodhousee0c7d762006-05-13 18:07:53 +0100650 * We dont have the separate regions as we have in the small page devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 * We must emulate NAND_CMD_READOOB to keep the code compatible.
652 *
653 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100654static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
656 register struct nand_chip *this = mtd->priv;
657
658 /* Emulate NAND_CMD_READOOB */
659 if (command == NAND_CMD_READOOB) {
660 column += mtd->oobblock;
661 command = NAND_CMD_READ0;
662 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 /* Begin command latch cycle */
665 this->hwcontrol(mtd, NAND_CTL_SETCLE);
666 /* Write out the command to the device. */
David A. Marlin30f464b2005-01-17 18:35:25 +0000667 this->write_byte(mtd, (command & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 /* End command latch cycle */
669 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
670
671 if (column != -1 || page_addr != -1) {
672 this->hwcontrol(mtd, NAND_CTL_SETALE);
673
674 /* Serially input address */
675 if (column != -1) {
676 /* Adjust columns for 16 bit buswidth */
677 if (this->options & NAND_BUSWIDTH_16)
678 column >>= 1;
679 this->write_byte(mtd, column & 0xff);
680 this->write_byte(mtd, column >> 8);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (page_addr != -1) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100683 this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
684 this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /* One more address cycle for devices > 128MiB */
686 if (this->chipsize > (128 << 20))
David Woodhousee0c7d762006-05-13 18:07:53 +0100687 this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
689 /* Latch in address */
690 this->hwcontrol(mtd, NAND_CTL_CLRALE);
691 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000692
693 /*
694 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000695 * status, sequential in, and deplete1 need no delay
696 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 case NAND_CMD_CACHEDPROG:
700 case NAND_CMD_PAGEPROG:
701 case NAND_CMD_ERASE1:
702 case NAND_CMD_ERASE2:
703 case NAND_CMD_SEQIN:
704 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000705 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
David Woodhousee0c7d762006-05-13 18:07:53 +0100708 /*
709 * read error status commands require only a short delay
710 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000711 case NAND_CMD_STATUS_ERROR:
712 case NAND_CMD_STATUS_ERROR0:
713 case NAND_CMD_STATUS_ERROR1:
714 case NAND_CMD_STATUS_ERROR2:
715 case NAND_CMD_STATUS_ERROR3:
716 udelay(this->chip_delay);
717 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 case NAND_CMD_RESET:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000720 if (this->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 break;
722 udelay(this->chip_delay);
723 this->hwcontrol(mtd, NAND_CTL_SETCLE);
724 this->write_byte(mtd, NAND_CMD_STATUS);
725 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
David Woodhousee0c7d762006-05-13 18:07:53 +0100726 while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return;
728
729 case NAND_CMD_READ0:
730 /* Begin command latch cycle */
731 this->hwcontrol(mtd, NAND_CTL_SETCLE);
732 /* Write out the start read command */
733 this->write_byte(mtd, NAND_CMD_READSTART);
734 /* End command latch cycle */
735 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
736 /* Fall through into ready check */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000737
David Woodhousee0c7d762006-05-13 18:07:53 +0100738 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000740 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 * If we don't have access to the busy pin, we apply the given
742 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100743 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (!this->dev_ready) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100745 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* Apply this short delay always to ensure that we do wait tWB in
751 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100752 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000753
754 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755}
756
757/**
758 * nand_get_device - [GENERIC] Get chip for selected access
759 * @this: the nand chip descriptor
760 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000761 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 *
763 * Get the device and lock it for exclusive access
764 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100765static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100767 struct nand_chip *active;
768 spinlock_t *lock;
769 wait_queue_head_t *wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100770 DECLARE_WAITQUEUE(wait, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100772 lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
773 wq = (this->controller) ? &this->controller->wq : &this->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100774 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100775 active = this;
776 spin_lock(lock);
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 /* Hardware controller shared among independend devices */
779 if (this->controller) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (this->controller->active)
781 active = this->controller->active;
782 else
783 this->controller->active = this;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100785 if (active == this && this->state == FL_READY) {
786 this->state = new_state;
787 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100788 return 0;
789 }
790 if (new_state == FL_PM_SUSPENDED) {
791 spin_unlock(lock);
792 return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100793 }
794 set_current_state(TASK_UNINTERRUPTIBLE);
795 add_wait_queue(wq, &wait);
796 spin_unlock(lock);
797 schedule();
798 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 goto retry;
800}
801
802/**
803 * nand_wait - [DEFAULT] wait until the command is done
804 * @mtd: MTD device structure
805 * @this: NAND chip structure
806 * @state: state to select the max. timeout value
807 *
808 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000809 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 * general NAND and SmartMedia specs
811 *
812*/
813static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
814{
815
David Woodhousee0c7d762006-05-13 18:07:53 +0100816 unsigned long timeo = jiffies;
817 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100820 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100822 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Richard Purdie8fe833c2006-03-31 02:31:14 -0800824 led_trigger_event(nand_led_trigger, LED_FULL);
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 /* Apply this short delay always to ensure that we do wait tWB in
827 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100828 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
David Woodhousee0c7d762006-05-13 18:07:53 +0100831 this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000832 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100833 this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000835 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 /* Check, if we were interrupted */
837 if (this->state != state)
838 return 0;
839
840 if (this->dev_ready) {
841 if (this->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000842 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 } else {
844 if (this->read_byte(mtd) & NAND_STATUS_READY)
845 break;
846 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000847 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800849 led_trigger_event(nand_led_trigger, LED_OFF);
850
David Woodhousee0c7d762006-05-13 18:07:53 +0100851 status = (int)this->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 return status;
853}
854
855/**
856 * nand_write_page - [GENERIC] write one page
857 * @mtd: MTD device structure
858 * @this: NAND chip structure
859 * @page: startpage inside the chip, must be called with (page & this->pagemask)
860 * @oob_buf: out of band data buffer
861 * @oobsel: out of band selecttion structre
862 * @cached: 1 = enable cached programming if supported by chip
863 *
864 * Nand_page_program function is used for write and writev !
865 * This function will always program a full page of data
866 * If you call it with a non page aligned buffer, you're lost :)
867 *
868 * Cached programming is not supported yet.
869 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100870static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
871 u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
David Woodhousee0c7d762006-05-13 18:07:53 +0100873 int i, status;
874 u_char ecc_code[32];
875 int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
876 int *oob_config = oobsel->eccpos;
877 int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
878 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* FIXME: Enable cached programming */
881 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /* Send command to begin auto page programming */
David Woodhousee0c7d762006-05-13 18:07:53 +0100884 this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 /* Write out complete page of data, take care of eccmode */
887 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100888 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100890 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 this->write_buf(mtd, this->data_poi, mtd->oobblock);
892 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000893
David Woodhousee0c7d762006-05-13 18:07:53 +0100894 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 case NAND_ECC_SOFT:
896 for (; eccsteps; eccsteps--) {
897 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
898 for (i = 0; i < 3; i++, eccidx++)
899 oob_buf[oob_config[eccidx]] = ecc_code[i];
900 datidx += this->eccsize;
901 }
902 this->write_buf(mtd, this->data_poi, mtd->oobblock);
903 break;
904 default:
905 eccbytes = this->eccbytes;
906 for (; eccsteps; eccsteps--) {
907 /* enable hardware ecc logic for write */
908 this->enable_hwecc(mtd, NAND_ECC_WRITE);
909 this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
910 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
911 for (i = 0; i < eccbytes; i++, eccidx++)
912 oob_buf[oob_config[eccidx]] = ecc_code[i];
913 /* If the hardware ecc provides syndromes then
914 * the ecc code must be written immidiately after
915 * the data bytes (words) */
916 if (this->options & NAND_HWECC_SYNDROME)
917 this->write_buf(mtd, ecc_code, eccbytes);
918 datidx += this->eccsize;
919 }
920 break;
921 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 /* Write out OOB data */
924 if (this->options & NAND_HWECC_SYNDROME)
925 this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000926 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 this->write_buf(mtd, oob_buf, mtd->oobsize);
928
929 /* Send command to actually program the data */
David Woodhousee0c7d762006-05-13 18:07:53 +0100930 this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 if (!cached) {
933 /* call wait ready function */
David Woodhousee0c7d762006-05-13 18:07:53 +0100934 status = this->waitfunc(mtd, this, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000935
936 /* See if operation failed and additional status checks are available */
937 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
938 status = this->errstat(mtd, this, FL_WRITING, status, page);
939 }
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000942 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100943 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 return -EIO;
945 }
946 } else {
947 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100948 /* wait until cache is ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
950 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000951 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
954#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
955/**
956 * nand_verify_pages - [GENERIC] verify the chip contents after a write
957 * @mtd: MTD device structure
958 * @this: NAND chip structure
959 * @page: startpage inside the chip, must be called with (page & this->pagemask)
960 * @numpages: number of pages to verify
961 * @oob_buf: out of band data buffer
962 * @oobsel: out of band selecttion structre
963 * @chipnr: number of the current chip
964 * @oobmode: 1 = full buffer verify, 0 = ecc only
965 *
966 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000967 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000969 * byte by byte basis. It is possible that the page was not completely erased
970 * or the page is becoming unusable due to wear. The read with ECC would catch
971 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 * it early in the page write stage. Better to write no data than invalid data.
973 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100974static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
975 u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
David Woodhousee0c7d762006-05-13 18:07:53 +0100977 int i, j, datidx = 0, oobofs = 0, res = -EIO;
978 int eccsteps = this->eccsteps;
979 int hweccbytes;
980 u_char oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
983
984 /* Send command to read back the first page */
David Woodhousee0c7d762006-05-13 18:07:53 +0100985 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
David Woodhousee0c7d762006-05-13 18:07:53 +0100987 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 for (j = 0; j < eccsteps; j++) {
989 /* Loop through and verify the data */
990 if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100991 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 goto out;
993 }
994 datidx += mtd->eccsize;
995 /* Have we a hw generator layout ? */
996 if (!hweccbytes)
997 continue;
998 if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100999 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 goto out;
1001 }
1002 oobofs += hweccbytes;
1003 }
1004
1005 /* check, if we must compare all data or if we just have to
1006 * compare the ecc bytes
1007 */
1008 if (oobmode) {
1009 if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001010 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 goto out;
1012 }
1013 } else {
1014 /* Read always, else autoincrement fails */
1015 this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
1016
1017 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
1018 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 for (i = 0; i < ecccnt; i++) {
1021 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +01001022 if (oobdata[idx] != oob_buf[oobofs + idx]) {
1023 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
1024 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 goto out;
1026 }
1027 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
1030 oobofs += mtd->oobsize - hweccbytes * eccsteps;
1031 page++;
1032 numpages--;
1033
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001034 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 * Do this before the AUTOINCR check, so no problems
1036 * arise if a chip which does auto increment
1037 * is marked as NOAUTOINCR by the board driver.
1038 * Do this also before returning, so the chip is
1039 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +01001040 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001041 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001042 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001044 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 /* All done, return happy */
1047 if (!numpages)
1048 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001049
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001050 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (!NAND_CANAUTOINCR(this))
David Woodhousee0c7d762006-05-13 18:07:53 +01001052 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001054 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 * Terminate the read command. We come here in case of an error
1056 * So we must issue a reset command.
1057 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001058 out:
1059 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return res;
1061}
1062#endif
1063
1064/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001065 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 * @mtd: MTD device structure
1067 * @from: offset to read from
1068 * @len: number of bytes to read
1069 * @retlen: pointer to variable to store the number of read bytes
1070 * @buf: the databuffer to put data
1071 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001072 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1073 * and flags = 0xff
1074 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001075static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
David Woodhousee0c7d762006-05-13 18:07:53 +01001077 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001078}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080/**
David A. Marlin068e3c02005-01-24 03:07:46 +00001081 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 * @mtd: MTD device structure
1083 * @from: offset to read from
1084 * @len: number of bytes to read
1085 * @retlen: pointer to variable to store the number of read bytes
1086 * @buf: the databuffer to put data
1087 * @oob_buf: filesystem supplied oob data buffer
1088 * @oobsel: oob selection structure
1089 *
David A. Marlin068e3c02005-01-24 03:07:46 +00001090 * This function simply calls nand_do_read_ecc with flags = 0xff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001092static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1093 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001095 /* use userspace supplied oobinfo, if zero */
1096 if (oobsel == NULL)
1097 oobsel = &mtd->oobinfo;
David A. Marlin068e3c02005-01-24 03:07:46 +00001098 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1099}
1100
David A. Marlin068e3c02005-01-24 03:07:46 +00001101/**
1102 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1103 * @mtd: MTD device structure
1104 * @from: offset to read from
1105 * @len: number of bytes to read
1106 * @retlen: pointer to variable to store the number of read bytes
1107 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001108 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001109 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001110 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1111 * and how many corrected error bits are acceptable:
1112 * bits 0..7 - number of tolerable errors
1113 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1114 *
1115 * NAND read with ECC
1116 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001117int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1118 size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001119{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1122 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1123 struct nand_chip *this = mtd->priv;
1124 u_char *data_poi, *oob_data = oob_buf;
Jarkko Lavinen0a18cde2005-04-11 15:16:11 +01001125 u_char ecc_calc[32];
1126 u_char ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001127 int eccmode, eccsteps;
1128 int *oob_config, datidx;
1129 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
1130 int eccbytes;
1131 int compareecc = 1;
1132 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
David Woodhousee0c7d762006-05-13 18:07:53 +01001134 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 -07001135
1136 /* Do not allow reads past end of device */
1137 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001138 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 *retlen = 0;
1140 return -EINVAL;
1141 }
1142
1143 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001144 if (flags & NAND_GET_DEVICE)
David Woodhousee0c7d762006-05-13 18:07:53 +01001145 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 /* Autoplace of oob data ? Use the default placement scheme */
1148 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1149 oobsel = this->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
1152 oob_config = oobsel->eccpos;
1153
1154 /* Select the NAND device */
1155 chipnr = (int)(from >> this->chip_shift);
1156 this->select_chip(mtd, chipnr);
1157
1158 /* First we calculate the starting page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001159 realpage = (int)(from >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 page = realpage & this->pagemask;
1161
1162 /* Get raw starting column */
1163 col = from & (mtd->oobblock - 1);
1164
1165 end = mtd->oobblock;
1166 ecc = this->eccsize;
1167 eccbytes = this->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1170 compareecc = 0;
1171
1172 oobreadlen = mtd->oobsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001173 if (this->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 oobreadlen -= oobsel->eccbytes;
1175
1176 /* Loop until all data read */
1177 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001180 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 * If the read is not page aligned, we have to read into data buffer
1182 * due to ecc, else we read into return buffer direct
1183 */
1184 if (aligned)
1185 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001186 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 data_poi = this->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001188
1189 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 *
1191 * FIXME: Make it work when we must provide oob data too,
1192 * check the usage of data_buf oob field
1193 */
1194 if (realpage == this->pagebuf && !oob_buf) {
1195 /* aligned read ? */
1196 if (aligned)
David Woodhousee0c7d762006-05-13 18:07:53 +01001197 memcpy(data_poi, this->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 goto readdata;
1199 }
1200
1201 /* Check, if we must send the read command */
1202 if (sndcmd) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001203 this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001208 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1209 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 oob_data = &this->data_buf[end];
1211
1212 eccsteps = this->eccsteps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001215 case NAND_ECC_NONE:{
1216 /* No ECC, Read in a page */
1217 static unsigned long lastwhinge = 0;
1218 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1219 printk(KERN_WARNING
1220 "Reading data from NAND FLASH without ECC is not recommended\n");
1221 lastwhinge = jiffies;
1222 }
1223 this->read_buf(mtd, data_poi, end);
1224 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1228 this->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001229 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001231 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001234 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 this->enable_hwecc(mtd, NAND_ECC_READ);
1236 this->read_buf(mtd, &data_poi[datidx], ecc);
1237
1238 /* HW ecc with syndrome calculation must read the
1239 * syndrome from flash immidiately after the data */
1240 if (!compareecc) {
1241 /* Some hw ecc generators need to know when the
1242 * syndrome is read from flash */
1243 this->enable_hwecc(mtd, NAND_ECC_READSYN);
1244 this->read_buf(mtd, &oob_data[i], eccbytes);
1245 /* We calc error correction directly, it checks the hw
1246 * generator for an error, reads back the syndrome and
1247 * does the error correction on the fly */
David A. Marlin068e3c02005-01-24 03:07:46 +00001248 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1249 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001250 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1251 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 ecc_failed++;
1253 }
1254 } else {
1255 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001258 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260
1261 /* read oobdata */
1262 this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1263
1264 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1265 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001266 goto readoob;
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 /* Pick the ECC bytes out of the oob data */
1269 for (j = 0; j < oobsel->eccbytes; j++)
1270 ecc_code[j] = oob_data[oob_config[j]];
1271
David Woodhousee0c7d762006-05-13 18:07:53 +01001272 /* correct data, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
1274 ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* Get next chunk of ecc bytes */
1277 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001278
1279 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 * This is the legacy mode. Used by YAFFS1
1281 * Should go away some day
1282 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001283 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 int *p = (int *)(&oob_data[mtd->oobsize]);
1285 p[i] = ecc_status;
1286 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001287
1288 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001289 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 ecc_failed++;
1291 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
David Woodhousee0c7d762006-05-13 18:07:53 +01001294 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 /* check, if we have a fs supplied oob-buffer */
1296 if (oob_buf) {
1297 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001298 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001300 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001302 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 int from = oobsel->oobfree[i][0];
1304 int num = oobsel->oobfree[i][1];
1305 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001306 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 break;
1309 case MTD_NANDECC_PLACE:
1310 /* YAFFS1 legacy mode */
David Woodhousee0c7d762006-05-13 18:07:53 +01001311 oob_data += this->eccsteps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 default:
1313 oob_data += mtd->oobsize;
1314 }
1315 }
1316 readdata:
1317 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001318 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 for (j = col; j < end && read < len; j++)
1320 buf[read++] = data_poi[j];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001321 this->pagebuf = realpage;
1322 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 read += mtd->oobblock;
1324
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001325 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 * Do this before the AUTOINCR check, so no problems
1327 * arise if a chip which does auto increment
1328 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001329 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001330 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001331 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001333 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001336 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 /* For subsequent reads align to page boundary. */
1339 col = 0;
1340 /* Increment page address */
1341 realpage++;
1342
1343 page = realpage & this->pagemask;
1344 /* Check, if we cross a chip boundary */
1345 if (!page) {
1346 chipnr++;
1347 this->select_chip(mtd, -1);
1348 this->select_chip(mtd, chipnr);
1349 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001350 /* Check, if the chip supports auto page increment
1351 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001352 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001354 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
1356
1357 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001358 if (flags & NAND_GET_DEVICE)
1359 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 /*
1362 * Return success, if no ECC failures, else -EBADMSG
1363 * fs driver will take care of that, because
1364 * retlen == desired len and result == -EBADMSG
1365 */
1366 *retlen = read;
1367 return ecc_failed ? -EBADMSG : 0;
1368}
1369
1370/**
1371 * nand_read_oob - [MTD Interface] NAND read out-of-band
1372 * @mtd: MTD device structure
1373 * @from: offset to read from
1374 * @len: number of bytes to read
1375 * @retlen: pointer to variable to store the number of read bytes
1376 * @buf: the databuffer to put data
1377 *
1378 * NAND read out-of-band data from the spare area
1379 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001380static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 int i, col, page, chipnr;
1383 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001384 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
David Woodhousee0c7d762006-05-13 18:07:53 +01001386 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 -07001387
1388 /* Shift to get page */
1389 page = (int)(from >> this->page_shift);
1390 chipnr = (int)(from >> this->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 /* Mask to get column */
1393 col = from & (mtd->oobsize - 1);
1394
1395 /* Initialize return length value */
1396 *retlen = 0;
1397
1398 /* Do not allow reads past end of device */
1399 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001400 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 *retlen = 0;
1402 return -EINVAL;
1403 }
1404
1405 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001406 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 /* Select the NAND device */
1409 this->select_chip(mtd, chipnr);
1410
1411 /* Send the read command */
David Woodhousee0c7d762006-05-13 18:07:53 +01001412 this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001413 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 * Read the data, if we read more than one page
1415 * oob data, let the device transfer the data !
1416 */
1417 i = 0;
1418 while (i < len) {
1419 int thislen = mtd->oobsize - col;
1420 thislen = min_t(int, thislen, len);
1421 this->read_buf(mtd, &buf[i], thislen);
1422 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
1424 /* Read more ? */
1425 if (i < len) {
1426 page++;
1427 col = 0;
1428
1429 /* Check, if we cross a chip boundary */
1430 if (!(page & this->pagemask)) {
1431 chipnr++;
1432 this->select_chip(mtd, -1);
1433 this->select_chip(mtd, chipnr);
1434 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001435
1436 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001437 * Do this before the AUTOINCR check, so no problems
1438 * arise if a chip which does auto increment
1439 * is marked as NOAUTOINCR by the board driver.
1440 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001441 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001442 udelay(this->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001443 else
1444 nand_wait_ready(mtd);
1445
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001446 /* Check, if the chip supports auto page increment
1447 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001448 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
1450 /* For subsequent page reads set offset to 0 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001451 this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 }
1453 }
1454 }
1455
1456 /* Deselect and wake up anyone waiting on the device */
1457 nand_release_device(mtd);
1458
1459 /* Return happy */
1460 *retlen = len;
1461 return 0;
1462}
1463
1464/**
1465 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1466 * @mtd: MTD device structure
1467 * @buf: temporary buffer
1468 * @from: offset to read from
1469 * @len: number of bytes to read
1470 * @ooblen: number of oob data bytes to read
1471 *
1472 * Read raw data including oob into buffer
1473 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001474int 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 -07001475{
1476 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001477 int page = (int)(from >> this->page_shift);
1478 int chip = (int)(from >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 int sndcmd = 1;
1480 int cnt = 0;
1481 int pagesize = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001482 int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 /* Do not allow reads past end of device */
1485 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001486 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 return -EINVAL;
1488 }
1489
1490 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001491 nand_get_device(this, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
David Woodhousee0c7d762006-05-13 18:07:53 +01001493 this->select_chip(mtd, chip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 /* Add requested oob length */
1496 len += ooblen;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 while (len) {
1499 if (sndcmd)
David Woodhousee0c7d762006-05-13 18:07:53 +01001500 this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001501 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
David Woodhousee0c7d762006-05-13 18:07:53 +01001503 this->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 len -= pagesize;
1506 cnt += pagesize;
1507 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001508
1509 if (!this->dev_ready)
David Woodhousee0c7d762006-05-13 18:07:53 +01001510 udelay(this->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001512 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001513
1514 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
1516 sndcmd = 1;
1517 }
1518
1519 /* Deselect and wake up anyone waiting on the device */
1520 nand_release_device(mtd);
1521 return 0;
1522}
1523
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001524/**
1525 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 * @mtd: MTD device structure
1527 * @fsbuf: buffer given by fs driver
1528 * @oobsel: out of band selection structre
1529 * @autoplace: 1 = place given buffer into the oob bytes
1530 * @numpages: number of pages to prepare
1531 *
1532 * Return:
1533 * 1. Filesystem buffer available and autoplacement is off,
1534 * return filesystem buffer
1535 * 2. No filesystem buffer or autoplace is off, return internal
1536 * buffer
1537 * 3. Filesystem buffer is given and autoplace selected
1538 * put data from fs buffer into internal buffer and
1539 * retrun internal buffer
1540 *
1541 * Note: The internal buffer is filled with 0xff. This must
1542 * be done only once, when no autoplacement happens
1543 * Autoplacement sets the buffer dirty flag, which
1544 * forces the 0xff fill before using the buffer again.
1545 *
1546*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001547static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
1548 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
1550 struct nand_chip *this = mtd->priv;
1551 int i, len, ofs;
1552
1553 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001554 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return fsbuf;
1556
1557 /* Check, if the buffer must be filled with ff again */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001558 if (this->oobdirty) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001559 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 this->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001561 }
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 /* If we have no autoplacement or no fs buffer use the internal one */
1564 if (!autoplace || !fsbuf)
1565 return this->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* Walk through the pages and place the data */
1568 this->oobdirty = 1;
1569 ofs = 0;
1570 while (numpages--) {
1571 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1572 int to = ofs + oobsel->oobfree[i][0];
1573 int num = oobsel->oobfree[i][1];
David Woodhousee0c7d762006-05-13 18:07:53 +01001574 memcpy(&this->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 len += num;
1576 fsbuf += num;
1577 }
1578 ofs += mtd->oobavail;
1579 }
1580 return this->oob_buf;
1581}
1582
1583#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
1584
1585/**
1586 * nand_write - [MTD Interface] compability function for nand_write_ecc
1587 * @mtd: MTD device structure
1588 * @to: offset to write to
1589 * @len: number of bytes to write
1590 * @retlen: pointer to variable to store the number of written bytes
1591 * @buf: the data to write
1592 *
1593 * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
1594 *
1595*/
David Woodhousee0c7d762006-05-13 18:07:53 +01001596static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
David Woodhousee0c7d762006-05-13 18:07:53 +01001598 return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601/**
1602 * nand_write_ecc - [MTD Interface] NAND write with ECC
1603 * @mtd: MTD device structure
1604 * @to: offset to write to
1605 * @len: number of bytes to write
1606 * @retlen: pointer to variable to store the number of written bytes
1607 * @buf: the data to write
1608 * @eccbuf: filesystem supplied oob data buffer
1609 * @oobsel: oob selection structure
1610 *
1611 * NAND write with ECC
1612 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001613static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
1614 size_t *retlen, const u_char *buf, u_char *eccbuf,
1615 struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616{
1617 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1618 int autoplace = 0, numpages, totalpages;
1619 struct nand_chip *this = mtd->priv;
1620 u_char *oobbuf, *bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001621 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
David Woodhousee0c7d762006-05-13 18:07:53 +01001623 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 -07001624
1625 /* Initialize retlen, in case of early exit */
1626 *retlen = 0;
1627
1628 /* Do not allow write past end of device */
1629 if ((to + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001630 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return -EINVAL;
1632 }
1633
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001634 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001635 if (NOTALIGNED(to) || NOTALIGNED(len)) {
1636 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 return -EINVAL;
1638 }
1639
1640 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001641 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 /* Calculate chipnr */
1644 chipnr = (int)(to >> this->chip_shift);
1645 /* Select the NAND device */
1646 this->select_chip(mtd, chipnr);
1647
1648 /* Check, if it is write protected */
1649 if (nand_check_wp(mtd))
1650 goto out;
1651
1652 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001653 if (oobsel == NULL)
1654 oobsel = &mtd->oobinfo;
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 /* Autoplace of oob data ? Use the default placement scheme */
1657 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1658 oobsel = this->autooob;
1659 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001660 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001661 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1662 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 /* Setup variables and oob buffer */
1665 totalpages = len >> this->page_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +01001666 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001668 if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 this->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 /* Set it relative to chip */
1672 page &= this->pagemask;
1673 startpage = page;
1674 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001675 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1676 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
1677 bufstart = (u_char *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 /* Loop until all data is written */
1680 while (written < len) {
1681
David Woodhousee0c7d762006-05-13 18:07:53 +01001682 this->data_poi = (u_char *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 /* Write one page. If this is the last page to write
1684 * or the last page in this block, then use the
1685 * real pageprogram command, else select cached programming
1686 * if supported by the chip.
1687 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001688 ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001690 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 /* Next oob page */
1694 oob += mtd->oobsize;
1695 /* Update written bytes count */
1696 written += mtd->oobblock;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001697 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* Increment page address */
1701 page++;
1702
1703 /* Have we hit a block boundary ? Then we have to verify and
1704 * if verify is ok, we have to setup the oob buffer for
1705 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001706 */
1707 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 int ofs;
1709 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001710 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1711 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 if (ret) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001713 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 *retlen = written;
1717
1718 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1719 if (eccbuf)
1720 eccbuf += (page - startpage) * ofs;
1721 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001722 numpages = min(totalpages, ppblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 page &= this->pagemask;
1724 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001725 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001726 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /* Check, if we cross a chip boundary */
1728 if (!page) {
1729 chipnr++;
1730 this->select_chip(mtd, -1);
1731 this->select_chip(mtd, chipnr);
1732 }
1733 }
1734 }
1735 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001736 cmp:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001738 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 if (!ret)
1740 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001741 else
David Woodhousee0c7d762006-05-13 18:07:53 +01001742 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
David Woodhousee0c7d762006-05-13 18:07:53 +01001744 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* Deselect and wake up anyone waiting on the device */
1746 nand_release_device(mtd);
1747
1748 return ret;
1749}
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751/**
1752 * nand_write_oob - [MTD Interface] NAND write out-of-band
1753 * @mtd: MTD device structure
1754 * @to: offset to write to
1755 * @len: number of bytes to write
1756 * @retlen: pointer to variable to store the number of written bytes
1757 * @buf: the data to write
1758 *
1759 * NAND write out-of-band
1760 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001761static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
1763 int column, page, status, ret = -EIO, chipnr;
1764 struct nand_chip *this = mtd->priv;
1765
David Woodhousee0c7d762006-05-13 18:07:53 +01001766 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 -07001767
1768 /* Shift to get page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001769 page = (int)(to >> this->page_shift);
1770 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 /* Mask to get column */
1773 column = to & (mtd->oobsize - 1);
1774
1775 /* Initialize return length value */
1776 *retlen = 0;
1777
1778 /* Do not allow write past end of page */
1779 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001780 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 return -EINVAL;
1782 }
1783
1784 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001785 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787 /* Select the NAND device */
1788 this->select_chip(mtd, chipnr);
1789
1790 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1791 in one of my DiskOnChip 2000 test units) will clear the whole
1792 data page too if we don't do this. I have no clue why, but
1793 I seem to have 'fixed' it in the doc2000 driver in
1794 August 1999. dwmw2. */
1795 this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
1796
1797 /* Check, if it is write protected */
1798 if (nand_check_wp(mtd))
1799 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 /* Invalidate the page cache, if we write to the cached page */
1802 if (page == this->pagebuf)
1803 this->pagebuf = -1;
1804
1805 if (NAND_MUST_PAD(this)) {
1806 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001807 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* prepad 0xff for partial programming */
1809 this->write_buf(mtd, ffchars, column);
1810 /* write data */
1811 this->write_buf(mtd, buf, len);
1812 /* postpad 0xff for partial programming */
David Woodhousee0c7d762006-05-13 18:07:53 +01001813 this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 } else {
1815 /* Write out desired data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001816 this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 /* write data */
1818 this->write_buf(mtd, buf, len);
1819 }
1820 /* Send command to program the OOB data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001821 this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
David Woodhousee0c7d762006-05-13 18:07:53 +01001823 status = this->waitfunc(mtd, this, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
1825 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001826 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001827 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 ret = -EIO;
1829 goto out;
1830 }
1831 /* Return happy */
1832 *retlen = len;
1833
1834#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1835 /* Send command to read back the data */
David Woodhousee0c7d762006-05-13 18:07:53 +01001836 this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
1838 if (this->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001839 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 ret = -EIO;
1841 goto out;
1842 }
1843#endif
1844 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001845 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 /* Deselect and wake up anyone waiting on the device */
1847 nand_release_device(mtd);
1848
1849 return ret;
1850}
1851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852/**
1853 * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
1854 * @mtd: MTD device structure
1855 * @vecs: the iovectors to write
1856 * @count: number of vectors
1857 * @to: offset to write to
1858 * @retlen: pointer to variable to store the number of written bytes
1859 *
1860 * NAND write with kvec. This just calls the ecc function
1861 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001862static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1863 loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864{
David Woodhousee0c7d762006-05-13 18:07:53 +01001865 return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868/**
1869 * nand_writev_ecc - [MTD Interface] write with iovec with ecc
1870 * @mtd: MTD device structure
1871 * @vecs: the iovectors to write
1872 * @count: number of vectors
1873 * @to: offset to write to
1874 * @retlen: pointer to variable to store the number of written bytes
1875 * @eccbuf: filesystem supplied oob data buffer
1876 * @oobsel: oob selection structure
1877 *
1878 * NAND write with iovec with ecc
1879 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001880static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
1881 loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882{
1883 int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
1884 int oob, numpages, autoplace = 0, startpage;
1885 struct nand_chip *this = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +01001886 int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 u_char *oobbuf, *bufstart;
1888
1889 /* Preset written len for early exit */
1890 *retlen = 0;
1891
1892 /* Calculate total length of data */
1893 total_len = 0;
1894 for (i = 0; i < count; i++)
David Woodhousee0c7d762006-05-13 18:07:53 +01001895 total_len += (int)vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
David Woodhousee0c7d762006-05-13 18:07:53 +01001897 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 -07001898
1899 /* Do not allow write past end of page */
1900 if ((to + total_len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001901 DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 return -EINVAL;
1903 }
1904
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001905 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001906 if (NOTALIGNED(to) || NOTALIGNED(total_len)) {
1907 printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 return -EINVAL;
1909 }
1910
1911 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01001912 nand_get_device(this, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
1914 /* Get the current chip-nr */
David Woodhousee0c7d762006-05-13 18:07:53 +01001915 chipnr = (int)(to >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 /* Select the NAND device */
1917 this->select_chip(mtd, chipnr);
1918
1919 /* Check, if it is write protected */
1920 if (nand_check_wp(mtd))
1921 goto out;
1922
1923 /* if oobsel is NULL, use chip defaults */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001924 if (oobsel == NULL)
1925 oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
1927 /* Autoplace of oob data ? Use the default placement scheme */
1928 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
1929 oobsel = this->autooob;
1930 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001931 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001932 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1933 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
1935 /* Setup start page */
David Woodhousee0c7d762006-05-13 18:07:53 +01001936 page = (int)(to >> this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001938 if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 this->pagebuf = -1;
1940
1941 startpage = page & this->pagemask;
1942
1943 /* Loop until all kvec' data has been written */
1944 len = 0;
1945 while (count) {
1946 /* If the given tuple is >= pagesize then
1947 * write it out from the iov
1948 */
1949 if ((vecs->iov_len - len) >= mtd->oobblock) {
1950 /* Calc number of pages we can write
1951 * out of this iov in one go */
1952 numpages = (vecs->iov_len - len) >> this->page_shift;
1953 /* Do not cross block boundaries */
David Woodhousee0c7d762006-05-13 18:07:53 +01001954 numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
1955 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
1956 bufstart = (u_char *) vecs->iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 bufstart += len;
1958 this->data_poi = bufstart;
1959 oob = 0;
1960 for (i = 1; i <= numpages; i++) {
1961 /* Write one page. If this is the last page to write
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001962 * then use the real pageprogram command, else select
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 * cached programming if supported by the chip.
1964 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001965 ret = nand_write_page(mtd, this, page & this->pagemask,
1966 &oobbuf[oob], oobsel, i != numpages);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 if (ret)
1968 goto out;
1969 this->data_poi += mtd->oobblock;
1970 len += mtd->oobblock;
1971 oob += mtd->oobsize;
1972 page++;
1973 }
1974 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001975 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 vecs++;
1977 len = 0;
1978 count--;
1979 }
1980 } else {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001981 /* We must use the internal buffer, read data out of each
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 * tuple until we have a full page to write
1983 */
1984 int cnt = 0;
1985 while (cnt < mtd->oobblock) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001986 if (vecs->iov_base != NULL && vecs->iov_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
1988 /* Check, if we have to switch to the next tuple */
David Woodhousee0c7d762006-05-13 18:07:53 +01001989 if (len >= (int)vecs->iov_len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 vecs++;
1991 len = 0;
1992 count--;
1993 }
1994 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001995 this->pagebuf = page;
1996 this->data_poi = this->data_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 bufstart = this->data_poi;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001998 numpages = 1;
David Woodhousee0c7d762006-05-13 18:07:53 +01001999 oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
2000 ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 if (ret)
2002 goto out;
2003 page++;
2004 }
2005
2006 this->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01002007 ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (ret)
2009 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 written += mtd->oobblock * numpages;
2012 /* All done ? */
2013 if (!count)
2014 break;
2015
2016 startpage = page & this->pagemask;
2017 /* Check, if we cross a chip boundary */
2018 if (!startpage) {
2019 chipnr++;
2020 this->select_chip(mtd, -1);
2021 this->select_chip(mtd, chipnr);
2022 }
2023 }
2024 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002025 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 /* Deselect and wake up anyone waiting on the device */
2027 nand_release_device(mtd);
2028
2029 *retlen = written;
2030 return ret;
2031}
2032
2033/**
2034 * single_erease_cmd - [GENERIC] NAND standard block erase command function
2035 * @mtd: MTD device structure
2036 * @page: the page address of the block which will be erased
2037 *
2038 * Standard erase command for NAND chips
2039 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002040static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041{
2042 struct nand_chip *this = mtd->priv;
2043 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002044 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2045 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046}
2047
2048/**
2049 * multi_erease_cmd - [GENERIC] AND specific block erase command function
2050 * @mtd: MTD device structure
2051 * @page: the page address of the block which will be erased
2052 *
2053 * AND multi block erase command function
2054 * Erase 4 consecutive blocks
2055 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002056static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
2058 struct nand_chip *this = mtd->priv;
2059 /* Send commands to erase a block */
David Woodhousee0c7d762006-05-13 18:07:53 +01002060 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2061 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2062 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
2063 this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
2064 this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065}
2066
2067/**
2068 * nand_erase - [MTD Interface] erase block(s)
2069 * @mtd: MTD device structure
2070 * @instr: erase instruction
2071 *
2072 * Erase one ore more blocks
2073 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002074static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
David Woodhousee0c7d762006-05-13 18:07:53 +01002076 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002078
David A. Marlin30f464b2005-01-17 18:35:25 +00002079#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080/**
2081 * nand_erase_intern - [NAND Interface] erase block(s)
2082 * @mtd: MTD device structure
2083 * @instr: erase instruction
2084 * @allowbbt: allow erasing the bbt area
2085 *
2086 * Erase one ore more blocks
2087 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002088int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089{
2090 int page, len, status, pages_per_block, ret, chipnr;
2091 struct nand_chip *this = mtd->priv;
David A. Marlin30f464b2005-01-17 18:35:25 +00002092 int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
2093 unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
2094 /* It is used to see if the current page is in the same */
2095 /* 256 block group and the same bank as the bbt. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
David Woodhousee0c7d762006-05-13 18:07:53 +01002097 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 -07002098
2099 /* Start address must align on block boundary */
2100 if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002101 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 return -EINVAL;
2103 }
2104
2105 /* Length must align on block boundary */
2106 if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002107 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 return -EINVAL;
2109 }
2110
2111 /* Do not allow erase past end of device */
2112 if ((instr->len + instr->addr) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002113 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 return -EINVAL;
2115 }
2116
2117 instr->fail_addr = 0xffffffff;
2118
2119 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002120 nand_get_device(this, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
2122 /* Shift to get first page */
David Woodhousee0c7d762006-05-13 18:07:53 +01002123 page = (int)(instr->addr >> this->page_shift);
2124 chipnr = (int)(instr->addr >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126 /* Calculate pages in each block */
2127 pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
2128
2129 /* Select the NAND device */
2130 this->select_chip(mtd, chipnr);
2131
2132 /* Check the WP bit */
2133 /* Check, if it is write protected */
2134 if (nand_check_wp(mtd)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002135 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 instr->state = MTD_ERASE_FAILED;
2137 goto erase_exit;
2138 }
2139
David A. Marlin30f464b2005-01-17 18:35:25 +00002140 /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
2141 if (this->options & BBT_AUTO_REFRESH) {
2142 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2143 } else {
2144 bbt_masked_page = 0xffffffff; /* should not match anything */
2145 }
2146
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 /* Loop through the pages */
2148 len = instr->len;
2149
2150 instr->state = MTD_ERASING;
2151
2152 while (len) {
2153 /* Check if we have a bad block, we do not erase bad blocks ! */
2154 if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002155 printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 instr->state = MTD_ERASE_FAILED;
2157 goto erase_exit;
2158 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002159
2160 /* Invalidate the page cache, if we erase the block which contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 the current cached page */
2162 if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
2163 this->pagebuf = -1;
2164
David Woodhousee0c7d762006-05-13 18:07:53 +01002165 this->erase_cmd(mtd, page & this->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002166
David Woodhousee0c7d762006-05-13 18:07:53 +01002167 status = this->waitfunc(mtd, this, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
David A. Marlin068e3c02005-01-24 03:07:46 +00002169 /* See if operation failed and additional status checks are available */
2170 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2171 status = this->errstat(mtd, this, FL_ERASING, status, page);
2172 }
2173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00002175 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002176 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 instr->state = MTD_ERASE_FAILED;
2178 instr->fail_addr = (page << this->page_shift);
2179 goto erase_exit;
2180 }
David A. Marlin30f464b2005-01-17 18:35:25 +00002181
2182 /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
2183 if (this->options & BBT_AUTO_REFRESH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002184 if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
David A. Marlin30f464b2005-01-17 18:35:25 +00002185 (page != this->bbt_td->pages[chipnr])) {
2186 rewrite_bbt[chipnr] = (page << this->page_shift);
2187 }
2188 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002189
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* Increment page address and decrement length */
2191 len -= (1 << this->phys_erase_shift);
2192 page += pages_per_block;
2193
2194 /* Check, if we cross a chip boundary */
2195 if (len && !(page & this->pagemask)) {
2196 chipnr++;
2197 this->select_chip(mtd, -1);
2198 this->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00002199
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002200 /* if BBT requires refresh and BBT-PERCHIP,
David A. Marlin30f464b2005-01-17 18:35:25 +00002201 * set the BBT page mask to see if this BBT should be rewritten */
2202 if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
2203 bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
2204 }
2205
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207 }
2208 instr->state = MTD_ERASE_DONE;
2209
David Woodhousee0c7d762006-05-13 18:07:53 +01002210 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
2213 /* Do call back function */
2214 if (!ret)
2215 mtd_erase_callback(instr);
2216
2217 /* Deselect and wake up anyone waiting on the device */
2218 nand_release_device(mtd);
2219
David A. Marlin30f464b2005-01-17 18:35:25 +00002220 /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
2221 if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
2222 for (chipnr = 0; chipnr < this->numchips; chipnr++) {
2223 if (rewrite_bbt[chipnr]) {
2224 /* update the BBT for chip */
David Woodhousee0c7d762006-05-13 18:07:53 +01002225 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
2226 chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
2227 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00002228 }
2229 }
2230 }
2231
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 /* Return more or less happy */
2233 return ret;
2234}
2235
2236/**
2237 * nand_sync - [MTD Interface] sync
2238 * @mtd: MTD device structure
2239 *
2240 * Sync is actually a wait for chip ready function
2241 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002242static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
2244 struct nand_chip *this = mtd->priv;
2245
David Woodhousee0c7d762006-05-13 18:07:53 +01002246 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
2248 /* Grab the lock and see if the device is available */
David Woodhousee0c7d762006-05-13 18:07:53 +01002249 nand_get_device(this, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002251 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254/**
2255 * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
2256 * @mtd: MTD device structure
2257 * @ofs: offset relative to mtd start
2258 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002259static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260{
2261 /* Check for invalid offset */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002262 if (ofs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002264
David Woodhousee0c7d762006-05-13 18:07:53 +01002265 return nand_block_checkbad(mtd, ofs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266}
2267
2268/**
2269 * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
2270 * @mtd: MTD device structure
2271 * @ofs: offset relative to mtd start
2272 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002273static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274{
2275 struct nand_chip *this = mtd->priv;
2276 int ret;
2277
David Woodhousee0c7d762006-05-13 18:07:53 +01002278 if ((ret = nand_block_isbad(mtd, ofs))) {
2279 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (ret > 0)
2281 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002282 return ret;
2283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285 return this->block_markbad(mtd, ofs);
2286}
2287
2288/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002289 * nand_suspend - [MTD Interface] Suspend the NAND flash
2290 * @mtd: MTD device structure
2291 */
2292static int nand_suspend(struct mtd_info *mtd)
2293{
2294 struct nand_chip *this = mtd->priv;
2295
David Woodhousee0c7d762006-05-13 18:07:53 +01002296 return nand_get_device(this, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002297}
2298
2299/**
2300 * nand_resume - [MTD Interface] Resume the NAND flash
2301 * @mtd: MTD device structure
2302 */
2303static void nand_resume(struct mtd_info *mtd)
2304{
2305 struct nand_chip *this = mtd->priv;
2306
2307 if (this->state == FL_PM_SUSPENDED)
2308 nand_release_device(mtd);
2309 else
David Woodhousee0c7d762006-05-13 18:07:53 +01002310 printk(KERN_ERR "resume() called for the chip which is not in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002311
2312}
2313
Vitaly Wool962034f2005-09-15 14:58:53 +01002314/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 * nand_scan - [NAND Interface] Scan for the NAND device
2316 * @mtd: MTD device structure
2317 * @maxchips: Number of chips to scan for
2318 *
2319 * This fills out all the not initialized function pointers
2320 * with the defaults.
2321 * The flash ID is read and the mtd/chip structures are
2322 * filled with the appropriate values. Buffers are allocated if
2323 * they are not provided by the board driver
2324 *
2325 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002326int nand_scan(struct mtd_info *mtd, int maxchips)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327{
Ben Dooks3b946e32005-03-14 18:30:48 +00002328 int i, nand_maf_id, nand_dev_id, busw, maf_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 struct nand_chip *this = mtd->priv;
2330
David Woodhousee0c7d762006-05-13 18:07:53 +01002331 /* Get buswidth to select the correct functions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 busw = this->options & NAND_BUSWIDTH_16;
2333
2334 /* check for proper chip_delay setup, set 20us if not */
2335 if (!this->chip_delay)
2336 this->chip_delay = 20;
2337
2338 /* check, if a user supplied command function given */
2339 if (this->cmdfunc == NULL)
2340 this->cmdfunc = nand_command;
2341
2342 /* check, if a user supplied wait function given */
2343 if (this->waitfunc == NULL)
2344 this->waitfunc = nand_wait;
2345
2346 if (!this->select_chip)
2347 this->select_chip = nand_select_chip;
2348 if (!this->write_byte)
2349 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
2350 if (!this->read_byte)
2351 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2352 if (!this->write_word)
2353 this->write_word = nand_write_word;
2354 if (!this->read_word)
2355 this->read_word = nand_read_word;
2356 if (!this->block_bad)
2357 this->block_bad = nand_block_bad;
2358 if (!this->block_markbad)
2359 this->block_markbad = nand_default_block_markbad;
2360 if (!this->write_buf)
2361 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2362 if (!this->read_buf)
2363 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2364 if (!this->verify_buf)
2365 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2366 if (!this->scan_bbt)
2367 this->scan_bbt = nand_default_bbt;
2368
2369 /* Select the device */
2370 this->select_chip(mtd, 0);
2371
2372 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002373 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375 /* Read manufacturer and device IDs */
2376 nand_maf_id = this->read_byte(mtd);
2377 nand_dev_id = this->read_byte(mtd);
2378
2379 /* Print and store flash device information */
2380 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002381
2382 if (nand_dev_id != nand_flash_ids[i].id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 continue;
2384
David Woodhousee0c7d762006-05-13 18:07:53 +01002385 if (!mtd->name)
2386 mtd->name = nand_flash_ids[i].name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 this->chipsize = nand_flash_ids[i].chipsize << 20;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002388
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 /* New devices have all the information in additional id bytes */
2390 if (!nand_flash_ids[i].pagesize) {
2391 int extid;
2392 /* The 3rd id byte contains non relevant data ATM */
2393 extid = this->read_byte(mtd);
2394 /* The 4th id byte is the important one */
2395 extid = this->read_byte(mtd);
2396 /* Calc pagesize */
2397 mtd->oobblock = 1024 << (extid & 0x3);
2398 extid >>= 2;
2399 /* Calc oobsize */
Thomas Gleixnerd4094662005-08-11 18:13:46 +01002400 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 extid >>= 2;
2402 /* Calc blocksize. Blocksize is multiples of 64KiB */
David Woodhousee0c7d762006-05-13 18:07:53 +01002403 mtd->erasesize = (64 * 1024) << (extid & 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 extid >>= 2;
2405 /* Get buswidth information */
2406 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002407
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 } else {
2409 /* Old devices have this data hardcoded in the
2410 * device id table */
2411 mtd->erasesize = nand_flash_ids[i].erasesize;
2412 mtd->oobblock = nand_flash_ids[i].pagesize;
2413 mtd->oobsize = mtd->oobblock / 32;
2414 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2415 }
2416
Kyungmin Park0ea4a752005-02-16 09:39:39 +00002417 /* Try to identify manufacturer */
2418 for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
2419 if (nand_manuf_ids[maf_id].id == nand_maf_id)
2420 break;
2421 }
2422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 /* Check, if buswidth is correct. Hardware drivers should set
2424 * this correct ! */
2425 if (busw != (this->options & NAND_BUSWIDTH_16)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002426 printk(KERN_INFO "NAND device: Manufacturer ID:"
2427 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2428 nand_manuf_ids[maf_id].name, mtd->name);
2429 printk(KERN_WARNING
2430 "NAND bus width %d instead %d bit\n",
2431 (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 this->select_chip(mtd, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002433 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002435
2436 /* Calculate the address shift from the page size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 this->page_shift = ffs(mtd->oobblock) - 1;
2438 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
2439 this->chip_shift = ffs(this->chipsize) - 1;
2440
2441 /* Set the bad block position */
David Woodhousee0c7d762006-05-13 18:07:53 +01002442 this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 /* Get chip options, preserve non chip based options */
2445 this->options &= ~NAND_CHIPOPTIONS_MSK;
2446 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
David Woodhousee0c7d762006-05-13 18:07:53 +01002447 /* Set this as a default. Board drivers can override it, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 this->options |= NAND_NO_AUTOINCR;
2449 /* Check if this is a not a samsung device. Do not clear the options
2450 * for chips which are not having an extended id.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002451 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
2453 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002454
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 /* Check for AND chips with 4 page planes */
2456 if (this->options & NAND_4PAGE_ARRAY)
2457 this->erase_cmd = multi_erase_cmd;
2458 else
2459 this->erase_cmd = single_erase_cmd;
2460
2461 /* Do not replace user supplied command function ! */
2462 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
2463 this->cmdfunc = nand_command_lp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002464
David Woodhousee0c7d762006-05-13 18:07:53 +01002465 printk(KERN_INFO "NAND device: Manufacturer ID:"
2466 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
2467 nand_manuf_ids[maf_id].name, nand_flash_ids[i].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 break;
2469 }
2470
2471 if (!nand_flash_ids[i].name) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002472 printk(KERN_WARNING "No NAND device found!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 this->select_chip(mtd, -1);
2474 return 1;
2475 }
2476
David Woodhousee0c7d762006-05-13 18:07:53 +01002477 for (i = 1; i < maxchips; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 this->select_chip(mtd, i);
2479
2480 /* Send the command for reading device ID */
David Woodhousee0c7d762006-05-13 18:07:53 +01002481 this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
2483 /* Read manufacturer and device IDs */
2484 if (nand_maf_id != this->read_byte(mtd) ||
2485 nand_dev_id != this->read_byte(mtd))
2486 break;
2487 }
2488 if (i > 1)
2489 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002490
David Woodhousee0c7d762006-05-13 18:07:53 +01002491 /* Allocate buffers, if necessary */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (!this->oob_buf) {
2493 size_t len;
2494 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
David Woodhousee0c7d762006-05-13 18:07:53 +01002495 this->oob_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 if (!this->oob_buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002497 printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 return -ENOMEM;
2499 }
2500 this->options |= NAND_OOBBUF_ALLOC;
2501 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002502
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 if (!this->data_buf) {
2504 size_t len;
2505 len = mtd->oobblock + mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01002506 this->data_buf = kmalloc(len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 if (!this->data_buf) {
2508 if (this->options & NAND_OOBBUF_ALLOC)
David Woodhousee0c7d762006-05-13 18:07:53 +01002509 kfree(this->oob_buf);
2510 printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 return -ENOMEM;
2512 }
2513 this->options |= NAND_DATABUF_ALLOC;
2514 }
2515
2516 /* Store the number of chips and calc total size for mtd */
2517 this->numchips = i;
2518 mtd->size = i * this->chipsize;
2519 /* Convert chipsize to number of pages per chip -1. */
2520 this->pagemask = (this->chipsize >> this->page_shift) - 1;
2521 /* Preset the internal oob buffer */
2522 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
2523
2524 /* If no default placement scheme is given, select an
2525 * appropriate one */
2526 if (!this->autooob) {
2527 /* Select the appropriate default oob placement scheme for
2528 * placement agnostic filesystems */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002529 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 case 8:
2531 this->autooob = &nand_oob_8;
2532 break;
2533 case 16:
2534 this->autooob = &nand_oob_16;
2535 break;
2536 case 64:
2537 this->autooob = &nand_oob_64;
2538 break;
2539 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002540 printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 BUG();
2542 }
2543 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 /* The number of bytes available for the filesystem to place fs dependend
2546 * oob data */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002547 mtd->oobavail = 0;
2548 for (i = 0; this->autooob->oobfree[i][1]; i++)
2549 mtd->oobavail += this->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002551 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 * check ECC mode, default to software
2553 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002554 * fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002555 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002556 this->eccsize = 256; /* set default eccsize */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 this->eccbytes = 3;
2558
2559 switch (this->eccmode) {
2560 case NAND_ECC_HW12_2048:
2561 if (mtd->oobblock < 2048) {
2562 printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
2563 mtd->oobblock);
2564 this->eccmode = NAND_ECC_SOFT;
2565 this->calculate_ecc = nand_calculate_ecc;
2566 this->correct_data = nand_correct_data;
2567 } else
2568 this->eccsize = 2048;
2569 break;
2570
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002571 case NAND_ECC_HW3_512:
2572 case NAND_ECC_HW6_512:
2573 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 if (mtd->oobblock == 256) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002575 printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 this->eccmode = NAND_ECC_SOFT;
2577 this->calculate_ecc = nand_calculate_ecc;
2578 this->correct_data = nand_correct_data;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002579 } else
David Woodhousee0c7d762006-05-13 18:07:53 +01002580 this->eccsize = 512; /* set eccsize to 512 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002582
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 case NAND_ECC_HW3_256:
2584 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002585
2586 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +01002587 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 this->eccmode = NAND_ECC_NONE;
2589 break;
2590
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002591 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 this->calculate_ecc = nand_calculate_ecc;
2593 this->correct_data = nand_correct_data;
2594 break;
2595
2596 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01002597 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002598 BUG();
2599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002601 /* Check hardware ecc function availability and adjust number of ecc bytes per
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 * calculation step
David Woodhousee0c7d762006-05-13 18:07:53 +01002603 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 switch (this->eccmode) {
2605 case NAND_ECC_HW12_2048:
2606 this->eccbytes += 4;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002607 case NAND_ECC_HW8_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 this->eccbytes += 2;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002609 case NAND_ECC_HW6_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 this->eccbytes += 3;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002611 case NAND_ECC_HW3_512:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 case NAND_ECC_HW3_256:
2613 if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
2614 break;
David Woodhousee0c7d762006-05-13 18:07:53 +01002615 printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002616 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002618
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 mtd->eccsize = this->eccsize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 /* Set the number of read / write steps for one page to ensure ECC generation */
2622 switch (this->eccmode) {
2623 case NAND_ECC_HW12_2048:
2624 this->eccsteps = mtd->oobblock / 2048;
2625 break;
2626 case NAND_ECC_HW3_512:
2627 case NAND_ECC_HW6_512:
2628 case NAND_ECC_HW8_512:
2629 this->eccsteps = mtd->oobblock / 512;
2630 break;
2631 case NAND_ECC_HW3_256:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002632 case NAND_ECC_SOFT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 this->eccsteps = mtd->oobblock / 256;
2634 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002635
2636 case NAND_ECC_NONE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 this->eccsteps = 1;
2638 break;
2639 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 /* Initialize state, waitqueue and spinlock */
2642 this->state = FL_READY;
David Woodhousee0c7d762006-05-13 18:07:53 +01002643 init_waitqueue_head(&this->wq);
2644 spin_lock_init(&this->chip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 /* De-select the device */
2647 this->select_chip(mtd, -1);
2648
2649 /* Invalidate the pagebuffer reference */
2650 this->pagebuf = -1;
2651
2652 /* Fill in remaining MTD driver data */
2653 mtd->type = MTD_NANDFLASH;
2654 mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
2655 mtd->ecctype = MTD_ECC_SW;
2656 mtd->erase = nand_erase;
2657 mtd->point = NULL;
2658 mtd->unpoint = NULL;
2659 mtd->read = nand_read;
2660 mtd->write = nand_write;
2661 mtd->read_ecc = nand_read_ecc;
2662 mtd->write_ecc = nand_write_ecc;
2663 mtd->read_oob = nand_read_oob;
2664 mtd->write_oob = nand_write_oob;
2665 mtd->readv = NULL;
2666 mtd->writev = nand_writev;
2667 mtd->writev_ecc = nand_writev_ecc;
2668 mtd->sync = nand_sync;
2669 mtd->lock = NULL;
2670 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002671 mtd->suspend = nand_suspend;
2672 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 mtd->block_isbad = nand_block_isbad;
2674 mtd->block_markbad = nand_block_markbad;
2675
2676 /* and make the autooob the default one */
2677 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
2678
2679 mtd->owner = THIS_MODULE;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002680
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002681 /* Check, if we should skip the bad block table scan */
2682 if (this->options & NAND_SKIP_BBTSCAN)
2683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685 /* Build bad block table */
David Woodhousee0c7d762006-05-13 18:07:53 +01002686 return this->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687}
2688
2689/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002690 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 * @mtd: MTD device structure
2692*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002693void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694{
2695 struct nand_chip *this = mtd->priv;
2696
2697#ifdef CONFIG_MTD_PARTITIONS
2698 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002699 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700#endif
2701 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002702 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Jesper Juhlfa671642005-11-07 01:01:27 -08002704 /* Free bad block table memory */
David Woodhousee0c7d762006-05-13 18:07:53 +01002705 kfree(this->bbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* Buffer allocated by nand_scan ? */
2707 if (this->options & NAND_OOBBUF_ALLOC)
David Woodhousee0c7d762006-05-13 18:07:53 +01002708 kfree(this->oob_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 /* Buffer allocated by nand_scan ? */
2710 if (this->options & NAND_DATABUF_ALLOC)
David Woodhousee0c7d762006-05-13 18:07:53 +01002711 kfree(this->data_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712}
2713
David Woodhousee0c7d762006-05-13 18:07:53 +01002714EXPORT_SYMBOL_GPL(nand_scan);
2715EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002716
2717static int __init nand_base_init(void)
2718{
2719 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2720 return 0;
2721}
2722
2723static void __exit nand_base_exit(void)
2724{
2725 led_trigger_unregister_simple(nand_led_trigger);
2726}
2727
2728module_init(nand_base_init);
2729module_exit(nand_base_exit);
2730
David Woodhousee0c7d762006-05-13 18:07:53 +01002731MODULE_LICENSE("GPL");
2732MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2733MODULE_DESCRIPTION("Generic NAND flash driver code");