blob: 5690de223c114b8478a4c0b8ff1044ac7823bef8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/mtd/nand.c
3 *
4 * Overview:
5 * This is the generic MTD driver for NAND flash devices. It should be
6 * capable of working with almost all NAND chips currently available.
7 * Basic support for AG-AND chips is provided.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Additional technical information is available on
10 * http://www.linux-mtd.infradead.org/tech/nand.html
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000011 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020013 * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020015 * Credits:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000016 * David Woodhouse for adding multichip support
17 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
19 * rework for 2K page size chips
20 *
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +020021 * TODO:
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * Enable cached programming for 2k page size chips
23 * Check, if mtd->ecctype should be set to MTD_ECC_HW
24 * if we have HW ecc support.
25 * The AG-AND chips have nice features for speed improvement,
26 * which are not supported yet. Read / program 4 pages in one go.
27 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License version 2 as
30 * published by the Free Software Foundation.
31 *
32 */
33
David Woodhouse552d9202006-05-14 01:20:46 +010034#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/delay.h>
36#include <linux/errno.h>
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +020037#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/sched.h>
39#include <linux/slab.h>
40#include <linux/types.h>
41#include <linux/mtd/mtd.h>
42#include <linux/mtd/nand.h>
43#include <linux/mtd/nand_ecc.h>
44#include <linux/mtd/compatmac.h>
45#include <linux/interrupt.h>
46#include <linux/bitops.h>
Richard Purdie8fe833c2006-03-31 02:31:14 -080047#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/io.h>
49
50#ifdef CONFIG_MTD_PARTITIONS
51#include <linux/mtd/partitions.h>
52#endif
53
54/* Define default oob placement schemes for large and small page devices */
55static struct nand_oobinfo nand_oob_8 = {
56 .useecc = MTD_NANDECC_AUTOPLACE,
57 .eccbytes = 3,
58 .eccpos = {0, 1, 2},
David Woodhousee0c7d762006-05-13 18:07:53 +010059 .oobfree = {{3, 2}, {6, 2}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070060};
61
62static struct nand_oobinfo nand_oob_16 = {
63 .useecc = MTD_NANDECC_AUTOPLACE,
64 .eccbytes = 6,
65 .eccpos = {0, 1, 2, 3, 6, 7},
David Woodhousee0c7d762006-05-13 18:07:53 +010066 .oobfree = {{8, 8}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070067};
68
69static struct nand_oobinfo nand_oob_64 = {
70 .useecc = MTD_NANDECC_AUTOPLACE,
71 .eccbytes = 24,
72 .eccpos = {
David Woodhousee0c7d762006-05-13 18:07:53 +010073 40, 41, 42, 43, 44, 45, 46, 47,
74 48, 49, 50, 51, 52, 53, 54, 55,
75 56, 57, 58, 59, 60, 61, 62, 63},
76 .oobfree = {{2, 38}}
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79/* This is used for padding purposes in nand_write_oob */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020080static uint8_t ffchars[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
82 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
83 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
84 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
85 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89};
90
91/*
92 * NAND low-level MTD interface functions
93 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020094static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
95static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
96static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +020098static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +020099 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200100static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200101 size_t *retlen, uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200102static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200103 size_t *retlen, const uint8_t *buf);
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200104static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200105 size_t *retlen, const uint8_t *buf);
David Woodhousee0c7d762006-05-13 18:07:53 +0100106static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
107static void nand_sync(struct mtd_info *mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109/* Some internal functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200110static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200111 int page, uint8_t * oob_buf,
David Woodhousee0c7d762006-05-13 18:07:53 +0100112 struct nand_oobinfo *oobsel, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200114static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200115 int page, int numpages, uint8_t *oob_buf,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200116 struct nand_oobinfo *oobsel, int chipnr,
117 int oobmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#else
119#define nand_verify_pages(...) (0)
120#endif
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000121
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200122static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200123 int new_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Thomas Gleixnerd470a972006-05-23 23:48:57 +0200125/*
126 * For devices which display every fart in the system on a seperate LED. Is
127 * compiled away when LED support is disabled.
128 */
129DEFINE_LED_TRIGGER(nand_led_trigger);
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131/**
132 * nand_release_device - [GENERIC] release chip
133 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000134 *
135 * Deselect, release chip lock and wake up anyone waiting on the device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100137static void nand_release_device(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200139 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* De-select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200142 chip->select_chip(mtd, -1);
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100143
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200144 /* Release the controller and the chip */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200145 spin_lock(&chip->controller->lock);
146 chip->controller->active = NULL;
147 chip->state = FL_READY;
148 wake_up(&chip->controller->wq);
149 spin_unlock(&chip->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150}
151
152/**
153 * nand_read_byte - [DEFAULT] read one byte from the chip
154 * @mtd: MTD device structure
155 *
156 * Default read function for 8bit buswith
157 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200158static uint8_t nand_read_byte(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200160 struct nand_chip *chip = mtd->priv;
161 return readb(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
163
164/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
166 * @mtd: MTD device structure
167 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000168 * Default read function for 16bit buswith with
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 * endianess conversion
170 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200171static uint8_t nand_read_byte16(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200173 struct nand_chip *chip = mtd->priv;
174 return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 * nand_read_word - [DEFAULT] read one word from the chip
179 * @mtd: MTD device structure
180 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000181 * Default read function for 16bit buswith without
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * endianess conversion
183 */
184static u16 nand_read_word(struct mtd_info *mtd)
185{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200186 struct nand_chip *chip = mtd->priv;
187 return readw(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
190/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 * nand_select_chip - [DEFAULT] control CE line
192 * @mtd: MTD device structure
193 * @chip: chipnumber to select, -1 for deselect
194 *
195 * Default select function for 1 chip devices.
196 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200197static void nand_select_chip(struct mtd_info *mtd, int chipnr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200199 struct nand_chip *chip = mtd->priv;
200
201 switch (chipnr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 case -1:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200203 chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 break;
205 case 0:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200206 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
207 NAND_NCE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 break;
209
210 default:
211 BUG();
212 }
213}
214
215/**
216 * nand_write_buf - [DEFAULT] write buffer to chip
217 * @mtd: MTD device structure
218 * @buf: data buffer
219 * @len: number of bytes to write
220 *
221 * Default write function for 8bit buswith
222 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200223static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200226 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
David Woodhousee0c7d762006-05-13 18:07:53 +0100228 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200229 writeb(buf[i], chip->IO_ADDR_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000233 * nand_read_buf - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 * @mtd: MTD device structure
235 * @buf: buffer to store date
236 * @len: number of bytes to read
237 *
238 * Default read function for 8bit buswith
239 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200240static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200243 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
David Woodhousee0c7d762006-05-13 18:07:53 +0100245 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200246 buf[i] = readb(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000250 * nand_verify_buf - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 * @mtd: MTD device structure
252 * @buf: buffer containing the data to compare
253 * @len: number of bytes to compare
254 *
255 * Default verify function for 8bit buswith
256 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200257static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200260 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Woodhousee0c7d762006-05-13 18:07:53 +0100262 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200263 if (buf[i] != readb(chip->IO_ADDR_R))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return -EFAULT;
265
266 return 0;
267}
268
269/**
270 * nand_write_buf16 - [DEFAULT] write buffer to chip
271 * @mtd: MTD device structure
272 * @buf: data buffer
273 * @len: number of bytes to write
274 *
275 * Default write function for 16bit buswith
276 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200277static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
279 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200280 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 u16 *p = (u16 *) buf;
282 len >>= 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000283
David Woodhousee0c7d762006-05-13 18:07:53 +0100284 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200285 writew(p[i], chip->IO_ADDR_W);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287}
288
289/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000290 * nand_read_buf16 - [DEFAULT] read chip data into buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 * @mtd: MTD device structure
292 * @buf: buffer to store date
293 * @len: number of bytes to read
294 *
295 * Default read function for 16bit buswith
296 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200297static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200300 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 u16 *p = (u16 *) buf;
302 len >>= 1;
303
David Woodhousee0c7d762006-05-13 18:07:53 +0100304 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200305 p[i] = readw(chip->IO_ADDR_R);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
308/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000309 * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 * @mtd: MTD device structure
311 * @buf: buffer containing the data to compare
312 * @len: number of bytes to compare
313 *
314 * Default verify function for 16bit buswith
315 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200316static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 int i;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200319 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 u16 *p = (u16 *) buf;
321 len >>= 1;
322
David Woodhousee0c7d762006-05-13 18:07:53 +0100323 for (i = 0; i < len; i++)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200324 if (p[i] != readw(chip->IO_ADDR_R))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return -EFAULT;
326
327 return 0;
328}
329
330/**
331 * nand_block_bad - [DEFAULT] Read bad block marker from the chip
332 * @mtd: MTD device structure
333 * @ofs: offset from device start
334 * @getchip: 0, if the chip is already selected
335 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000336 * Check, if the block is bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 */
338static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
339{
340 int page, chipnr, res = 0;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200341 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 u16 bad;
343
344 if (getchip) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200345 page = (int)(ofs >> chip->page_shift);
346 chipnr = (int)(ofs >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200348 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200351 chip->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000352 } else
David Woodhousee0c7d762006-05-13 18:07:53 +0100353 page = (int)ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200355 if (chip->options & NAND_BUSWIDTH_16) {
356 chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
357 page & chip->pagemask);
358 bad = cpu_to_le16(chip->read_word(mtd));
359 if (chip->badblockpos & 0x1)
Vitaly Wool49196f32005-11-02 16:54:46 +0000360 bad >>= 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if ((bad & 0xFF) != 0xff)
362 res = 1;
363 } else {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200364 chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
365 page & chip->pagemask);
366 if (chip->read_byte(mtd) != 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 res = 1;
368 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000369
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200370 if (getchip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 nand_release_device(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return res;
374}
375
376/**
377 * nand_default_block_markbad - [DEFAULT] mark a block bad
378 * @mtd: MTD device structure
379 * @ofs: offset from device start
380 *
381 * This is the default implementation, which can be overridden by
382 * a hardware specific driver.
383*/
384static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
385{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200386 struct nand_chip *chip = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200387 uint8_t buf[2] = { 0, 0 };
David Woodhousee0c7d762006-05-13 18:07:53 +0100388 size_t retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 int block;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* Get block number */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200392 block = ((int)ofs) >> chip->bbt_erase_shift;
393 if (chip->bbt)
394 chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
396 /* Do we have a flash based bad block table ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200397 if (chip->options & NAND_USE_FLASH_BBT)
David Woodhousee0c7d762006-05-13 18:07:53 +0100398 return nand_update_bbt(mtd, ofs);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* We write two bytes, so we dont have to mess with 16 bit access */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200401 ofs += mtd->oobsize + (chip->badblockpos & ~0x01);
David Woodhousee0c7d762006-05-13 18:07:53 +0100402 return nand_write_oob(mtd, ofs, 2, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000405/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 * nand_check_wp - [GENERIC] check if the chip is write protected
407 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000408 * Check, if the device is write protected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000410 * The function expects, that the device is already selected
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100412static int nand_check_wp(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200414 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 /* Check the WP bit */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200416 chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
417 return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
420/**
421 * nand_block_checkbad - [GENERIC] Check if a block is marked bad
422 * @mtd: MTD device structure
423 * @ofs: offset from device start
424 * @getchip: 0, if the chip is already selected
425 * @allowbbt: 1, if its allowed to access the bbt area
426 *
427 * Check, if the block is bad. Either by reading the bad block table or
428 * calling of the scan function.
429 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200430static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
431 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200433 struct nand_chip *chip = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000434
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200435 if (!chip->bbt)
436 return chip->block_bad(mtd, ofs, getchip);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 /* Return info from the table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100439 return nand_isbad_bbt(mtd, ofs, allowbbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000442/*
Thomas Gleixner3b887752005-02-22 21:56:49 +0000443 * Wait for the ready pin, after a command
444 * The timeout is catched later.
445 */
446static void nand_wait_ready(struct mtd_info *mtd)
447{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200448 struct nand_chip *chip = mtd->priv;
David Woodhousee0c7d762006-05-13 18:07:53 +0100449 unsigned long timeo = jiffies + 2;
Thomas Gleixner3b887752005-02-22 21:56:49 +0000450
Richard Purdie8fe833c2006-03-31 02:31:14 -0800451 led_trigger_event(nand_led_trigger, LED_FULL);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000452 /* wait until command is processed or timeout occures */
453 do {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200454 if (chip->dev_ready(mtd))
Richard Purdie8fe833c2006-03-31 02:31:14 -0800455 break;
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700456 touch_softlockup_watchdog();
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000457 } while (time_before(jiffies, timeo));
Richard Purdie8fe833c2006-03-31 02:31:14 -0800458 led_trigger_event(nand_led_trigger, LED_OFF);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461/**
462 * nand_command - [DEFAULT] Send command to NAND device
463 * @mtd: MTD device structure
464 * @command: the command to be sent
465 * @column: the column address for this command, -1 if none
466 * @page_addr: the page address for this command, -1 if none
467 *
468 * Send command to NAND device. This function is used for small page
469 * devices (256/512 Bytes per page)
470 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200471static void nand_command(struct mtd_info *mtd, unsigned int command,
472 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200474 register struct nand_chip *chip = mtd->priv;
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200475 int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 /*
478 * Write out the command to the device.
479 */
480 if (command == NAND_CMD_SEQIN) {
481 int readcmd;
482
Joern Engel28318772006-05-22 23:18:05 +0200483 if (column >= mtd->writesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 /* OOB area */
Joern Engel28318772006-05-22 23:18:05 +0200485 column -= mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 readcmd = NAND_CMD_READOOB;
487 } else if (column < 256) {
488 /* First 256 bytes --> READ0 */
489 readcmd = NAND_CMD_READ0;
490 } else {
491 column -= 256;
492 readcmd = NAND_CMD_READ1;
493 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200494 chip->cmd_ctrl(mtd, readcmd, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200495 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200497 chip->cmd_ctrl(mtd, command, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200499 /*
500 * Address cycle, when necessary
501 */
502 ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
503 /* Serially input address */
504 if (column != -1) {
505 /* Adjust columns for 16 bit buswidth */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200506 if (chip->options & NAND_BUSWIDTH_16)
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200507 column >>= 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200508 chip->cmd_ctrl(mtd, column, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200509 ctrl &= ~NAND_CTRL_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200511 if (page_addr != -1) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200512 chip->cmd_ctrl(mtd, page_addr, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200513 ctrl &= ~NAND_CTRL_CHANGE;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200514 chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200515 /* One more address cycle for devices > 32MiB */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200516 if (chip->chipsize > (32 << 20))
517 chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200518 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200519 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000520
521 /*
522 * program and erase have their own busy handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 * status and sequential in needs no delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100524 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 case NAND_CMD_PAGEPROG:
528 case NAND_CMD_ERASE1:
529 case NAND_CMD_ERASE2:
530 case NAND_CMD_SEQIN:
531 case NAND_CMD_STATUS:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200532 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return;
534
535 case NAND_CMD_RESET:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200536 if (chip->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 break;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200538 udelay(chip->chip_delay);
539 chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200540 NAND_CTRL_CLE | NAND_CTRL_CHANGE);
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200541 chip->cmd_ctrl(mtd,
542 NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200543 while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return;
545
David Woodhousee0c7d762006-05-13 18:07:53 +0100546 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000548 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 * If we don't have access to the busy pin, we apply the given
550 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100551 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200552 if (!chip->dev_ready) {
553 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* Apply this short delay always to ensure that we do wait tWB in
558 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100559 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000560
561 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
564/**
565 * nand_command_lp - [DEFAULT] Send command to NAND large page device
566 * @mtd: MTD device structure
567 * @command: the command to be sent
568 * @column: the column address for this command, -1 if none
569 * @page_addr: the page address for this command, -1 if none
570 *
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200571 * Send command to NAND device. This is the version for the new large page
572 * devices We dont have the separate regions as we have in the small page
573 * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 *
575 */
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200576static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
577 int column, int page_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200579 register struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 /* Emulate NAND_CMD_READOOB */
582 if (command == NAND_CMD_READOOB) {
Joern Engel28318772006-05-22 23:18:05 +0200583 column += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 command = NAND_CMD_READ0;
585 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000586
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200587 /* Command latch cycle */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200588 chip->cmd_ctrl(mtd, command & 0xff,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200589 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 if (column != -1 || page_addr != -1) {
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200592 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 /* Serially input address */
595 if (column != -1) {
596 /* Adjust columns for 16 bit buswidth */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200597 if (chip->options & NAND_BUSWIDTH_16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 column >>= 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200599 chip->cmd_ctrl(mtd, column, ctrl);
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200600 ctrl &= ~NAND_CTRL_CHANGE;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200601 chip->cmd_ctrl(mtd, column >> 8, ctrl);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (page_addr != -1) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200604 chip->cmd_ctrl(mtd, page_addr, ctrl);
605 chip->cmd_ctrl(mtd, page_addr >> 8,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200606 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /* One more address cycle for devices > 128MiB */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200608 if (chip->chipsize > (128 << 20))
609 chip->cmd_ctrl(mtd, page_addr >> 16,
Thomas Gleixner7abd3ef2006-05-23 23:25:53 +0200610 NAND_NCE | NAND_ALE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200613 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000614
615 /*
616 * program and erase have their own busy handlers
David A. Marlin30f464b2005-01-17 18:35:25 +0000617 * status, sequential in, and deplete1 need no delay
618 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 switch (command) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 case NAND_CMD_CACHEDPROG:
622 case NAND_CMD_PAGEPROG:
623 case NAND_CMD_ERASE1:
624 case NAND_CMD_ERASE2:
625 case NAND_CMD_SEQIN:
626 case NAND_CMD_STATUS:
David A. Marlin30f464b2005-01-17 18:35:25 +0000627 case NAND_CMD_DEPLETE1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return;
629
David Woodhousee0c7d762006-05-13 18:07:53 +0100630 /*
631 * read error status commands require only a short delay
632 */
David A. Marlin30f464b2005-01-17 18:35:25 +0000633 case NAND_CMD_STATUS_ERROR:
634 case NAND_CMD_STATUS_ERROR0:
635 case NAND_CMD_STATUS_ERROR1:
636 case NAND_CMD_STATUS_ERROR2:
637 case NAND_CMD_STATUS_ERROR3:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200638 udelay(chip->chip_delay);
David A. Marlin30f464b2005-01-17 18:35:25 +0000639 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 case NAND_CMD_RESET:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200642 if (chip->dev_ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 break;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200644 udelay(chip->chip_delay);
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200645 chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
646 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
647 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
648 NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200649 while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return;
651
652 case NAND_CMD_READ0:
Thomas Gleixner12efdde2006-05-24 22:57:09 +0200653 chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
654 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
655 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
656 NAND_NCE | NAND_CTRL_CHANGE);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000657
David Woodhousee0c7d762006-05-13 18:07:53 +0100658 /* This applies to read commands */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 default:
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000660 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 * If we don't have access to the busy pin, we apply the given
662 * command delay
David Woodhousee0c7d762006-05-13 18:07:53 +0100663 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200664 if (!chip->dev_ready) {
665 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Thomas Gleixner3b887752005-02-22 21:56:49 +0000669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /* Apply this short delay always to ensure that we do wait tWB in
671 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100672 ndelay(100);
Thomas Gleixner3b887752005-02-22 21:56:49 +0000673
674 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
677/**
678 * nand_get_device - [GENERIC] Get chip for selected access
679 * @this: the nand chip descriptor
680 * @mtd: MTD device structure
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000681 * @new_state: the state which is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 *
683 * Get the device and lock it for exclusive access
684 */
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +0200685static int
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200686nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200688 spinlock_t *lock = &chip->controller->lock;
689 wait_queue_head_t *wq = &chip->controller->wq;
David Woodhousee0c7d762006-05-13 18:07:53 +0100690 DECLARE_WAITQUEUE(wait, current);
David Woodhousee0c7d762006-05-13 18:07:53 +0100691 retry:
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100692 spin_lock(lock);
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* Hardware controller shared among independend devices */
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200695 /* Hardware controller shared among independend devices */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200696 if (!chip->controller->active)
697 chip->controller->active = chip;
Thomas Gleixnera36ed292006-05-23 11:37:03 +0200698
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200699 if (chip->controller->active == chip && chip->state == FL_READY) {
700 chip->state = new_state;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100701 spin_unlock(lock);
Vitaly Wool962034f2005-09-15 14:58:53 +0100702 return 0;
703 }
704 if (new_state == FL_PM_SUSPENDED) {
705 spin_unlock(lock);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200706 return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
Thomas Gleixner0dfc6242005-05-31 20:39:20 +0100707 }
708 set_current_state(TASK_UNINTERRUPTIBLE);
709 add_wait_queue(wq, &wait);
710 spin_unlock(lock);
711 schedule();
712 remove_wait_queue(wq, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 goto retry;
714}
715
716/**
717 * nand_wait - [DEFAULT] wait until the command is done
718 * @mtd: MTD device structure
719 * @this: NAND chip structure
720 * @state: state to select the max. timeout value
721 *
722 * Wait for command done. This applies to erase and program only
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000723 * Erase can take up to 400ms and program up to 20ms according to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 * general NAND and SmartMedia specs
725 *
726*/
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200727static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
729
David Woodhousee0c7d762006-05-13 18:07:53 +0100730 unsigned long timeo = jiffies;
731 int status;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (state == FL_ERASING)
David Woodhousee0c7d762006-05-13 18:07:53 +0100734 timeo += (HZ * 400) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 else
David Woodhousee0c7d762006-05-13 18:07:53 +0100736 timeo += (HZ * 20) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Richard Purdie8fe833c2006-03-31 02:31:14 -0800738 led_trigger_event(nand_led_trigger, LED_FULL);
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 /* Apply this short delay always to ensure that we do wait tWB in
741 * any case on any machine. */
David Woodhousee0c7d762006-05-13 18:07:53 +0100742 ndelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200744 if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
745 chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000746 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200747 chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000749 while (time_before(jiffies, timeo)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* Check, if we were interrupted */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200751 if (chip->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200754 if (chip->dev_ready) {
755 if (chip->dev_ready(mtd))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000756 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 } else {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200758 if (chip->read_byte(mtd) & NAND_STATUS_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 break;
760 }
Thomas Gleixner20a6c212005-03-01 09:32:48 +0000761 cond_resched();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Richard Purdie8fe833c2006-03-31 02:31:14 -0800763 led_trigger_event(nand_led_trigger, LED_OFF);
764
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200765 status = (int)chip->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return status;
767}
768
769/**
770 * nand_write_page - [GENERIC] write one page
771 * @mtd: MTD device structure
772 * @this: NAND chip structure
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200773 * @page: startpage inside the chip, must be called with (page & chip->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 * @oob_buf: out of band data buffer
775 * @oobsel: out of band selecttion structre
776 * @cached: 1 = enable cached programming if supported by chip
777 *
778 * Nand_page_program function is used for write and writev !
779 * This function will always program a full page of data
780 * If you call it with a non page aligned buffer, you're lost :)
781 *
782 * Cached programming is not supported yet.
783 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200784static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, int page,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200785 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
David Woodhousee0c7d762006-05-13 18:07:53 +0100787 int i, status;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200788 uint8_t ecc_code[32];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200789 int eccmode = oobsel->useecc ? chip->ecc.mode : NAND_ECC_NONE;
David Woodhousee0c7d762006-05-13 18:07:53 +0100790 int *oob_config = oobsel->eccpos;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200791 int datidx = 0, eccidx = 0, eccsteps = chip->ecc.steps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100792 int eccbytes = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 /* FIXME: Enable cached programming */
795 cached = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 /* Send command to begin auto page programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200798 chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 /* Write out complete page of data, take care of eccmode */
801 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100802 /* No ecc, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 case NAND_ECC_NONE:
David Woodhousee0c7d762006-05-13 18:07:53 +0100804 printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200805 chip->write_buf(mtd, chip->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000807
David Woodhousee0c7d762006-05-13 18:07:53 +0100808 /* Software ecc 3/256, write all */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 case NAND_ECC_SOFT:
810 for (; eccsteps; eccsteps--) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200811 chip->ecc.calculate(mtd, &chip->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 for (i = 0; i < 3; i++, eccidx++)
813 oob_buf[oob_config[eccidx]] = ecc_code[i];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200814 datidx += chip->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200816 chip->write_buf(mtd, chip->data_poi, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818 default:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200819 eccbytes = chip->ecc.bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 for (; eccsteps; eccsteps--) {
821 /* enable hardware ecc logic for write */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200822 chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
823 chip->write_buf(mtd, &chip->data_poi[datidx], chip->ecc.size);
824 chip->ecc.calculate(mtd, &chip->data_poi[datidx], ecc_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 for (i = 0; i < eccbytes; i++, eccidx++)
826 oob_buf[oob_config[eccidx]] = ecc_code[i];
827 /* If the hardware ecc provides syndromes then
828 * the ecc code must be written immidiately after
829 * the data bytes (words) */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200830 if (chip->options & NAND_HWECC_SYNDROME)
831 chip->write_buf(mtd, ecc_code, eccbytes);
832 datidx += chip->ecc.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834 break;
835 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* Write out OOB data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200838 if (chip->options & NAND_HWECC_SYNDROME)
839 chip->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000840 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200841 chip->write_buf(mtd, oob_buf, mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 /* Send command to actually program the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200844 chip->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 if (!cached) {
847 /* call wait ready function */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200848 status = chip->waitfunc(mtd, chip, FL_WRITING);
David A. Marlin068e3c02005-01-24 03:07:46 +0000849
850 /* See if operation failed and additional status checks are available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200851 if ((status & NAND_STATUS_FAIL) && (chip->errstat)) {
852 status = chip->errstat(mtd, chip, FL_WRITING, status, page);
David A. Marlin068e3c02005-01-24 03:07:46 +0000853 }
854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +0000856 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100857 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return -EIO;
859 }
860 } else {
861 /* FIXME: Implement cached programming ! */
David Woodhousee0c7d762006-05-13 18:07:53 +0100862 /* wait until cache is ready */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200863 // status = chip->waitfunc (mtd, this, FL_CACHEDRPG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000865 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
868#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
869/**
870 * nand_verify_pages - [GENERIC] verify the chip contents after a write
871 * @mtd: MTD device structure
872 * @this: NAND chip structure
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200873 * @page: startpage inside the chip, must be called with (page & chip->pagemask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 * @numpages: number of pages to verify
875 * @oob_buf: out of band data buffer
876 * @oobsel: out of band selecttion structre
877 * @chipnr: number of the current chip
878 * @oobmode: 1 = full buffer verify, 0 = ecc only
879 *
880 * The NAND device assumes that it is always writing to a cleanly erased page.
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000881 * Hence, it performs its internal write verification only on bits that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 * transitioned from 1 to 0. The device does NOT verify the whole page on a
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000883 * byte by byte basis. It is possible that the page was not completely erased
884 * or the page is becoming unusable due to wear. The read with ECC would catch
885 * the error later when the ECC page check fails, but we would rather catch
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 * it early in the page write stage. Better to write no data than invalid data.
887 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200888static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip, int page, int numpages,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200889 uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
David Woodhousee0c7d762006-05-13 18:07:53 +0100891 int i, j, datidx = 0, oobofs = 0, res = -EIO;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200892 int eccsteps = chip->eccsteps;
David Woodhousee0c7d762006-05-13 18:07:53 +0100893 int hweccbytes;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200894 uint8_t oobdata[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200896 hweccbytes = (chip->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
898 /* Send command to read back the first page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200899 chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
David Woodhousee0c7d762006-05-13 18:07:53 +0100901 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 for (j = 0; j < eccsteps; j++) {
903 /* Loop through and verify the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200904 if (chip->verify_buf(mtd, &chip->data_poi[datidx], mtd->eccsize)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100905 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 goto out;
907 }
908 datidx += mtd->eccsize;
909 /* Have we a hw generator layout ? */
910 if (!hweccbytes)
911 continue;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200912 if (chip->verify_buf(mtd, &chip->oob_buf[oobofs], hweccbytes)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100913 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 goto out;
915 }
916 oobofs += hweccbytes;
917 }
918
919 /* check, if we must compare all data or if we just have to
920 * compare the ecc bytes
921 */
922 if (oobmode) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200923 if (chip->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100924 DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 goto out;
926 }
927 } else {
928 /* Read always, else autoincrement fails */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200929 chip->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
932 int ecccnt = oobsel->eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 for (i = 0; i < ecccnt; i++) {
935 int idx = oobsel->eccpos[i];
David Woodhousee0c7d762006-05-13 18:07:53 +0100936 if (oobdata[idx] != oob_buf[oobofs + idx]) {
937 DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n",
938 __FUNCTION__, page, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 goto out;
940 }
941 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 oobofs += mtd->oobsize - hweccbytes * eccsteps;
945 page++;
946 numpages--;
947
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000948 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 * Do this before the AUTOINCR check, so no problems
950 * arise if a chip which does auto increment
951 * is marked as NOAUTOINCR by the board driver.
952 * Do this also before returning, so the chip is
953 * ready for the next command.
David Woodhousee0c7d762006-05-13 18:07:53 +0100954 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200955 if (!chip->dev_ready)
956 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 else
Thomas Gleixner3b887752005-02-22 21:56:49 +0000958 nand_wait_ready(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 /* All done, return happy */
961 if (!numpages)
962 return 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000963
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000964 /* Check, if the chip supports auto page increment */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if (!NAND_CANAUTOINCR(this))
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200966 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000968 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 * Terminate the read command. We come here in case of an error
970 * So we must issue a reset command.
971 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100972 out:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +0200973 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return res;
975}
976#endif
977
978/**
David A. Marlin068e3c02005-01-24 03:07:46 +0000979 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 * @mtd: MTD device structure
981 * @from: offset to read from
982 * @len: number of bytes to read
983 * @retlen: pointer to variable to store the number of read bytes
984 * @buf: the databuffer to put data
985 *
David A. Marlin068e3c02005-01-24 03:07:46 +0000986 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
987 * and flags = 0xff
988 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +0200989static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
David Woodhousee0c7d762006-05-13 18:07:53 +0100991 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
Thomas Gleixner22c60f52005-04-04 19:56:32 +0100992}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994/**
David A. Marlin068e3c02005-01-24 03:07:46 +0000995 * nand_do_read_ecc - [MTD Interface] Read data with ECC
996 * @mtd: MTD device structure
997 * @from: offset to read from
998 * @len: number of bytes to read
999 * @retlen: pointer to variable to store the number of read bytes
1000 * @buf: the databuffer to put data
Dan Brownbb75ba42005-04-04 19:02:26 +01001001 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001002 * @oobsel: oob selection structure
David A. Marlin068e3c02005-01-24 03:07:46 +00001003 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1004 * and how many corrected error bits are acceptable:
1005 * bits 0..7 - number of tolerable errors
1006 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1007 *
1008 * NAND read with ECC
1009 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001010int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001011 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
David A. Marlin068e3c02005-01-24 03:07:46 +00001012{
Thomas Gleixner22c60f52005-04-04 19:56:32 +01001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1015 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001016 struct nand_chip *chip = mtd->priv;
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001017 uint8_t *data_poi, *oob_data = oob_buf;
1018 uint8_t ecc_calc[32];
1019 uint8_t ecc_code[32];
David Woodhousee0c7d762006-05-13 18:07:53 +01001020 int eccmode, eccsteps;
1021 int *oob_config, datidx;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001022 int blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
David Woodhousee0c7d762006-05-13 18:07:53 +01001023 int eccbytes;
1024 int compareecc = 1;
1025 int oobreadlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
David Woodhousee0c7d762006-05-13 18:07:53 +01001027 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 -07001028
1029 /* Do not allow reads past end of device */
1030 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001031 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 *retlen = 0;
1033 return -EINVAL;
1034 }
1035
1036 /* Grab the lock and see if the device is available */
David A. Marlin068e3c02005-01-24 03:07:46 +00001037 if (flags & NAND_GET_DEVICE)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001038 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 /* Autoplace of oob data ? Use the default placement scheme */
1041 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001042 oobsel = chip->autooob;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001043
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001044 eccmode = oobsel->useecc ? chip->ecc.mode : NAND_ECC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 oob_config = oobsel->eccpos;
1046
1047 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001048 chipnr = (int)(from >> chip->chip_shift);
1049 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 /* First we calculate the starting page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001052 realpage = (int)(from >> chip->page_shift);
1053 page = realpage & chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
1055 /* Get raw starting column */
Joern Engel28318772006-05-22 23:18:05 +02001056 col = from & (mtd->writesize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Joern Engel28318772006-05-22 23:18:05 +02001058 end = mtd->writesize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001059 ecc = chip->ecc.size;
1060 eccbytes = chip->ecc.bytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001061
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001062 if ((eccmode == NAND_ECC_NONE) || (chip->options & NAND_HWECC_SYNDROME))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 compareecc = 0;
1064
1065 oobreadlen = mtd->oobsize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001066 if (chip->options & NAND_HWECC_SYNDROME)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 oobreadlen -= oobsel->eccbytes;
1068
1069 /* Loop until all data read */
1070 while (read < len) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 int aligned = (!col && (len - read) >= end);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001073 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 * If the read is not page aligned, we have to read into data buffer
1075 * due to ecc, else we read into return buffer direct
1076 */
1077 if (aligned)
1078 data_poi = &buf[read];
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001079 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001080 data_poi = chip->data_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001081
1082 /* Check, if we have this page in the buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 *
1084 * FIXME: Make it work when we must provide oob data too,
1085 * check the usage of data_buf oob field
1086 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001087 if (realpage == chip->pagebuf && !oob_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /* aligned read ? */
1089 if (aligned)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001090 memcpy(data_poi, chip->data_buf, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 goto readdata;
1092 }
1093
1094 /* Check, if we must send the read command */
1095 if (sndcmd) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001096 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 sndcmd = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 /* get oob area, if we have no oob buffer from fs-driver */
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001101 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
1102 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001103 oob_data = &chip->data_buf[end];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001105 eccsteps = chip->ecc.steps;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 switch (eccmode) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001108 case NAND_ECC_NONE:{
1109 /* No ECC, Read in a page */
1110 static unsigned long lastwhinge = 0;
1111 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1112 printk(KERN_WARNING
1113 "Reading data from NAND FLASH without ECC is not recommended\n");
1114 lastwhinge = jiffies;
1115 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001116 chip->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001117 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001121 chip->read_buf(mtd, data_poi, end);
David Woodhousee0c7d762006-05-13 18:07:53 +01001122 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001123 chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001124 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 default:
David Woodhousee0c7d762006-05-13 18:07:53 +01001127 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001128 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1129 chip->read_buf(mtd, &data_poi[datidx], ecc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 /* HW ecc with syndrome calculation must read the
1132 * syndrome from flash immidiately after the data */
1133 if (!compareecc) {
1134 /* Some hw ecc generators need to know when the
1135 * syndrome is read from flash */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001136 chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
1137 chip->read_buf(mtd, &oob_data[i], eccbytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 /* We calc error correction directly, it checks the hw
1139 * generator for an error, reads back the syndrome and
1140 * does the error correction on the fly */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001141 ecc_status = chip->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
David A. Marlin068e3c02005-01-24 03:07:46 +00001142 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001143 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1144 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 ecc_failed++;
1146 }
1147 } else {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001148 chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
1154 /* read oobdata */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001155 chip->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
1158 if (!compareecc)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001159 goto readoob;
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 /* Pick the ECC bytes out of the oob data */
1162 for (j = 0; j < oobsel->eccbytes; j++)
1163 ecc_code[j] = oob_data[oob_config[j]];
1164
David Woodhousee0c7d762006-05-13 18:07:53 +01001165 /* correct data, if necessary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001166 for (i = 0, j = 0, datidx = 0; i < chip->ecc.steps; i++, datidx += ecc) {
1167 ecc_status = chip->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 /* Get next chunk of ecc bytes */
1170 j += eccbytes;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001171
1172 /* Check, if we have a fs supplied oob-buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 * This is the legacy mode. Used by YAFFS1
1174 * Should go away some day
1175 */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001176 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 int *p = (int *)(&oob_data[mtd->oobsize]);
1178 p[i] = ecc_status;
1179 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001180
1181 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001182 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 ecc_failed++;
1184 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
David Woodhousee0c7d762006-05-13 18:07:53 +01001187 readoob:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 /* check, if we have a fs supplied oob-buffer */
1189 if (oob_buf) {
1190 /* without autoplace. Legacy mode used by YAFFS1 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001191 switch (oobsel->useecc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 case MTD_NANDECC_AUTOPLACE:
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001193 case MTD_NANDECC_AUTOPL_USR:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 /* Walk through the autoplace chunks */
Dan Brown82e1d192005-04-06 21:13:09 +01001195 for (i = 0; oobsel->oobfree[i][1]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 int from = oobsel->oobfree[i][0];
1197 int num = oobsel->oobfree[i][1];
1198 memcpy(&oob_buf[oob], &oob_data[from], num);
Dan Brown82e1d192005-04-06 21:13:09 +01001199 oob += num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 break;
1202 case MTD_NANDECC_PLACE:
1203 /* YAFFS1 legacy mode */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001204 oob_data += chip->ecc.steps * sizeof(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 default:
1206 oob_data += mtd->oobsize;
1207 }
1208 }
1209 readdata:
1210 /* Partial page read, transfer data into fs buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001211 if (!aligned) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 for (j = col; j < end && read < len; j++)
1213 buf[read++] = data_poi[j];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001214 chip->pagebuf = realpage;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001215 } else
Joern Engel28318772006-05-22 23:18:05 +02001216 read += mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001218 /* Apply delay or wait for ready/busy pin
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 * Do this before the AUTOINCR check, so no problems
1220 * arise if a chip which does auto increment
1221 * is marked as NOAUTOINCR by the board driver.
David Woodhousee0c7d762006-05-13 18:07:53 +01001222 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001223 if (!chip->dev_ready)
1224 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001226 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (read == len)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001229 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
1231 /* For subsequent reads align to page boundary. */
1232 col = 0;
1233 /* Increment page address */
1234 realpage++;
1235
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001236 page = realpage & chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 /* Check, if we cross a chip boundary */
1238 if (!page) {
1239 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001240 chip->select_chip(mtd, -1);
1241 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001243 /* Check, if the chip supports auto page increment
1244 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001245 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001246 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001247 sndcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
1249
1250 /* Deselect and wake up anyone waiting on the device */
David A. Marlin068e3c02005-01-24 03:07:46 +00001251 if (flags & NAND_GET_DEVICE)
1252 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 /*
1255 * Return success, if no ECC failures, else -EBADMSG
1256 * fs driver will take care of that, because
1257 * retlen == desired len and result == -EBADMSG
1258 */
1259 *retlen = read;
1260 return ecc_failed ? -EBADMSG : 0;
1261}
1262
1263/**
1264 * nand_read_oob - [MTD Interface] NAND read out-of-band
1265 * @mtd: MTD device structure
1266 * @from: offset to read from
1267 * @len: number of bytes to read
1268 * @retlen: pointer to variable to store the number of read bytes
1269 * @buf: the databuffer to put data
1270 *
1271 * NAND read out-of-band data from the spare area
1272 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001273static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
1275 int i, col, page, chipnr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001276 struct nand_chip *chip = mtd->priv;
1277 int blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
David Woodhousee0c7d762006-05-13 18:07:53 +01001279 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 -07001280
1281 /* Shift to get page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001282 page = (int)(from >> chip->page_shift);
1283 chipnr = (int)(from >> chip->chip_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 /* Mask to get column */
1286 col = from & (mtd->oobsize - 1);
1287
1288 /* Initialize return length value */
1289 *retlen = 0;
1290
1291 /* Do not allow reads past end of device */
1292 if ((from + len) > mtd->size) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001293 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 *retlen = 0;
1295 return -EINVAL;
1296 }
1297
1298 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001299 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001302 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304 /* Send the read command */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001305 chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page & chip->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001306 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 * Read the data, if we read more than one page
1308 * oob data, let the device transfer the data !
1309 */
1310 i = 0;
1311 while (i < len) {
1312 int thislen = mtd->oobsize - col;
1313 thislen = min_t(int, thislen, len);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001314 chip->read_buf(mtd, &buf[i], thislen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 i += thislen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
1317 /* Read more ? */
1318 if (i < len) {
1319 page++;
1320 col = 0;
1321
1322 /* Check, if we cross a chip boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001323 if (!(page & chip->pagemask)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001325 chip->select_chip(mtd, -1);
1326 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001328
1329 /* Apply delay or wait for ready/busy pin
Thomas Gleixner19870da2005-07-15 14:53:51 +01001330 * Do this before the AUTOINCR check, so no problems
1331 * arise if a chip which does auto increment
1332 * is marked as NOAUTOINCR by the board driver.
1333 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001334 if (!chip->dev_ready)
1335 udelay(chip->chip_delay);
Thomas Gleixner19870da2005-07-15 14:53:51 +01001336 else
1337 nand_wait_ready(mtd);
1338
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001339 /* Check, if the chip supports auto page increment
1340 * or if we have hit a block boundary.
David Woodhousee0c7d762006-05-13 18:07:53 +01001341 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001342 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 /* For subsequent page reads set offset to 0 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001344 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
1346 }
1347 }
1348
1349 /* Deselect and wake up anyone waiting on the device */
1350 nand_release_device(mtd);
1351
1352 /* Return happy */
1353 *retlen = len;
1354 return 0;
1355}
1356
1357/**
1358 * nand_read_raw - [GENERIC] Read raw data including oob into buffer
1359 * @mtd: MTD device structure
1360 * @buf: temporary buffer
1361 * @from: offset to read from
1362 * @len: number of bytes to read
1363 * @ooblen: number of oob data bytes to read
1364 *
1365 * Read raw data including oob into buffer
1366 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001367int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
1368 size_t ooblen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001370 struct nand_chip *chip = mtd->priv;
1371 int page = (int)(from >> chip->page_shift);
1372 int chipnr = (int)(from >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 int sndcmd = 1;
1374 int cnt = 0;
Joern Engel28318772006-05-22 23:18:05 +02001375 int pagesize = mtd->writesize + mtd->oobsize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001376 int blockcheck;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 /* Do not allow reads past end of device */
1379 if ((from + len) > mtd->size) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001380 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: "
1381 "Attempt read beyond end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return -EINVAL;
1383 }
1384
1385 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001386 nand_get_device(chip, mtd, FL_READING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001388 chip->select_chip(mtd, chipnr);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 /* Add requested oob length */
1391 len += ooblen;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001392 blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 while (len) {
1395 if (sndcmd)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001396 chip->cmdfunc(mtd, NAND_CMD_READ0, 0,
1397 page & chip->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001398 sndcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001400 chip->read_buf(mtd, &buf[cnt], pagesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 len -= pagesize;
1403 cnt += pagesize;
1404 page++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001405
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001406 if (!chip->dev_ready)
1407 udelay(chip->chip_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 else
Thomas Gleixner3b887752005-02-22 21:56:49 +00001409 nand_wait_ready(mtd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001410
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001411 /*
1412 * Check, if the chip supports auto page increment or if we
1413 * cross a block boundary.
1414 */
1415 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 sndcmd = 1;
1417 }
1418
1419 /* Deselect and wake up anyone waiting on the device */
1420 nand_release_device(mtd);
1421 return 0;
1422}
1423
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001424/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001425 * nand_write_raw - [GENERIC] Write raw data including oob
1426 * @mtd: MTD device structure
1427 * @buf: source buffer
1428 * @to: offset to write to
1429 * @len: number of bytes to write
1430 * @buf: source buffer
1431 * @oob: oob buffer
1432 *
1433 * Write raw data including oob
1434 */
1435int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
1436 uint8_t *buf, uint8_t *oob)
1437{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001438 struct nand_chip *chip = mtd->priv;
1439 int page = (int)(to >> chip->page_shift);
1440 int chipnr = (int)(to >> chip->chip_shift);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001441 int ret;
1442
1443 *retlen = 0;
1444
1445 /* Do not allow writes past end of device */
1446 if ((to + len) > mtd->size) {
1447 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
1448 "beyond end of device\n");
1449 return -EINVAL;
1450 }
1451
1452 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001453 nand_get_device(chip, mtd, FL_WRITING);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001454
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001455 chip->select_chip(mtd, chipnr);
1456 chip->data_poi = buf;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001457
1458 while (len != *retlen) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001459 ret = nand_write_page(mtd, chip, page, oob, &mtd->oobinfo, 0);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001460 if (ret)
1461 return ret;
1462 page++;
1463 *retlen += mtd->writesize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001464 chip->data_poi += mtd->writesize;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001465 oob += mtd->oobsize;
1466 }
1467
1468 /* Deselect and wake up anyone waiting on the device */
1469 nand_release_device(mtd);
1470 return 0;
1471}
Thomas Gleixner38217202006-05-23 22:33:52 +02001472EXPORT_SYMBOL_GPL(nand_write_raw);
Thomas Gleixner9223a452006-05-23 17:21:03 +02001473
1474/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001475 * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 * @mtd: MTD device structure
1477 * @fsbuf: buffer given by fs driver
1478 * @oobsel: out of band selection structre
1479 * @autoplace: 1 = place given buffer into the oob bytes
1480 * @numpages: number of pages to prepare
1481 *
1482 * Return:
1483 * 1. Filesystem buffer available and autoplacement is off,
1484 * return filesystem buffer
1485 * 2. No filesystem buffer or autoplace is off, return internal
1486 * buffer
1487 * 3. Filesystem buffer is given and autoplace selected
1488 * put data from fs buffer into internal buffer and
1489 * retrun internal buffer
1490 *
1491 * Note: The internal buffer is filled with 0xff. This must
1492 * be done only once, when no autoplacement happens
1493 * Autoplacement sets the buffer dirty flag, which
1494 * forces the 0xff fill before using the buffer again.
1495 *
1496*/
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001497static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
David Woodhousee0c7d762006-05-13 18:07:53 +01001498 int autoplace, int numpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001500 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 int i, len, ofs;
1502
1503 /* Zero copy fs supplied buffer */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001504 if (fsbuf && !autoplace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return fsbuf;
1506
1507 /* Check, if the buffer must be filled with ff again */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001508 if (chip->oobdirty) {
1509 memset(chip->oob_buf, 0xff, mtd->oobsize << (chip->phys_erase_shift - chip->page_shift));
1510 chip->oobdirty = 0;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001511 }
1512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 /* If we have no autoplacement or no fs buffer use the internal one */
1514 if (!autoplace || !fsbuf)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001515 return chip->oob_buf;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 /* Walk through the pages and place the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001518 chip->oobdirty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 ofs = 0;
1520 while (numpages--) {
1521 for (i = 0, len = 0; len < mtd->oobavail; i++) {
1522 int to = ofs + oobsel->oobfree[i][0];
1523 int num = oobsel->oobfree[i][1];
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001524 memcpy(&chip->oob_buf[to], fsbuf, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 len += num;
1526 fsbuf += num;
1527 }
1528 ofs += mtd->oobavail;
1529 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001530 return chip->oob_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531}
1532
Joern Engel28318772006-05-22 23:18:05 +02001533#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535/**
Thomas Gleixner9223a452006-05-23 17:21:03 +02001536 * nand_write - [MTD Interface] NAND write with ECC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 * @mtd: MTD device structure
1538 * @to: offset to write to
1539 * @len: number of bytes to write
1540 * @retlen: pointer to variable to store the number of written bytes
1541 * @buf: the data to write
1542 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 * NAND write with ECC
1544 */
Thomas Gleixner9223a452006-05-23 17:21:03 +02001545static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1546 size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
1549 int autoplace = 0, numpages, totalpages;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001550 struct nand_chip *chip = mtd->priv;
Thomas Gleixner9223a452006-05-23 17:21:03 +02001551 uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001552 int ppblock = (1 << (chip->phys_erase_shift - chip->page_shift));
Thomas Gleixner9223a452006-05-23 17:21:03 +02001553 struct nand_oobinfo *oobsel = &mtd->oobinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Thomas Gleixner9223a452006-05-23 17:21:03 +02001555 DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 /* Initialize retlen, in case of early exit */
1558 *retlen = 0;
1559
1560 /* Do not allow write past end of device */
1561 if ((to + len) > mtd->size) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001562 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 return -EINVAL;
1564 }
1565
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001566 /* reject writes, which are not page aligned */
David Woodhousee0c7d762006-05-13 18:07:53 +01001567 if (NOTALIGNED(to) || NOTALIGNED(len)) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001568 printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 return -EINVAL;
1570 }
1571
1572 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001573 nand_get_device(chip, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /* Calculate chipnr */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001576 chipnr = (int)(to >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001578 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580 /* Check, if it is write protected */
1581 if (nand_check_wp(mtd))
1582 goto out;
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 /* Autoplace of oob data ? Use the default placement scheme */
1585 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001586 oobsel = chip->autooob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 autoplace = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001588 }
Thomas Gleixner90e260c2005-05-19 17:10:26 +01001589 if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1590 autoplace = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 /* Setup variables and oob buffer */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001593 totalpages = len >> chip->page_shift;
1594 page = (int)(to >> chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001596 if (page <= chip->pagebuf && chip->pagebuf < (page + totalpages))
1597 chip->pagebuf = -1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 /* Set it relative to chip */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001600 page &= chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 startpage = page;
1602 /* Calc number of pages we can write in one go */
David Woodhousee0c7d762006-05-13 18:07:53 +01001603 numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
1604 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001605 bufstart = (uint8_t *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 /* Loop until all data is written */
1608 while (written < len) {
1609
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001610 chip->data_poi = (uint8_t *) &buf[written];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 /* Write one page. If this is the last page to write
1612 * or the last page in this block, then use the
1613 * real pageprogram command, else select cached programming
1614 * if supported by the chip.
1615 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001616 ret = nand_write_page(mtd, chip, page, &oobbuf[oob], oobsel, (--numpages > 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001618 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* Next oob page */
1622 oob += mtd->oobsize;
1623 /* Update written bytes count */
Joern Engel28318772006-05-22 23:18:05 +02001624 written += mtd->writesize;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001625 if (written == len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 goto cmp;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* Increment page address */
1629 page++;
1630
1631 /* Have we hit a block boundary ? Then we have to verify and
1632 * if verify is ok, we have to setup the oob buffer for
1633 * the next pages.
David Woodhousee0c7d762006-05-13 18:07:53 +01001634 */
1635 if (!(page & (ppblock - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 int ofs;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001637 chip->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001638 ret = nand_verify_pages(mtd, this, startpage, page - startpage,
1639 oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (ret) {
Thomas Gleixner9223a452006-05-23 17:21:03 +02001641 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 *retlen = written;
1645
1646 ofs = autoplace ? mtd->oobavail : mtd->oobsize;
1647 if (eccbuf)
1648 eccbuf += (page - startpage) * ofs;
1649 totalpages -= page - startpage;
David Woodhousee0c7d762006-05-13 18:07:53 +01001650 numpages = min(totalpages, ppblock);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001651 page &= chip->pagemask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 startpage = page;
David Woodhousee0c7d762006-05-13 18:07:53 +01001653 oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
Todd Poynor868801e2005-11-05 03:21:15 +00001654 oob = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* Check, if we cross a chip boundary */
1656 if (!page) {
1657 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001658 chip->select_chip(mtd, -1);
1659 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
1661 }
1662 }
1663 /* Verify the remaining pages */
David Woodhousee0c7d762006-05-13 18:07:53 +01001664 cmp:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001665 chip->data_poi = bufstart;
David Woodhousee0c7d762006-05-13 18:07:53 +01001666 ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 if (!ret)
1668 *retlen = written;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001669 else
Thomas Gleixner9223a452006-05-23 17:21:03 +02001670 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
David Woodhousee0c7d762006-05-13 18:07:53 +01001672 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Deselect and wake up anyone waiting on the device */
1674 nand_release_device(mtd);
1675
1676 return ret;
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679/**
1680 * nand_write_oob - [MTD Interface] NAND write out-of-band
1681 * @mtd: MTD device structure
1682 * @to: offset to write to
1683 * @len: number of bytes to write
1684 * @retlen: pointer to variable to store the number of written bytes
1685 * @buf: the data to write
1686 *
1687 * NAND write out-of-band
1688 */
Thomas Gleixner58dd8f2b2006-05-23 11:52:35 +02001689static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690{
1691 int column, page, status, ret = -EIO, chipnr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001692 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
David Woodhousee0c7d762006-05-13 18:07:53 +01001694 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 -07001695
1696 /* Shift to get page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001697 page = (int)(to >> chip->page_shift);
1698 chipnr = (int)(to >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 /* Mask to get column */
1701 column = to & (mtd->oobsize - 1);
1702
1703 /* Initialize return length value */
1704 *retlen = 0;
1705
1706 /* Do not allow write past end of page */
1707 if ((column + len) > mtd->oobsize) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001708 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 return -EINVAL;
1710 }
1711
1712 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001713 nand_get_device(chip, mtd, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001716 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718 /* Reset the chip. Some chips (like the Toshiba TC5832DC found
1719 in one of my DiskOnChip 2000 test units) will clear the whole
1720 data page too if we don't do this. I have no clue why, but
1721 I seem to have 'fixed' it in the doc2000 driver in
1722 August 1999. dwmw2. */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001723 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 /* Check, if it is write protected */
1726 if (nand_check_wp(mtd))
1727 goto out;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* Invalidate the page cache, if we write to the cached page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001730 if (page == chip->pagebuf)
1731 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001733 if (NAND_MUST_PAD(chip)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* Write out desired data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001735 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 /* prepad 0xff for partial programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001737 chip->write_buf(mtd, ffchars, column);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 /* write data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001739 chip->write_buf(mtd, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 /* postpad 0xff for partial programming */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001741 chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 } else {
1743 /* Write out desired data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001744 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* write data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001746 chip->write_buf(mtd, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
1748 /* Send command to program the OOB data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001749 chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001751 status = chip->waitfunc(mtd, chip, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753 /* See if device thinks it succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001754 if (status & NAND_STATUS_FAIL) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001755 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 ret = -EIO;
1757 goto out;
1758 }
1759 /* Return happy */
1760 *retlen = len;
1761
1762#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1763 /* Send command to read back the data */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001764 chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001766 if (chip->verify_buf(mtd, buf, len)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001767 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 ret = -EIO;
1769 goto out;
1770 }
1771#endif
1772 ret = 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01001773 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 /* Deselect and wake up anyone waiting on the device */
1775 nand_release_device(mtd);
1776
1777 return ret;
1778}
1779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 * single_erease_cmd - [GENERIC] NAND standard block erase command function
1782 * @mtd: MTD device structure
1783 * @page: the page address of the block which will be erased
1784 *
1785 * Standard erase command for NAND chips
1786 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001787static void single_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001789 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 /* Send commands to erase a block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001791 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1792 chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793}
1794
1795/**
1796 * multi_erease_cmd - [GENERIC] AND specific block erase command function
1797 * @mtd: MTD device structure
1798 * @page: the page address of the block which will be erased
1799 *
1800 * AND multi block erase command function
1801 * Erase 4 consecutive blocks
1802 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001803static void multi_erase_cmd(struct mtd_info *mtd, int page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001805 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 /* Send commands to erase a block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001807 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1808 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1809 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
1810 chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
1811 chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
1814/**
1815 * nand_erase - [MTD Interface] erase block(s)
1816 * @mtd: MTD device structure
1817 * @instr: erase instruction
1818 *
1819 * Erase one ore more blocks
1820 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001821static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822{
David Woodhousee0c7d762006-05-13 18:07:53 +01001823 return nand_erase_nand(mtd, instr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824}
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001825
David A. Marlin30f464b2005-01-17 18:35:25 +00001826#define BBT_PAGE_MASK 0xffffff3f
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001828 * nand_erase_nand - [Internal] erase block(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 * @mtd: MTD device structure
1830 * @instr: erase instruction
1831 * @allowbbt: allow erasing the bbt area
1832 *
1833 * Erase one ore more blocks
1834 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001835int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
1836 int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837{
1838 int page, len, status, pages_per_block, ret, chipnr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001839 struct nand_chip *chip = mtd->priv;
1840 int rewrite_bbt[NAND_MAX_CHIPS]={0};
1841 unsigned int bbt_masked_page = 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001843 DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
1844 (unsigned int)instr->addr, (unsigned int)instr->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 /* Start address must align on block boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001847 if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001848 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 return -EINVAL;
1850 }
1851
1852 /* Length must align on block boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001853 if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
1854 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1855 "Length not block aligned\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 return -EINVAL;
1857 }
1858
1859 /* Do not allow erase past end of device */
1860 if ((instr->len + instr->addr) > mtd->size) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001861 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1862 "Erase past end of device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 return -EINVAL;
1864 }
1865
1866 instr->fail_addr = 0xffffffff;
1867
1868 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001869 nand_get_device(chip, mtd, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 /* Shift to get first page */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001872 page = (int)(instr->addr >> chip->page_shift);
1873 chipnr = (int)(instr->addr >> chip->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 /* Calculate pages in each block */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001876 pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
1878 /* Select the NAND device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001879 chip->select_chip(mtd, chipnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 /* Check, if it is write protected */
1882 if (nand_check_wp(mtd)) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001883 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1884 "Device is write protected!!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 instr->state = MTD_ERASE_FAILED;
1886 goto erase_exit;
1887 }
1888
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001889 /*
1890 * If BBT requires refresh, set the BBT page mask to see if the BBT
1891 * should be rewritten. Otherwise the mask is set to 0xffffffff which
1892 * can not be matched. This is also done when the bbt is actually
1893 * erased to avoid recusrsive updates
1894 */
1895 if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
1896 bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
David A. Marlin30f464b2005-01-17 18:35:25 +00001897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 /* Loop through the pages */
1899 len = instr->len;
1900
1901 instr->state = MTD_ERASING;
1902
1903 while (len) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001904 /*
1905 * heck if we have a bad block, we do not erase bad blocks !
1906 */
1907 if (nand_block_checkbad(mtd, ((loff_t) page) <<
1908 chip->page_shift, 0, allowbbt)) {
1909 printk(KERN_WARNING "nand_erase: attempt to erase a "
1910 "bad block at page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 instr->state = MTD_ERASE_FAILED;
1912 goto erase_exit;
1913 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001914
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001915 /*
1916 * Invalidate the page cache, if we erase the block which
1917 * contains the current cached page
1918 */
1919 if (page <= chip->pagebuf && chip->pagebuf <
1920 (page + pages_per_block))
1921 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001923 chip->erase_cmd(mtd, page & chip->pagemask);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001924
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001925 status = chip->waitfunc(mtd, chip, FL_ERASING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001927 /*
1928 * See if operation failed and additional status checks are
1929 * available
1930 */
1931 if ((status & NAND_STATUS_FAIL) && (chip->errstat))
1932 status = chip->errstat(mtd, chip, FL_ERASING,
1933 status, page);
David A. Marlin068e3c02005-01-24 03:07:46 +00001934
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 /* See if block erase succeeded */
David A. Marlina4ab4c52005-01-23 18:30:53 +00001936 if (status & NAND_STATUS_FAIL) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001937 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
1938 "Failed erase, page 0x%08x\n", page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 instr->state = MTD_ERASE_FAILED;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001940 instr->fail_addr = (page << chip->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 goto erase_exit;
1942 }
David A. Marlin30f464b2005-01-17 18:35:25 +00001943
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001944 /*
1945 * If BBT requires refresh, set the BBT rewrite flag to the
1946 * page being erased
1947 */
1948 if (bbt_masked_page != 0xffffffff &&
1949 (page & BBT_PAGE_MASK) == bbt_masked_page)
1950 rewrite_bbt[chipnr] = (page << chip->page_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 /* Increment page address and decrement length */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001953 len -= (1 << chip->phys_erase_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 page += pages_per_block;
1955
1956 /* Check, if we cross a chip boundary */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001957 if (len && !(page & chip->pagemask)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 chipnr++;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001959 chip->select_chip(mtd, -1);
1960 chip->select_chip(mtd, chipnr);
David A. Marlin30f464b2005-01-17 18:35:25 +00001961
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001962 /*
1963 * If BBT requires refresh and BBT-PERCHIP, set the BBT
1964 * page mask to see if this BBT should be rewritten
1965 */
1966 if (bbt_masked_page != 0xffffffff &&
1967 (chip->bbt_td->options & NAND_BBT_PERCHIP))
1968 bbt_masked_page = chip->bbt_td->pages[chipnr] &
1969 BBT_PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
1972 instr->state = MTD_ERASE_DONE;
1973
David Woodhousee0c7d762006-05-13 18:07:53 +01001974 erase_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
1976 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1977 /* Do call back function */
1978 if (!ret)
1979 mtd_erase_callback(instr);
1980
1981 /* Deselect and wake up anyone waiting on the device */
1982 nand_release_device(mtd);
1983
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02001984 /*
1985 * If BBT requires refresh and erase was successful, rewrite any
1986 * selected bad block tables
1987 */
1988 if (bbt_masked_page == 0xffffffff || ret)
1989 return ret;
1990
1991 for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
1992 if (!rewrite_bbt[chipnr])
1993 continue;
1994 /* update the BBT for chip */
1995 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
1996 "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
1997 chip->bbt_td->pages[chipnr]);
1998 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
David A. Marlin30f464b2005-01-17 18:35:25 +00001999 }
2000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 /* Return more or less happy */
2002 return ret;
2003}
2004
2005/**
2006 * nand_sync - [MTD Interface] sync
2007 * @mtd: MTD device structure
2008 *
2009 * Sync is actually a wait for chip ready function
2010 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002011static void nand_sync(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002013 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
David Woodhousee0c7d762006-05-13 18:07:53 +01002015 DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
2017 /* Grab the lock and see if the device is available */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002018 nand_get_device(chip, mtd, FL_SYNCING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 /* Release it and go back */
David Woodhousee0c7d762006-05-13 18:07:53 +01002020 nand_release_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021}
2022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002024 * nand_block_isbad - [MTD Interface] Check if block at offset is bad
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 * @mtd: MTD device structure
2026 * @ofs: offset relative to mtd start
2027 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002028static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
2030 /* Check for invalid offset */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002031 if (offs > mtd->size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 return -EINVAL;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002033
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002034 return nand_block_checkbad(mtd, offs, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035}
2036
2037/**
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002038 * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 * @mtd: MTD device structure
2040 * @ofs: offset relative to mtd start
2041 */
David Woodhousee0c7d762006-05-13 18:07:53 +01002042static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002044 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 int ret;
2046
David Woodhousee0c7d762006-05-13 18:07:53 +01002047 if ((ret = nand_block_isbad(mtd, ofs))) {
2048 /* If it was bad already, return success and do nothing. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 if (ret > 0)
2050 return 0;
David Woodhousee0c7d762006-05-13 18:07:53 +01002051 return ret;
2052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002054 return chip->block_markbad(mtd, ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055}
2056
2057/**
Vitaly Wool962034f2005-09-15 14:58:53 +01002058 * nand_suspend - [MTD Interface] Suspend the NAND flash
2059 * @mtd: MTD device structure
2060 */
2061static int nand_suspend(struct mtd_info *mtd)
2062{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002063 struct nand_chip *chip = mtd->priv;
Vitaly Wool962034f2005-09-15 14:58:53 +01002064
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002065 return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
Vitaly Wool962034f2005-09-15 14:58:53 +01002066}
2067
2068/**
2069 * nand_resume - [MTD Interface] Resume the NAND flash
2070 * @mtd: MTD device structure
2071 */
2072static void nand_resume(struct mtd_info *mtd)
2073{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002074 struct nand_chip *chip = mtd->priv;
Vitaly Wool962034f2005-09-15 14:58:53 +01002075
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002076 if (chip->state == FL_PM_SUSPENDED)
Vitaly Wool962034f2005-09-15 14:58:53 +01002077 nand_release_device(mtd);
2078 else
Thomas Gleixner2c0a2be2006-05-23 11:50:56 +02002079 printk(KERN_ERR "nand_resume() called for a chip which is not "
2080 "in suspended state\n");
Vitaly Wool962034f2005-09-15 14:58:53 +01002081}
2082
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002083/*
2084 * Free allocated data structures
2085 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002086static void nand_free_kmem(struct nand_chip *chip)
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002087{
2088 /* Buffer allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002089 if (chip->options & NAND_OOBBUF_ALLOC)
2090 kfree(chip->oob_buf);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002091 /* Buffer allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002092 if (chip->options & NAND_DATABUF_ALLOC)
2093 kfree(chip->data_buf);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002094 /* Controller allocated by nand_scan ? */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002095 if (chip->options & NAND_CONTROLLER_ALLOC)
2096 kfree(chip->controller);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002097}
2098
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002099/*
2100 * Allocate buffers and data structures
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002102static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *chip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002104 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002106 if (!chip->oob_buf) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002107 len = mtd->oobsize <<
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002108 (chip->phys_erase_shift - chip->page_shift);
2109 chip->oob_buf = kmalloc(len, GFP_KERNEL);
2110 if (!chip->oob_buf)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002111 goto outerr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002112 chip->options |= NAND_OOBBUF_ALLOC;
David Woodhouse552d9202006-05-14 01:20:46 +01002113 }
2114
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002115 if (!chip->data_buf) {
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002116 len = mtd->writesize + mtd->oobsize;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002117 chip->data_buf = kmalloc(len, GFP_KERNEL);
2118 if (!chip->data_buf)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002119 goto outerr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002120 chip->options |= NAND_DATABUF_ALLOC;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002123 if (!chip->controller) {
2124 chip->controller = kzalloc(sizeof(struct nand_hw_control),
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002125 GFP_KERNEL);
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002126 if (!chip->controller)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002127 goto outerr;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002128 chip->options |= NAND_CONTROLLER_ALLOC;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002129 }
2130 return 0;
2131
2132 outerr:
2133 printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002134 nand_free_kmem(chip);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002135 return -ENOMEM;
2136}
2137
2138/*
2139 * Set default functions
2140 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002141static void nand_set_defaults(struct nand_chip *chip, int busw)
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002142{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 /* check for proper chip_delay setup, set 20us if not */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002144 if (!chip->chip_delay)
2145 chip->chip_delay = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
2147 /* check, if a user supplied command function given */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002148 if (chip->cmdfunc == NULL)
2149 chip->cmdfunc = nand_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
2151 /* check, if a user supplied wait function given */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002152 if (chip->waitfunc == NULL)
2153 chip->waitfunc = nand_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002155 if (!chip->select_chip)
2156 chip->select_chip = nand_select_chip;
2157 if (!chip->read_byte)
2158 chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
2159 if (!chip->read_word)
2160 chip->read_word = nand_read_word;
2161 if (!chip->block_bad)
2162 chip->block_bad = nand_block_bad;
2163 if (!chip->block_markbad)
2164 chip->block_markbad = nand_default_block_markbad;
2165 if (!chip->write_buf)
2166 chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
2167 if (!chip->read_buf)
2168 chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
2169 if (!chip->verify_buf)
2170 chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
2171 if (!chip->scan_bbt)
2172 chip->scan_bbt = nand_default_bbt;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002173}
2174
2175/*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002176 * Get the flash and manufacturer id and lookup if the type is supported
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002177 */
2178static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002179 struct nand_chip *chip,
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002180 int busw, int *maf_id)
2181{
2182 struct nand_flash_dev *type = NULL;
2183 int i, dev_id, maf_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
2185 /* Select the device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002186 chip->select_chip(mtd, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
2188 /* Send the command for reading device ID */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002189 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
2191 /* Read manufacturer and device IDs */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002192 *maf_id = chip->read_byte(mtd);
2193 dev_id = chip->read_byte(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002195 /* Lookup the flash id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002197 if (dev_id == nand_flash_ids[i].id) {
2198 type = &nand_flash_ids[i];
2199 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 }
2202
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002203 if (!type)
2204 return ERR_PTR(-ENODEV);
2205
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002206 chip->chipsize = nand_flash_ids[i].chipsize << 20;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002207
2208 /* Newer devices have all the information in additional id bytes */
2209 if (!nand_flash_ids[i].pagesize) {
2210 int extid;
2211 /* The 3rd id byte contains non relevant data ATM */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002212 extid = chip->read_byte(mtd);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002213 /* The 4th id byte is the important one */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002214 extid = chip->read_byte(mtd);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002215 /* Calc pagesize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002216 mtd->writesize = 1024 << (extid & 0x3);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002217 extid >>= 2;
2218 /* Calc oobsize */
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002219 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002220 extid >>= 2;
2221 /* Calc blocksize. Blocksize is multiples of 64KiB */
2222 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2223 extid >>= 2;
2224 /* Get buswidth information */
2225 busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
2226
2227 } else {
2228 /*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002229 * Old devices have chip data hardcoded in the device id table
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002230 */
2231 mtd->erasesize = nand_flash_ids[i].erasesize;
Thomas Gleixner4cbb9b82006-05-23 12:37:31 +02002232 mtd->writesize = nand_flash_ids[i].pagesize;
2233 mtd->oobsize = mtd->writesize / 32;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002234 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
2235 }
2236
2237 /* Try to identify manufacturer */
2238 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
2239 if (nand_manuf_ids[maf_idx].id == *maf_id)
2240 break;
2241 }
2242
2243 /*
2244 * Check, if buswidth is correct. Hardware drivers should set
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002245 * chip correct !
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002246 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002247 if (busw != (chip->options & NAND_BUSWIDTH_16)) {
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002248 printk(KERN_INFO "NAND device: Manufacturer ID:"
2249 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2250 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2251 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002252 (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002253 busw ? 16 : 8);
2254 return ERR_PTR(-EINVAL);
2255 }
2256
2257 /* Calculate the address shift from the page size */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002258 chip->page_shift = ffs(mtd->writesize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002259 /* Convert chipsize to number of pages per chip -1. */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002260 chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002261
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002262 chip->bbt_erase_shift = chip->phys_erase_shift =
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002263 ffs(mtd->erasesize) - 1;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002264 chip->chip_shift = ffs(chip->chipsize) - 1;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002265
2266 /* Set the bad block position */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002267 chip->badblockpos = mtd->writesize > 512 ?
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002268 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2269
2270 /* Get chip options, preserve non chip based options */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002271 chip->options &= ~NAND_CHIPOPTIONS_MSK;
2272 chip->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002273
2274 /*
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002275 * Set chip as a default. Board drivers can override it, if necessary
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002276 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002277 chip->options |= NAND_NO_AUTOINCR;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002278
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002279 /* Check if chip is a not a samsung device. Do not clear the
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002280 * options for chips which are not having an extended id.
2281 */
2282 if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002283 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002284
2285 /* Check for AND chips with 4 page planes */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002286 if (chip->options & NAND_4PAGE_ARRAY)
2287 chip->erase_cmd = multi_erase_cmd;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002288 else
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002289 chip->erase_cmd = single_erase_cmd;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002290
2291 /* Do not replace user supplied command function ! */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002292 if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
2293 chip->cmdfunc = nand_command_lp;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002294
2295 printk(KERN_INFO "NAND device: Manufacturer ID:"
2296 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2297 nand_manuf_ids[maf_idx].name, type->name);
2298
2299 return type;
2300}
2301
2302/* module_text_address() isn't exported, and it's mostly a pointless
2303 test if this is a module _anyway_ -- they'd have to try _really_ hard
2304 to call us from in-kernel code if the core NAND support is modular. */
2305#ifdef MODULE
2306#define caller_is_module() (1)
2307#else
2308#define caller_is_module() \
2309 module_text_address((unsigned long)__builtin_return_address(0))
2310#endif
2311
2312/**
2313 * nand_scan - [NAND Interface] Scan for the NAND device
2314 * @mtd: MTD device structure
2315 * @maxchips: Number of chips to scan for
2316 *
2317 * This fills out all the uninitialized function pointers
2318 * with the defaults.
2319 * The flash ID is read and the mtd/chip structures are
2320 * filled with the appropriate values. Buffers are allocated if
2321 * they are not provided by the board driver
2322 * The mtd->owner field must be set to the module of the caller
2323 *
2324 */
2325int nand_scan(struct mtd_info *mtd, int maxchips)
2326{
2327 int i, busw, nand_maf_id;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002328 struct nand_chip *chip = mtd->priv;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002329 struct nand_flash_dev *type;
2330
2331 /* Many callers got this wrong, so check for it for a while... */
2332 if (!mtd->owner && caller_is_module()) {
2333 printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
2334 BUG();
2335 }
2336
2337 /* Get buswidth to select the correct functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002338 busw = chip->options & NAND_BUSWIDTH_16;
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002339 /* Set the default functions */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002340 nand_set_defaults(chip, busw);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002341
2342 /* Read the flash type */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002343 type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002344
2345 if (IS_ERR(type)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01002346 printk(KERN_WARNING "No NAND device found!!!\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002347 chip->select_chip(mtd, -1);
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002348 return PTR_ERR(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 }
2350
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002351 /* Check for a chip array */
David Woodhousee0c7d762006-05-13 18:07:53 +01002352 for (i = 1; i < maxchips; i++) {
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002353 chip->select_chip(mtd, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 /* Send the command for reading device ID */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002355 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 /* Read manufacturer and device IDs */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002357 if (nand_maf_id != chip->read_byte(mtd) ||
2358 type->id != chip->read_byte(mtd))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 break;
2360 }
2361 if (i > 1)
2362 printk(KERN_INFO "%d NAND chips detected\n", i);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 /* Store the number of chips and calc total size for mtd */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002365 chip->numchips = i;
2366 mtd->size = i * chip->chipsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002368 /* Allocate buffers and data structures */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002369 if (nand_allocate_kmem(mtd, chip))
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002370 return -ENOMEM;
2371
2372 /* Preset the internal oob buffer */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002373 memset(chip->oob_buf, 0xff,
2374 mtd->oobsize << (chip->phys_erase_shift - chip->page_shift));
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002375
2376 /*
2377 * If no default placement scheme is given, select an appropriate one
2378 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002379 if (!chip->autooob) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002380 switch (mtd->oobsize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 case 8:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002382 chip->autooob = &nand_oob_8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 break;
2384 case 16:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002385 chip->autooob = &nand_oob_16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 break;
2387 case 64:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002388 chip->autooob = &nand_oob_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 break;
2390 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002391 printk(KERN_WARNING "No oob scheme defined for "
2392 "oobsize %d\n", mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 BUG();
2394 }
2395 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002396
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002397 /*
2398 * The number of bytes available for the filesystem to place fs
2399 * dependend oob data
2400 */
Thomas Gleixner998cf642005-04-01 08:21:48 +01002401 mtd->oobavail = 0;
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002402 for (i = 0; chip->autooob->oobfree[i][1]; i++)
2403 mtd->oobavail += chip->autooob->oobfree[i][1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002405 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002406 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2407 * selected and we have 256 byte pagesize fallback to software ECC
David Woodhousee0c7d762006-05-13 18:07:53 +01002408 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002409 switch (chip->ecc.mode) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002410 case NAND_ECC_HW:
2411 case NAND_ECC_HW_SYNDROME:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002412 if (!chip->ecc.calculate || !chip->ecc.correct ||
2413 !chip->ecc.hwctl) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002414 printk(KERN_WARNING "No ECC functions supplied, "
2415 "Hardware ECC not possible\n");
2416 BUG();
2417 }
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002418 if (mtd->writesize >= chip->ecc.size)
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002419 break;
2420 printk(KERN_WARNING "%d byte HW ECC not possible on "
2421 "%d byte page size, fallback to SW ECC\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002422 chip->ecc.size, mtd->writesize);
2423 chip->ecc.mode = NAND_ECC_SOFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002425 case NAND_ECC_SOFT:
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002426 chip->ecc.calculate = nand_calculate_ecc;
2427 chip->ecc.correct = nand_correct_data;
2428 chip->ecc.size = 256;
2429 chip->ecc.bytes = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 break;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002431
2432 case NAND_ECC_NONE:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002433 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2434 "This is not recommended !!\n");
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002435 chip->ecc.size = mtd->writesize;
2436 chip->ecc.bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 default:
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002439 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002440 chip->ecc.mode);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002441 BUG();
2442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002444 /*
Thomas Gleixner7aa65bf2006-05-23 11:54:38 +02002445 * Set the number of read / write steps for one page depending on ECC
2446 * mode
2447 */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002448 chip->ecc.steps = mtd->writesize / chip->ecc.size;
2449 if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
Thomas Gleixner6dfc6d22006-05-23 12:00:46 +02002450 printk(KERN_WARNING "Invalid ecc parameters\n");
2451 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 /* Initialize state, waitqueue and spinlock */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002455 chip->state = FL_READY;
2456 init_waitqueue_head(&chip->controller->wq);
2457 spin_lock_init(&chip->controller->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458
2459 /* De-select the device */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002460 chip->select_chip(mtd, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 /* Invalidate the pagebuffer reference */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002463 chip->pagebuf = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
2465 /* Fill in remaining MTD driver data */
2466 mtd->type = MTD_NANDFLASH;
Joern Engel5fa43392006-05-22 23:18:29 +02002467 mtd->flags = MTD_CAP_NANDFLASH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 mtd->ecctype = MTD_ECC_SW;
2469 mtd->erase = nand_erase;
2470 mtd->point = NULL;
2471 mtd->unpoint = NULL;
2472 mtd->read = nand_read;
2473 mtd->write = nand_write;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 mtd->read_oob = nand_read_oob;
2475 mtd->write_oob = nand_write_oob;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 mtd->sync = nand_sync;
2477 mtd->lock = NULL;
2478 mtd->unlock = NULL;
Vitaly Wool962034f2005-09-15 14:58:53 +01002479 mtd->suspend = nand_suspend;
2480 mtd->resume = nand_resume;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 mtd->block_isbad = nand_block_isbad;
2482 mtd->block_markbad = nand_block_markbad;
2483
2484 /* and make the autooob the default one */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002485 memcpy(&mtd->oobinfo, chip->autooob, sizeof(mtd->oobinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002487 /* Check, if we should skip the bad block table scan */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002488 if (chip->options & NAND_SKIP_BBTSCAN)
Thomas Gleixner0040bf32005-02-09 12:20:00 +00002489 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491 /* Build bad block table */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002492 return chip->scan_bbt(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493}
2494
2495/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00002496 * nand_release - [NAND Interface] Free resources held by the NAND device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 * @mtd: MTD device structure
2498*/
David Woodhousee0c7d762006-05-13 18:07:53 +01002499void nand_release(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500{
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002501 struct nand_chip *chip = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503#ifdef CONFIG_MTD_PARTITIONS
2504 /* Deregister partitions */
David Woodhousee0c7d762006-05-13 18:07:53 +01002505 del_mtd_partitions(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506#endif
2507 /* Deregister the device */
David Woodhousee0c7d762006-05-13 18:07:53 +01002508 del_mtd_device(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Jesper Juhlfa671642005-11-07 01:01:27 -08002510 /* Free bad block table memory */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002511 kfree(chip->bbt);
Thomas Gleixnera36ed292006-05-23 11:37:03 +02002512 /* Free buffers */
Thomas Gleixnerace4dfe2006-05-24 12:07:37 +02002513 nand_free_kmem(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514}
2515
David Woodhousee0c7d762006-05-13 18:07:53 +01002516EXPORT_SYMBOL_GPL(nand_scan);
2517EXPORT_SYMBOL_GPL(nand_release);
Richard Purdie8fe833c2006-03-31 02:31:14 -08002518
2519static int __init nand_base_init(void)
2520{
2521 led_trigger_register_simple("nand-disk", &nand_led_trigger);
2522 return 0;
2523}
2524
2525static void __exit nand_base_exit(void)
2526{
2527 led_trigger_unregister_simple(nand_led_trigger);
2528}
2529
2530module_init(nand_base_init);
2531module_exit(nand_base_exit);
2532
David Woodhousee0c7d762006-05-13 18:07:53 +01002533MODULE_LICENSE("GPL");
2534MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
2535MODULE_DESCRIPTION("Generic NAND flash driver code");