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