diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-10-22 10:09:33 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-10-22 10:09:33 -0400 |
commit | fbad5696c5c45982d02e05b85922bad6eb6e6349 (patch) | |
tree | c0d2c95a81a985a7305c2fabb9f95743deb424a1 /drivers | |
parent | 04459d7c6239193fa8de4a5107ee8fdb0f366e35 (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')
-rw-r--r-- | drivers/mtd/nand/Makefile | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe.c | 149 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe_ecc.c | 5 |
3 files changed, 109 insertions, 48 deletions
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 7cebc10c474e..f7a53f0b7017 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -25,4 +25,5 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o | |||
25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | 25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o |
26 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o | 26 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o |
27 | 27 | ||
28 | nand-objs = nand_base.o nand_bbt.o | 28 | nand-objs := nand_base.o nand_bbt.o |
29 | cafe_nand-objs := cafe.o cafe_ecc.o | ||
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 | |||
302 | static int cafe_nand_interrupt(int irq, void *id, struct pt_regs *regs) | 305 | static 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 | |||
354 | static unsigned short cafe_empty_syndromes[8] = { 4095, 748, 2629, 2920, 875, 1454, 51, 1456 }; | ||
355 | |||
356 | static 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 | |||
350 | static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | 373 | static 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 */ |
393 | static uint8_t cafe_bbt_pattern[] = {'B', 'b', 't', '0' }; | 422 | static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' }; |
394 | static uint8_t cafe_mirror_pattern[] = {'1', 't', 'b', 'B' }; | 423 | static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' }; |
424 | |||
425 | static uint8_t cafe_bbt_pattern_512[] = { 0xBB }; | ||
426 | static uint8_t cafe_mirror_pattern_512[] = { 0xBC }; | ||
427 | |||
395 | 428 | ||
396 | static struct nand_bbt_descr cafe_bbt_main_descr_2048 = { | 429 | static 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 | ||
406 | static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = { | 439 | static 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 | ||
416 | static struct nand_ecclayout cafe_oobinfo_512 = { | 449 | static 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 | ||
455 | static 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 | |||
465 | static 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 | |||
422 | static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, | 476 | static 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) |
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c index 4df28a846fbc..c4bec37e73eb 100644 --- a/drivers/mtd/nand/cafe_ecc.c +++ b/drivers/mtd/nand/cafe_ecc.c | |||
@@ -499,10 +499,11 @@ static void solve_2x3(unsigned short m[2][3], unsigned short *coefs) | |||
499 | } | 499 | } |
500 | 500 | ||
501 | static unsigned char gf64_inv[64] = { | 501 | static unsigned char gf64_inv[64] = { |
502 | 0, 1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25, | 502 | 0, 1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25, |
503 | 61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45, 6, | 503 | 61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45, 6, |
504 | 63, 2, 27, 21, 56, 9, 50, 19, 13, 47, 48, 5, 7, 30, 12, 41, | 504 | 63, 2, 27, 21, 56, 9, 50, 19, 13, 47, 48, 5, 7, 30, 12, 41, |
505 | 42, 4, 38, 18, 10, 29, 17, 60, 36, 8, 59, 58, 55, 16, 3, 32}; | 505 | 42, 4, 38, 18, 10, 29, 17, 60, 36, 8, 59, 58, 55, 16, 3, 32 |
506 | }; | ||
506 | 507 | ||
507 | static unsigned short gf4096_inv(unsigned short din) | 508 | static unsigned short gf4096_inv(unsigned short din) |
508 | { | 509 | { |