]>
Commit | Line | Data |
---|---|---|
932394ac WD |
1 | /* |
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. | |
ac7eb8a3 | 7 | * |
932394ac | 8 | * Additional technical information is available on |
c45912d8 | 9 | * http://www.linux-mtd.infradead.org/doc/nand.html |
ac7eb8a3 | 10 | * |
932394ac | 11 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
cfa460ad | 12 | * 2002-2006 Thomas Gleixner (tglx@linutronix.de) |
932394ac | 13 | * |
cfa460ad | 14 | * Credits: |
ac7eb8a3 WD |
15 | * David Woodhouse for adding multichip support |
16 | * | |
932394ac WD |
17 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the |
18 | * rework for 2K page size chips | |
19 | * | |
cfa460ad | 20 | * TODO: |
932394ac WD |
21 | * Enable cached programming for 2k page size chips |
22 | * Check, if mtd->ecctype should be set to MTD_ECC_HW | |
dfe64e2c | 23 | * if we have HW ECC support. |
c45912d8 | 24 | * BBT table is not serialized, has to be fixed |
932394ac | 25 | * |
932394ac WD |
26 | * This program is free software; you can redistribute it and/or modify |
27 | * it under the terms of the GNU General Public License version 2 as | |
28 | * published by the Free Software Foundation. | |
29 | * | |
30 | */ | |
31 | ||
ff94bc40 HS |
32 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
33 | #include <common.h> | |
932394ac WD |
34 | #include <malloc.h> |
35 | #include <watchdog.h> | |
cfa460ad | 36 | #include <linux/err.h> |
7b15e2bb | 37 | #include <linux/compat.h> |
932394ac WD |
38 | #include <linux/mtd/mtd.h> |
39 | #include <linux/mtd/nand.h> | |
40 | #include <linux/mtd/nand_ecc.h> | |
4c6de856 | 41 | #include <linux/mtd/nand_bch.h> |
10bb62d8 SR |
42 | #ifdef CONFIG_MTD_PARTITIONS |
43 | #include <linux/mtd/partitions.h> | |
44 | #endif | |
932394ac WD |
45 | #include <asm/io.h> |
46 | #include <asm/errno.h> | |
47 | ||
ff94bc40 | 48 | static bool is_module_text_address(unsigned long addr) {return 0;} |
ff94bc40 | 49 | |
932394ac | 50 | /* Define default oob placement schemes for large and small page devices */ |
cfa460ad | 51 | static struct nand_ecclayout nand_oob_8 = { |
932394ac WD |
52 | .eccbytes = 3, |
53 | .eccpos = {0, 1, 2}, | |
cfa460ad WJ |
54 | .oobfree = { |
55 | {.offset = 3, | |
56 | .length = 2}, | |
57 | {.offset = 6, | |
90e3f395 | 58 | .length = 2} } |
932394ac WD |
59 | }; |
60 | ||
cfa460ad | 61 | static struct nand_ecclayout nand_oob_16 = { |
932394ac WD |
62 | .eccbytes = 6, |
63 | .eccpos = {0, 1, 2, 3, 6, 7}, | |
cfa460ad WJ |
64 | .oobfree = { |
65 | {.offset = 8, | |
90e3f395 | 66 | . length = 8} } |
932394ac WD |
67 | }; |
68 | ||
cfa460ad | 69 | static struct nand_ecclayout nand_oob_64 = { |
932394ac WD |
70 | .eccbytes = 24, |
71 | .eccpos = { | |
cfa460ad WJ |
72 | 40, 41, 42, 43, 44, 45, 46, 47, |
73 | 48, 49, 50, 51, 52, 53, 54, 55, | |
74 | 56, 57, 58, 59, 60, 61, 62, 63}, | |
75 | .oobfree = { | |
76 | {.offset = 2, | |
90e3f395 | 77 | .length = 38} } |
932394ac WD |
78 | }; |
79 | ||
cfa460ad | 80 | static struct nand_ecclayout nand_oob_128 = { |
248ae5cf SP |
81 | .eccbytes = 48, |
82 | .eccpos = { | |
90e3f395 CH |
83 | 80, 81, 82, 83, 84, 85, 86, 87, |
84 | 88, 89, 90, 91, 92, 93, 94, 95, | |
85 | 96, 97, 98, 99, 100, 101, 102, 103, | |
cfa460ad WJ |
86 | 104, 105, 106, 107, 108, 109, 110, 111, |
87 | 112, 113, 114, 115, 116, 117, 118, 119, | |
88 | 120, 121, 122, 123, 124, 125, 126, 127}, | |
89 | .oobfree = { | |
90 | {.offset = 2, | |
90e3f395 | 91 | .length = 78} } |
932394ac WD |
92 | }; |
93 | ||
ff94bc40 | 94 | static int nand_get_device(struct mtd_info *mtd, int new_state); |
cfa460ad WJ |
95 | |
96 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |
97 | struct mtd_oob_ops *ops); | |
98 | ||
ff94bc40 HS |
99 | /* |
100 | * For devices which display every fart in the system on a separate LED. Is | |
101 | * compiled away when LED support is disabled. | |
102 | */ | |
103 | DEFINE_LED_TRIGGER(nand_led_trigger); | |
248ae5cf | 104 | |
2a8e0fc8 CH |
105 | static int check_offs_len(struct mtd_info *mtd, |
106 | loff_t ofs, uint64_t len) | |
107 | { | |
17cb4b8f | 108 | struct nand_chip *chip = mtd_to_nand(mtd); |
2a8e0fc8 CH |
109 | int ret = 0; |
110 | ||
111 | /* Start address must align on block boundary */ | |
ff94bc40 HS |
112 | if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) { |
113 | pr_debug("%s: unaligned address\n", __func__); | |
2a8e0fc8 CH |
114 | ret = -EINVAL; |
115 | } | |
116 | ||
117 | /* Length must align on block boundary */ | |
ff94bc40 HS |
118 | if (len & ((1ULL << chip->phys_erase_shift) - 1)) { |
119 | pr_debug("%s: length not block aligned\n", __func__); | |
2a8e0fc8 CH |
120 | ret = -EINVAL; |
121 | } | |
122 | ||
2a8e0fc8 CH |
123 | return ret; |
124 | } | |
125 | ||
932394ac WD |
126 | /** |
127 | * nand_release_device - [GENERIC] release chip | |
dfe64e2c | 128 | * @mtd: MTD device structure |
ac7eb8a3 | 129 | * |
ff94bc40 | 130 | * Release chip lock and wake up anyone waiting on the device. |
932394ac | 131 | */ |
90e3f395 | 132 | static void nand_release_device(struct mtd_info *mtd) |
8e9655f8 | 133 | { |
17cb4b8f | 134 | struct nand_chip *chip = mtd_to_nand(mtd); |
2a8e0fc8 CH |
135 | |
136 | /* De-select the NAND device */ | |
137 | chip->select_chip(mtd, -1); | |
8e9655f8 | 138 | } |
932394ac WD |
139 | |
140 | /** | |
141 | * nand_read_byte - [DEFAULT] read one byte from the chip | |
dfe64e2c | 142 | * @mtd: MTD device structure |
932394ac | 143 | * |
ff94bc40 | 144 | * Default read function for 8bit buswidth |
932394ac | 145 | */ |
82645f81 | 146 | uint8_t nand_read_byte(struct mtd_info *mtd) |
932394ac | 147 | { |
17cb4b8f | 148 | struct nand_chip *chip = mtd_to_nand(mtd); |
cfa460ad | 149 | return readb(chip->IO_ADDR_R); |
932394ac WD |
150 | } |
151 | ||
152 | /** | |
dfe64e2c SL |
153 | * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip |
154 | * @mtd: MTD device structure | |
155 | * | |
156 | * Default read function for 16bit buswidth with endianness conversion. | |
932394ac | 157 | * |
932394ac | 158 | */ |
cfa460ad | 159 | static uint8_t nand_read_byte16(struct mtd_info *mtd) |
932394ac | 160 | { |
17cb4b8f | 161 | struct nand_chip *chip = mtd_to_nand(mtd); |
cfa460ad | 162 | return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); |
932394ac WD |
163 | } |
164 | ||
165 | /** | |
166 | * nand_read_word - [DEFAULT] read one word from the chip | |
dfe64e2c | 167 | * @mtd: MTD device structure |
932394ac | 168 | * |
dfe64e2c | 169 | * Default read function for 16bit buswidth without endianness conversion. |
932394ac WD |
170 | */ |
171 | static u16 nand_read_word(struct mtd_info *mtd) | |
172 | { | |
17cb4b8f | 173 | struct nand_chip *chip = mtd_to_nand(mtd); |
cfa460ad | 174 | return readw(chip->IO_ADDR_R); |
932394ac WD |
175 | } |
176 | ||
177 | /** | |
178 | * nand_select_chip - [DEFAULT] control CE line | |
dfe64e2c SL |
179 | * @mtd: MTD device structure |
180 | * @chipnr: chipnumber to select, -1 for deselect | |
932394ac WD |
181 | * |
182 | * Default select function for 1 chip devices. | |
183 | */ | |
cfa460ad | 184 | static void nand_select_chip(struct mtd_info *mtd, int chipnr) |
932394ac | 185 | { |
17cb4b8f | 186 | struct nand_chip *chip = mtd_to_nand(mtd); |
cfa460ad WJ |
187 | |
188 | switch (chipnr) { | |
932394ac | 189 | case -1: |
cfa460ad | 190 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); |
932394ac WD |
191 | break; |
192 | case 0: | |
932394ac WD |
193 | break; |
194 | ||
195 | default: | |
196 | BUG(); | |
197 | } | |
198 | } | |
199 | ||
ff94bc40 HS |
200 | /** |
201 | * nand_write_byte - [DEFAULT] write single byte to chip | |
202 | * @mtd: MTD device structure | |
203 | * @byte: value to write | |
204 | * | |
205 | * Default function to write a byte to I/O[7:0] | |
206 | */ | |
207 | static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) | |
208 | { | |
17cb4b8f | 209 | struct nand_chip *chip = mtd_to_nand(mtd); |
ff94bc40 HS |
210 | |
211 | chip->write_buf(mtd, &byte, 1); | |
212 | } | |
213 | ||
214 | /** | |
215 | * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 | |
216 | * @mtd: MTD device structure | |
217 | * @byte: value to write | |
218 | * | |
219 | * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. | |
220 | */ | |
221 | static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) | |
222 | { | |
17cb4b8f | 223 | struct nand_chip *chip = mtd_to_nand(mtd); |
ff94bc40 HS |
224 | uint16_t word = byte; |
225 | ||
226 | /* | |
227 | * It's not entirely clear what should happen to I/O[15:8] when writing | |
228 | * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: | |
229 | * | |
230 | * When the host supports a 16-bit bus width, only data is | |
231 | * transferred at the 16-bit width. All address and command line | |
232 | * transfers shall use only the lower 8-bits of the data bus. During | |
233 | * command transfers, the host may place any value on the upper | |
234 | * 8-bits of the data bus. During address transfers, the host shall | |
235 | * set the upper 8-bits of the data bus to 00h. | |
236 | * | |
237 | * One user of the write_byte callback is nand_onfi_set_features. The | |
238 | * four parameters are specified to be written to I/O[7:0], but this is | |
239 | * neither an address nor a command transfer. Let's assume a 0 on the | |
240 | * upper I/O lines is OK. | |
241 | */ | |
242 | chip->write_buf(mtd, (uint8_t *)&word, 2); | |
243 | } | |
244 | ||
27331064 | 245 | #if !defined(CONFIG_BLACKFIN) |
ff94bc40 HS |
246 | static void iowrite8_rep(void *addr, const uint8_t *buf, int len) |
247 | { | |
248 | int i; | |
249 | ||
250 | for (i = 0; i < len; i++) | |
251 | writeb(buf[i], addr); | |
252 | } | |
253 | static void ioread8_rep(void *addr, uint8_t *buf, int len) | |
254 | { | |
255 | int i; | |
256 | ||
257 | for (i = 0; i < len; i++) | |
258 | buf[i] = readb(addr); | |
259 | } | |
260 | ||
261 | static void ioread16_rep(void *addr, void *buf, int len) | |
262 | { | |
263 | int i; | |
264 | u16 *p = (u16 *) buf; | |
be16aba5 | 265 | |
ff94bc40 HS |
266 | for (i = 0; i < len; i++) |
267 | p[i] = readw(addr); | |
268 | } | |
269 | ||
270 | static void iowrite16_rep(void *addr, void *buf, int len) | |
271 | { | |
272 | int i; | |
273 | u16 *p = (u16 *) buf; | |
ff94bc40 HS |
274 | |
275 | for (i = 0; i < len; i++) | |
276 | writew(p[i], addr); | |
277 | } | |
278 | #endif | |
279 | ||
932394ac WD |
280 | /** |
281 | * nand_write_buf - [DEFAULT] write buffer to chip | |
dfe64e2c SL |
282 | * @mtd: MTD device structure |
283 | * @buf: data buffer | |
284 | * @len: number of bytes to write | |
932394ac | 285 | * |
dfe64e2c | 286 | * Default write function for 8bit buswidth. |
932394ac | 287 | */ |
82645f81 | 288 | void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
932394ac | 289 | { |
17cb4b8f | 290 | struct nand_chip *chip = mtd_to_nand(mtd); |
932394ac | 291 | |
ff94bc40 | 292 | iowrite8_rep(chip->IO_ADDR_W, buf, len); |
932394ac WD |
293 | } |
294 | ||
295 | /** | |
ac7eb8a3 | 296 | * nand_read_buf - [DEFAULT] read chip data into buffer |
dfe64e2c SL |
297 | * @mtd: MTD device structure |
298 | * @buf: buffer to store date | |
299 | * @len: number of bytes to read | |
932394ac | 300 | * |
dfe64e2c | 301 | * Default read function for 8bit buswidth. |
932394ac | 302 | */ |
12c2f1ee | 303 | void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
932394ac | 304 | { |
17cb4b8f | 305 | struct nand_chip *chip = mtd_to_nand(mtd); |
932394ac | 306 | |
ff94bc40 | 307 | ioread8_rep(chip->IO_ADDR_R, buf, len); |
932394ac WD |
308 | } |
309 | ||
932394ac | 310 | /** |
ff94bc40 | 311 | * nand_write_buf16 - [DEFAULT] write buffer to chip |
dfe64e2c | 312 | * @mtd: MTD device structure |
ff94bc40 HS |
313 | * @buf: data buffer |
314 | * @len: number of bytes to write | |
932394ac | 315 | * |
ff94bc40 | 316 | * Default write function for 16bit buswidth. |
932394ac | 317 | */ |
ff94bc40 | 318 | void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) |
932394ac | 319 | { |
17cb4b8f | 320 | struct nand_chip *chip = mtd_to_nand(mtd); |
932394ac | 321 | u16 *p = (u16 *) buf; |
932394ac | 322 | |
ff94bc40 | 323 | iowrite16_rep(chip->IO_ADDR_W, p, len >> 1); |
932394ac WD |
324 | } |
325 | ||
326 | /** | |
ff94bc40 | 327 | * nand_read_buf16 - [DEFAULT] read chip data into buffer |
dfe64e2c | 328 | * @mtd: MTD device structure |
ff94bc40 HS |
329 | * @buf: buffer to store date |
330 | * @len: number of bytes to read | |
932394ac | 331 | * |
ff94bc40 | 332 | * Default read function for 16bit buswidth. |
932394ac | 333 | */ |
ff94bc40 | 334 | void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) |
932394ac | 335 | { |
17cb4b8f | 336 | struct nand_chip *chip = mtd_to_nand(mtd); |
932394ac | 337 | u16 *p = (u16 *) buf; |
932394ac | 338 | |
ff94bc40 | 339 | ioread16_rep(chip->IO_ADDR_R, p, len >> 1); |
932394ac WD |
340 | } |
341 | ||
342 | /** | |
343 | * nand_block_bad - [DEFAULT] Read bad block marker from the chip | |
dfe64e2c SL |
344 | * @mtd: MTD device structure |
345 | * @ofs: offset from device start | |
346 | * @getchip: 0, if the chip is already selected | |
932394ac | 347 | * |
ac7eb8a3 | 348 | * Check, if the block is bad. |
932394ac WD |
349 | */ |
350 | static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |
351 | { | |
dfe64e2c | 352 | int page, chipnr, res = 0, i = 0; |
17cb4b8f | 353 | struct nand_chip *chip = mtd_to_nand(mtd); |
932394ac WD |
354 | u16 bad; |
355 | ||
dfe64e2c | 356 | if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) |
2a8e0fc8 CH |
357 | ofs += mtd->erasesize - mtd->writesize; |
358 | ||
cfa460ad | 359 | page = (int)(ofs >> chip->page_shift) & chip->pagemask; |
a7988659 | 360 | |
932394ac | 361 | if (getchip) { |
cfa460ad | 362 | chipnr = (int)(ofs >> chip->chip_shift); |
932394ac | 363 | |
ff94bc40 | 364 | nand_get_device(mtd, FL_READING); |
932394ac WD |
365 | |
366 | /* Select the NAND device */ | |
cfa460ad | 367 | chip->select_chip(mtd, chipnr); |
a7988659 | 368 | } |
932394ac | 369 | |
dfe64e2c SL |
370 | do { |
371 | if (chip->options & NAND_BUSWIDTH_16) { | |
372 | chip->cmdfunc(mtd, NAND_CMD_READOOB, | |
373 | chip->badblockpos & 0xFE, page); | |
374 | bad = cpu_to_le16(chip->read_word(mtd)); | |
375 | if (chip->badblockpos & 0x1) | |
376 | bad >>= 8; | |
377 | else | |
378 | bad &= 0xFF; | |
379 | } else { | |
380 | chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, | |
381 | page); | |
382 | bad = chip->read_byte(mtd); | |
383 | } | |
ac7eb8a3 | 384 | |
dfe64e2c SL |
385 | if (likely(chip->badblockbits == 8)) |
386 | res = bad != 0xFF; | |
387 | else | |
388 | res = hweight8(bad) < chip->badblockbits; | |
389 | ofs += mtd->writesize; | |
390 | page = (int)(ofs >> chip->page_shift) & chip->pagemask; | |
391 | i++; | |
392 | } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); | |
2a8e0fc8 | 393 | |
ff94bc40 HS |
394 | if (getchip) { |
395 | chip->select_chip(mtd, -1); | |
932394ac | 396 | nand_release_device(mtd); |
ff94bc40 | 397 | } |
ac7eb8a3 | 398 | |
932394ac WD |
399 | return res; |
400 | } | |
401 | ||
402 | /** | |
ff94bc40 | 403 | * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker |
dfe64e2c SL |
404 | * @mtd: MTD device structure |
405 | * @ofs: offset from device start | |
932394ac | 406 | * |
dfe64e2c | 407 | * This is the default implementation, which can be overridden by a hardware |
ff94bc40 HS |
408 | * specific driver. It provides the details for writing a bad block marker to a |
409 | * block. | |
410 | */ | |
411 | static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |
412 | { | |
17cb4b8f | 413 | struct nand_chip *chip = mtd_to_nand(mtd); |
ff94bc40 HS |
414 | struct mtd_oob_ops ops; |
415 | uint8_t buf[2] = { 0, 0 }; | |
416 | int ret = 0, res, i = 0; | |
417 | ||
d3963721 | 418 | memset(&ops, 0, sizeof(ops)); |
ff94bc40 HS |
419 | ops.oobbuf = buf; |
420 | ops.ooboffs = chip->badblockpos; | |
421 | if (chip->options & NAND_BUSWIDTH_16) { | |
422 | ops.ooboffs &= ~0x01; | |
423 | ops.len = ops.ooblen = 2; | |
424 | } else { | |
425 | ops.len = ops.ooblen = 1; | |
426 | } | |
427 | ops.mode = MTD_OPS_PLACE_OOB; | |
428 | ||
429 | /* Write to first/last page(s) if necessary */ | |
430 | if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) | |
431 | ofs += mtd->erasesize - mtd->writesize; | |
432 | do { | |
433 | res = nand_do_write_oob(mtd, ofs, &ops); | |
434 | if (!ret) | |
435 | ret = res; | |
436 | ||
437 | i++; | |
438 | ofs += mtd->writesize; | |
439 | } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); | |
440 | ||
441 | return ret; | |
442 | } | |
443 | ||
444 | /** | |
445 | * nand_block_markbad_lowlevel - mark a block bad | |
446 | * @mtd: MTD device structure | |
447 | * @ofs: offset from device start | |
448 | * | |
449 | * This function performs the generic NAND bad block marking steps (i.e., bad | |
450 | * block table(s) and/or marker(s)). We only allow the hardware driver to | |
451 | * specify how to write bad block markers to OOB (chip->block_markbad). | |
452 | * | |
453 | * We try operations in the following order: | |
dfe64e2c | 454 | * (1) erase the affected block, to allow OOB marker to be written cleanly |
ff94bc40 HS |
455 | * (2) write bad block marker to OOB area of affected block (unless flag |
456 | * NAND_BBT_NO_OOB_BBM is present) | |
457 | * (3) update the BBT | |
458 | * Note that we retain the first error encountered in (2) or (3), finish the | |
dfe64e2c | 459 | * procedures, and dump the error in the end. |
932394ac | 460 | */ |
ff94bc40 | 461 | static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) |
932394ac | 462 | { |
17cb4b8f | 463 | struct nand_chip *chip = mtd_to_nand(mtd); |
ff94bc40 | 464 | int res, ret = 0; |
2a8e0fc8 | 465 | |
ff94bc40 | 466 | if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { |
dfe64e2c SL |
467 | struct erase_info einfo; |
468 | ||
469 | /* Attempt erase before marking OOB */ | |
470 | memset(&einfo, 0, sizeof(einfo)); | |
471 | einfo.mtd = mtd; | |
472 | einfo.addr = ofs; | |
ff94bc40 | 473 | einfo.len = 1ULL << chip->phys_erase_shift; |
dfe64e2c | 474 | nand_erase_nand(mtd, &einfo, 0); |
2a8e0fc8 | 475 | |
ff94bc40 HS |
476 | /* Write bad block marker to OOB */ |
477 | nand_get_device(mtd, FL_WRITING); | |
478 | ret = chip->block_markbad(mtd, ofs); | |
c45912d8 | 479 | nand_release_device(mtd); |
cfa460ad | 480 | } |
dfe64e2c | 481 | |
ff94bc40 HS |
482 | /* Mark block bad in BBT */ |
483 | if (chip->bbt) { | |
484 | res = nand_markbad_bbt(mtd, ofs); | |
dfe64e2c SL |
485 | if (!ret) |
486 | ret = res; | |
487 | } | |
488 | ||
cfa460ad WJ |
489 | if (!ret) |
490 | mtd->ecc_stats.badblocks++; | |
c45912d8 | 491 | |
cfa460ad | 492 | return ret; |
932394ac WD |
493 | } |
494 | ||
ac7eb8a3 | 495 | /** |
932394ac | 496 | * nand_check_wp - [GENERIC] check if the chip is write protected |
dfe64e2c | 497 | * @mtd: MTD device structure |
932394ac | 498 | * |
dfe64e2c SL |
499 | * Check, if the device is write protected. The function expects, that the |
500 | * device is already selected. | |
932394ac | 501 | */ |
cfa460ad | 502 | static int nand_check_wp(struct mtd_info *mtd) |
932394ac | 503 | { |
17cb4b8f | 504 | struct nand_chip *chip = mtd_to_nand(mtd); |
2a8e0fc8 | 505 | |
dfe64e2c | 506 | /* Broken xD cards report WP despite being writable */ |
2a8e0fc8 CH |
507 | if (chip->options & NAND_BROKEN_XD) |
508 | return 0; | |
509 | ||
932394ac | 510 | /* Check the WP bit */ |
cfa460ad WJ |
511 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
512 | return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; | |
932394ac | 513 | } |