aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/cafe.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2006-10-22 10:09:33 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-10-22 10:09:33 -0400
commitfbad5696c5c45982d02e05b85922bad6eb6e6349 (patch)
treec0d2c95a81a985a7305c2fabb9f95743deb424a1 /drivers/mtd/nand/cafe.c
parent04459d7c6239193fa8de4a5107ee8fdb0f366e35 (diff)
[MTD] NAND: CAFÉ NAND driver cleanup, fix ECC on reading empty flash
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/nand/cafe.c')
-rw-r--r--drivers/mtd/nand/cafe.c149
1 files changed, 104 insertions, 45 deletions
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
index 1fe110836cc1..10132efd0588 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * cafe_nand.c 2 * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
3 * 3 *
4 * Copyright © 2006 Red Hat, Inc. 4 * Copyright © 2006 Red Hat, Inc.
5 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> 5 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
@@ -30,13 +30,13 @@
30#define CAFE_NAND_TIMING3 0x2c 30#define CAFE_NAND_TIMING3 0x2c
31#define CAFE_NAND_NONMEM 0x30 31#define CAFE_NAND_NONMEM 0x30
32#define CAFE_NAND_ECC_RESULT 0x3C 32#define CAFE_NAND_ECC_RESULT 0x3C
33#define CAFE_NAND_DMA_CTRL 0x40
34#define CAFE_NAND_DMA_ADDR0 0x44
35#define CAFE_NAND_DMA_ADDR1 0x48
33#define CAFE_NAND_ECC_SYN01 0x50 36#define CAFE_NAND_ECC_SYN01 0x50
34#define CAFE_NAND_ECC_SYN23 0x54 37#define CAFE_NAND_ECC_SYN23 0x54
35#define CAFE_NAND_ECC_SYN45 0x58 38#define CAFE_NAND_ECC_SYN45 0x58
36#define CAFE_NAND_ECC_SYN67 0x5c 39#define CAFE_NAND_ECC_SYN67 0x5c
37#define CAFE_NAND_DMA_CTRL 0x40
38#define CAFE_NAND_DMA_ADDR0 0x44
39#define CAFE_NAND_DMA_ADDR1 0x48
40#define CAFE_NAND_READ_DATA 0x1000 40#define CAFE_NAND_READ_DATA 0x1000
41#define CAFE_NAND_WRITE_DATA 0x2000 41#define CAFE_NAND_WRITE_DATA 0x2000
42 42
@@ -75,12 +75,14 @@ static int cafe_device_ready(struct mtd_info *mtd)
75{ 75{
76 struct cafe_priv *cafe = mtd->priv; 76 struct cafe_priv *cafe = mtd->priv;
77 int result = !!(readl(cafe->mmio + CAFE_NAND_STATUS) | 0x40000000); 77 int result = !!(readl(cafe->mmio + CAFE_NAND_STATUS) | 0x40000000);
78
79 uint32_t irqs = readl(cafe->mmio + CAFE_NAND_IRQ); 78 uint32_t irqs = readl(cafe->mmio + CAFE_NAND_IRQ);
79
80 writel(irqs, cafe->mmio+CAFE_NAND_IRQ); 80 writel(irqs, cafe->mmio+CAFE_NAND_IRQ);
81
81 cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n", 82 cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
82 result?"":" not", irqs, readl(cafe->mmio + CAFE_NAND_IRQ), 83 result?"":" not", irqs, readl(cafe->mmio + CAFE_NAND_IRQ),
83 readl(cafe->mmio + 0x3008), readl(cafe->mmio + 0x300c)); 84 readl(cafe->mmio + 0x3008), readl(cafe->mmio + 0x300c));
85
84 return result; 86 return result;
85} 87}
86 88
@@ -93,6 +95,7 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
93 memcpy(cafe->dmabuf + cafe->datalen, buf, len); 95 memcpy(cafe->dmabuf + cafe->datalen, buf, len);
94 else 96 else
95 memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len); 97 memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
98
96 cafe->datalen += len; 99 cafe->datalen += len;
97 100
98 cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n", 101 cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
@@ -131,14 +134,13 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
131 int adrbytes = 0; 134 int adrbytes = 0;
132 uint32_t ctl1; 135 uint32_t ctl1;
133 uint32_t doneint = 0x80000000; 136 uint32_t doneint = 0x80000000;
134 int i;
135 137
136 cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n", 138 cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
137 command, column, page_addr); 139 command, column, page_addr);
138 140
139 if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) { 141 if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
140 /* Second half of a command we already calculated */ 142 /* Second half of a command we already calculated */
141 writel(cafe->ctl2 | 0x100 | command, cafe->mmio + 0x04); 143 writel(cafe->ctl2 | 0x100 | command, cafe->mmio + CAFE_NAND_CTRL2);
142 ctl1 = cafe->ctl1; 144 ctl1 = cafe->ctl1;
143 cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n", 145 cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
144 cafe->ctl1, cafe->nr_data); 146 cafe->ctl1, cafe->nr_data);
@@ -158,12 +160,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
158 for small-page chips, to position the buffer correctly? */ 160 for small-page chips, to position the buffer correctly? */
159 161
160 if (column != -1) { 162 if (column != -1) {
161 writel(column, cafe->mmio + 0x1c); 163 writel(column, cafe->mmio + CAFE_NAND_ADDR1);
162 adrbytes = 2; 164 adrbytes = 2;
163 if (page_addr != -1) 165 if (page_addr != -1)
164 goto write_adr2; 166 goto write_adr2;
165 } else if (page_addr != -1) { 167 } else if (page_addr != -1) {
166 writel(page_addr & 0xffff, cafe->mmio + 0x1c); 168 writel(page_addr & 0xffff, cafe->mmio + CAFE_NAND_ADDR1);
167 page_addr >>= 16; 169 page_addr >>= 16;
168 write_adr2: 170 write_adr2:
169 writel(page_addr, cafe->mmio+0x20); 171 writel(page_addr, cafe->mmio+0x20);
@@ -212,13 +214,15 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
212 writel(cafe->ctl2 | 0x100 | NAND_CMD_READSTART, cafe->mmio + CAFE_NAND_CTRL2); 214 writel(cafe->ctl2 | 0x100 | NAND_CMD_READSTART, cafe->mmio + CAFE_NAND_CTRL2);
213 215
214 do_command: 216 do_command:
215#if 0 217#if 1
216 // ECC on read only works if we ... 218 /* http://dev.laptop.org/ticket/200
219 ECC on read only works if we read precisely 0x80e bytes */
217 if (cafe->datalen == 2112) 220 if (cafe->datalen == 2112)
218 cafe->datalen = 2062; 221 cafe->datalen = 2062;
219#endif 222#endif
220 cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n", 223 cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
221 cafe->datalen, ctl1, readl(cafe->mmio+CAFE_NAND_CTRL2)); 224 cafe->datalen, ctl1, readl(cafe->mmio+CAFE_NAND_CTRL2));
225
222 /* NB: The datasheet lies -- we really should be subtracting 1 here */ 226 /* NB: The datasheet lies -- we really should be subtracting 1 here */
223 writel(cafe->datalen, cafe->mmio + CAFE_NAND_DATA_LEN); 227 writel(cafe->datalen, cafe->mmio + CAFE_NAND_DATA_LEN);
224 writel(0x90000000, cafe->mmio + CAFE_NAND_IRQ); 228 writel(0x90000000, cafe->mmio + CAFE_NAND_IRQ);
@@ -232,18 +236,16 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
232 the command. */ 236 the command. */
233 doneint = 0x10000000; 237 doneint = 0x10000000;
234 } 238 }
235 writel(dmactl, cafe->mmio + 0x40); 239 writel(dmactl, cafe->mmio + CAFE_NAND_DMA_CTRL);
236 } 240 }
237#if 0
238 printk("DMA setup is %x, status %x, ctl1 %x\n", readl(cafe->mmio + 0x40), readl(cafe->mmio + 0x0c), readl(cafe->mmio));
239 printk("DMA setup is %x, status %x, ctl1 %x\n", readl(cafe->mmio + 0x40), readl(cafe->mmio + 0x0c), readl(cafe->mmio));
240#endif
241 cafe->datalen = 0; 241 cafe->datalen = 0;
242 242
243#if 0 243#if 0
244 { int i;
244 printk("About to write command %08x\n", ctl1); 245 printk("About to write command %08x\n", ctl1);
245 for (i=0; i< 0x5c; i+=4) 246 for (i=0; i< 0x5c; i+=4)
246 printk("Register %x: %08x\n", i, readl(cafe->mmio + i)); 247 printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
248 }
247#endif 249#endif
248 writel(ctl1, cafe->mmio + CAFE_NAND_CTRL1); 250 writel(ctl1, cafe->mmio + CAFE_NAND_CTRL1);
249 /* Apply this short delay always to ensure that we do wait tWB in 251 /* Apply this short delay always to ensure that we do wait tWB in
@@ -299,6 +301,7 @@ static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
299 //struct cafe_priv *cafe = mtd->priv; 301 //struct cafe_priv *cafe = mtd->priv;
300 // cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr); 302 // cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
301} 303}
304
302static int cafe_nand_interrupt(int irq, void *id, struct pt_regs *regs) 305static int cafe_nand_interrupt(int irq, void *id, struct pt_regs *regs)
303{ 306{
304 struct mtd_info *mtd = id; 307 struct mtd_info *mtd = id;
@@ -347,14 +350,34 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
347 * The hw generator calculates the error syndrome automatically. Therefor 350 * The hw generator calculates the error syndrome automatically. Therefor
348 * we need a special oob layout and handling. 351 * we need a special oob layout and handling.
349 */ 352 */
353
354static unsigned short cafe_empty_syndromes[8] = { 4095, 748, 2629, 2920, 875, 1454, 51, 1456 };
355
356static int is_all_ff(unsigned char *buf, int len)
357{
358 unsigned long *lbuf = (void *)buf;
359 int i;
360
361 for (i=0; i < (len/sizeof(long)); i++) {
362 if (lbuf[i] != ~0UL)
363 return 0;
364 }
365 i *= sizeof(long);
366 for (; i< len; i++) {
367 if (buf[i] != 0xff)
368 return 0;
369 }
370 return 1;
371}
372
350static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, 373static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
351 uint8_t *buf) 374 uint8_t *buf)
352{ 375{
353 struct cafe_priv *cafe = mtd->priv; 376 struct cafe_priv *cafe = mtd->priv;
354 377
355 dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", 378 cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
356 readl(cafe->mmio + CAFE_NAND_ECC_RESULT), 379 readl(cafe->mmio + CAFE_NAND_ECC_RESULT),
357 readl(cafe->mmio + CAFE_NAND_ECC_SYN01)); 380 readl(cafe->mmio + CAFE_NAND_ECC_SYN01));
358 381
359 chip->read_buf(mtd, buf, mtd->writesize); 382 chip->read_buf(mtd, buf, mtd->writesize);
360 chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); 383 chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -369,7 +392,13 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
369 syn[i+1] = (tmp >> 16) & 0xfff; 392 syn[i+1] = (tmp >> 16) & 0xfff;
370 } 393 }
371 394
372 if ((i = cafe_correct_ecc(buf, syn)) < 0) { 395 /* FIXME: http://dev.laptop.org/ticket/215 */
396 if (!memcmp(syn, cafe_empty_syndromes, sizeof(syn))
397 && is_all_ff(chip->oob_poi, 14)
398 && is_all_ff(buf, mtd->writesize)) {
399 dev_dbg(&cafe->pdev->dev, "ECC error reported on empty block\n");
400 /* It was an empty block. Nothing to fix here except the hardware */
401 } else if ((i = cafe_correct_ecc(buf, syn)) < 0) {
373 dev_dbg(&cafe->pdev->dev, "Failed to correct ECC\n"); 402 dev_dbg(&cafe->pdev->dev, "Failed to correct ECC\n");
374 mtd->ecc_stats.failed++; 403 mtd->ecc_stats.failed++;
375 } else { 404 } else {
@@ -389,9 +418,13 @@ static struct nand_ecclayout cafe_oobinfo_2048 = {
389}; 418};
390 419
391/* Ick. The BBT code really ought to be able to work this bit out 420/* Ick. The BBT code really ought to be able to work this bit out
392 for itself from the above */ 421 for itself from the above, at least for the 2KiB case */
393static uint8_t cafe_bbt_pattern[] = {'B', 'b', 't', '0' }; 422static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
394static uint8_t cafe_mirror_pattern[] = {'1', 't', 'b', 'B' }; 423static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
424
425static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
426static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
427
395 428
396static struct nand_bbt_descr cafe_bbt_main_descr_2048 = { 429static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
397 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 430 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
@@ -400,7 +433,7 @@ static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
400 .len = 4, 433 .len = 4,
401 .veroffs = 18, 434 .veroffs = 18,
402 .maxblocks = 4, 435 .maxblocks = 4,
403 .pattern = cafe_bbt_pattern 436 .pattern = cafe_bbt_pattern_2048
404}; 437};
405 438
406static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = { 439static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
@@ -410,7 +443,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
410 .len = 4, 443 .len = 4,
411 .veroffs = 18, 444 .veroffs = 18,
412 .maxblocks = 4, 445 .maxblocks = 4,
413 .pattern = cafe_mirror_pattern 446 .pattern = cafe_mirror_pattern_2048
414}; 447};
415 448
416static struct nand_ecclayout cafe_oobinfo_512 = { 449static struct nand_ecclayout cafe_oobinfo_512 = {
@@ -419,6 +452,27 @@ static struct nand_ecclayout cafe_oobinfo_512 = {
419 .oobfree = {{14, 2}} 452 .oobfree = {{14, 2}}
420}; 453};
421 454
455static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
456 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
457 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
458 .offs = 14,
459 .len = 1,
460 .veroffs = 15,
461 .maxblocks = 4,
462 .pattern = cafe_bbt_pattern_512
463};
464
465static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
466 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
467 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
468 .offs = 14,
469 .len = 1,
470 .veroffs = 15,
471 .maxblocks = 4,
472 .pattern = cafe_mirror_pattern_512
473};
474
475
422static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, 476static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
423 struct nand_chip *chip, const uint8_t *buf) 477 struct nand_chip *chip, const uint8_t *buf)
424{ 478{
@@ -566,19 +620,21 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
566 ctrl |= 0x00007000; 620 ctrl |= 0x00007000;
567 writel(ctrl | 0x05, cafe->mmio + 0x3004); 621 writel(ctrl | 0x05, cafe->mmio + 0x3004);
568 writel(ctrl | 0x0a, cafe->mmio + 0x3004); 622 writel(ctrl | 0x0a, cafe->mmio + 0x3004);
569 writel(0, cafe->mmio + 0x40); 623 writel(0, cafe->mmio + CAFE_NAND_DMA_CTRL);
570 624
571 writel(0x7006, cafe->mmio + 0x3004); 625 writel(0x7006, cafe->mmio + 0x3004);
572 writel(0x700a, cafe->mmio + 0x3004); 626 writel(0x700a, cafe->mmio + 0x3004);
573 627
574 /* Set up DMA address */ 628 /* Set up DMA address */
575 writel(cafe->dmaaddr & 0xffffffff, cafe->mmio + 0x44); 629 writel(cafe->dmaaddr & 0xffffffff, cafe->mmio + CAFE_NAND_DMA_ADDR0);
576 if (sizeof(cafe->dmaaddr) > 4) 630 if (sizeof(cafe->dmaaddr) > 4)
577 writel((cafe->dmaaddr >> 16) >> 16, cafe->mmio + 0x48); 631 /* Shift in two parts to shut the compiler up */
632 writel((cafe->dmaaddr >> 16) >> 16, cafe->mmio + CAFE_NAND_DMA_ADDR1);
578 else 633 else
579 writel(0, cafe->mmio + 0x48); 634 writel(0, cafe->mmio + CAFE_NAND_DMA_ADDR1);
635
580 cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n", 636 cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
581 readl(cafe->mmio+0x44), cafe->dmabuf); 637 readl(cafe->mmio + CAFE_NAND_DMA_ADDR0), cafe->dmabuf);
582 638
583 /* Enable NAND IRQ in global IRQ mask register */ 639 /* Enable NAND IRQ in global IRQ mask register */
584 writel(0x80000007, cafe->mmio + 0x300c); 640 writel(0x80000007, cafe->mmio + 0x300c);
@@ -620,27 +676,30 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
620 cafe->ctl2 |= 1<<29; /* 2KiB page size */ 676 cafe->ctl2 |= 1<<29; /* 2KiB page size */
621 677
622 /* Set up ECC according to the type of chip we found */ 678 /* Set up ECC according to the type of chip we found */
623 if (mtd->writesize == 512 || mtd->writesize == 2048) { 679 if (mtd->writesize == 2048) {
624 cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
625 cafe->nand.ecc.size = mtd->writesize;
626 cafe->nand.ecc.bytes = 14;
627 cafe->nand.ecc.layout = &cafe_oobinfo_2048; 680 cafe->nand.ecc.layout = &cafe_oobinfo_2048;
628 cafe->nand.bbt_td = &cafe_bbt_main_descr_2048; 681 cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
629 cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048; 682 cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
630 cafe->nand.ecc.hwctl = (void *)cafe_nand_bug; 683 } else if (mtd->writesize == 512) {
631 cafe->nand.ecc.calculate = (void *)cafe_nand_bug; 684 cafe->nand.ecc.layout = &cafe_oobinfo_512;
632 cafe->nand.ecc.correct = (void *)cafe_nand_bug; 685 cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
633 cafe->nand.write_page = cafe_nand_write_page; 686 cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
634 cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
635 cafe->nand.ecc.write_oob = cafe_nand_write_oob;
636 cafe->nand.ecc.read_page = cafe_nand_read_page;
637 cafe->nand.ecc.read_oob = cafe_nand_read_oob;
638
639 } else { 687 } else {
640 printk(KERN_WARNING "Unexpected NAND flash writesize %d. Using software ECC\n", 688 printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
641 mtd->writesize); 689 mtd->writesize);
642 cafe->nand.ecc.mode = NAND_ECC_NONE; 690 goto out_irq;
643 } 691 }
692 cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
693 cafe->nand.ecc.size = mtd->writesize;
694 cafe->nand.ecc.bytes = 14;
695 cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
696 cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
697 cafe->nand.ecc.correct = (void *)cafe_nand_bug;
698 cafe->nand.write_page = cafe_nand_write_page;
699 cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
700 cafe->nand.ecc.write_oob = cafe_nand_write_oob;
701 cafe->nand.ecc.read_page = cafe_nand_read_page;
702 cafe->nand.ecc.read_oob = cafe_nand_read_oob;
644 703
645 err = nand_scan_tail(mtd); 704 err = nand_scan_tail(mtd);
646 if (err) 705 if (err)