diff options
| -rw-r--r-- | drivers/mtd/nand/omap2.c | 206 |
1 files changed, 161 insertions, 45 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ac4fd756eda3..52fc089d5bcb 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
| @@ -101,6 +101,16 @@ | |||
| 101 | #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) | 101 | #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) |
| 102 | #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) | 102 | #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) |
| 103 | 103 | ||
| 104 | #define PREFETCH_CONFIG1_CS_SHIFT 24 | ||
| 105 | #define ECC_CONFIG_CS_SHIFT 1 | ||
| 106 | #define CS_MASK 0x7 | ||
| 107 | #define ENABLE_PREFETCH (0x1 << 7) | ||
| 108 | #define DMA_MPU_MODE_SHIFT 2 | ||
| 109 | #define ECCSIZE1_SHIFT 22 | ||
| 110 | #define ECC1RESULTSIZE 0x1 | ||
| 111 | #define ECCCLEAR 0x100 | ||
| 112 | #define ECC1 0x1 | ||
| 113 | |||
| 104 | /* oob info generated runtime depending on ecc algorithm and layout selected */ | 114 | /* oob info generated runtime depending on ecc algorithm and layout selected */ |
| 105 | static struct nand_ecclayout omap_oobinfo; | 115 | static struct nand_ecclayout omap_oobinfo; |
| 106 | /* Define some generic bad / good block scan pattern which are used | 116 | /* Define some generic bad / good block scan pattern which are used |
| @@ -133,6 +143,7 @@ struct omap_nand_info { | |||
| 133 | } iomode; | 143 | } iomode; |
| 134 | u_char *buf; | 144 | u_char *buf; |
| 135 | int buf_len; | 145 | int buf_len; |
| 146 | struct gpmc_nand_regs reg; | ||
| 136 | 147 | ||
| 137 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 148 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
| 138 | struct bch_control *bch; | 149 | struct bch_control *bch; |
| @@ -141,6 +152,63 @@ struct omap_nand_info { | |||
| 141 | }; | 152 | }; |
| 142 | 153 | ||
| 143 | /** | 154 | /** |
| 155 | * omap_prefetch_enable - configures and starts prefetch transfer | ||
| 156 | * @cs: cs (chip select) number | ||
| 157 | * @fifo_th: fifo threshold to be used for read/ write | ||
| 158 | * @dma_mode: dma mode enable (1) or disable (0) | ||
| 159 | * @u32_count: number of bytes to be transferred | ||
| 160 | * @is_write: prefetch read(0) or write post(1) mode | ||
| 161 | */ | ||
| 162 | static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode, | ||
| 163 | unsigned int u32_count, int is_write, struct omap_nand_info *info) | ||
| 164 | { | ||
| 165 | u32 val; | ||
| 166 | |||
| 167 | if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) | ||
| 168 | return -1; | ||
| 169 | |||
| 170 | if (readl(info->reg.gpmc_prefetch_control)) | ||
| 171 | return -EBUSY; | ||
| 172 | |||
| 173 | /* Set the amount of bytes to be prefetched */ | ||
| 174 | writel(u32_count, info->reg.gpmc_prefetch_config2); | ||
| 175 | |||
| 176 | /* Set dma/mpu mode, the prefetch read / post write and | ||
| 177 | * enable the engine. Set which cs is has requested for. | ||
| 178 | */ | ||
| 179 | val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) | | ||
| 180 | PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH | | ||
| 181 | (dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write)); | ||
| 182 | writel(val, info->reg.gpmc_prefetch_config1); | ||
| 183 | |||
| 184 | /* Start the prefetch engine */ | ||
| 185 | writel(0x1, info->reg.gpmc_prefetch_control); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * omap_prefetch_reset - disables and stops the prefetch engine | ||
| 192 | */ | ||
| 193 | static int omap_prefetch_reset(int cs, struct omap_nand_info *info) | ||
| 194 | { | ||
| 195 | u32 config1; | ||
| 196 | |||
| 197 | /* check if the same module/cs is trying to reset */ | ||
| 198 | config1 = readl(info->reg.gpmc_prefetch_config1); | ||
| 199 | if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs) | ||
| 200 | return -EINVAL; | ||
| 201 | |||
| 202 | /* Stop the PFPW engine */ | ||
| 203 | writel(0x0, info->reg.gpmc_prefetch_control); | ||
| 204 | |||
| 205 | /* Reset/disable the PFPW engine */ | ||
| 206 | writel(0x0, info->reg.gpmc_prefetch_config1); | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | /** | ||
| 144 | * omap_hwcontrol - hardware specific access to control-lines | 212 | * omap_hwcontrol - hardware specific access to control-lines |
| 145 | * @mtd: MTD device structure | 213 | * @mtd: MTD device structure |
| 146 | * @cmd: command to device | 214 | * @cmd: command to device |
| @@ -158,13 +226,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
| 158 | 226 | ||
| 159 | if (cmd != NAND_CMD_NONE) { | 227 | if (cmd != NAND_CMD_NONE) { |
| 160 | if (ctrl & NAND_CLE) | 228 | if (ctrl & NAND_CLE) |
| 161 | gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd); | 229 | writeb(cmd, info->reg.gpmc_nand_command); |
| 162 | 230 | ||
| 163 | else if (ctrl & NAND_ALE) | 231 | else if (ctrl & NAND_ALE) |
| 164 | gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd); | 232 | writeb(cmd, info->reg.gpmc_nand_address); |
| 165 | 233 | ||
| 166 | else /* NAND_NCE */ | 234 | else /* NAND_NCE */ |
| 167 | gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd); | 235 | writeb(cmd, info->reg.gpmc_nand_data); |
| 168 | } | 236 | } |
| 169 | } | 237 | } |
| 170 | 238 | ||
| @@ -198,7 +266,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) | |||
| 198 | iowrite8(*p++, info->nand.IO_ADDR_W); | 266 | iowrite8(*p++, info->nand.IO_ADDR_W); |
| 199 | /* wait until buffer is available for write */ | 267 | /* wait until buffer is available for write */ |
| 200 | do { | 268 | do { |
| 201 | status = gpmc_read_status(GPMC_STATUS_BUFFER); | 269 | status = readl(info->reg.gpmc_status) & |
| 270 | GPMC_STATUS_BUFF_EMPTY; | ||
| 202 | } while (!status); | 271 | } while (!status); |
| 203 | } | 272 | } |
| 204 | } | 273 | } |
| @@ -235,7 +304,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) | |||
| 235 | iowrite16(*p++, info->nand.IO_ADDR_W); | 304 | iowrite16(*p++, info->nand.IO_ADDR_W); |
| 236 | /* wait until buffer is available for write */ | 305 | /* wait until buffer is available for write */ |
| 237 | do { | 306 | do { |
| 238 | status = gpmc_read_status(GPMC_STATUS_BUFFER); | 307 | status = readl(info->reg.gpmc_status) & |
| 308 | GPMC_STATUS_BUFF_EMPTY; | ||
| 239 | } while (!status); | 309 | } while (!status); |
| 240 | } | 310 | } |
| 241 | } | 311 | } |
| @@ -265,8 +335,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) | |||
| 265 | } | 335 | } |
| 266 | 336 | ||
| 267 | /* configure and start prefetch transfer */ | 337 | /* configure and start prefetch transfer */ |
| 268 | ret = gpmc_prefetch_enable(info->gpmc_cs, | 338 | ret = omap_prefetch_enable(info->gpmc_cs, |
| 269 | PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0); | 339 | PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info); |
| 270 | if (ret) { | 340 | if (ret) { |
| 271 | /* PFPW engine is busy, use cpu copy method */ | 341 | /* PFPW engine is busy, use cpu copy method */ |
| 272 | if (info->nand.options & NAND_BUSWIDTH_16) | 342 | if (info->nand.options & NAND_BUSWIDTH_16) |
| @@ -275,14 +345,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) | |||
| 275 | omap_read_buf8(mtd, (u_char *)p, len); | 345 | omap_read_buf8(mtd, (u_char *)p, len); |
| 276 | } else { | 346 | } else { |
| 277 | do { | 347 | do { |
| 278 | r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); | 348 | r_count = readl(info->reg.gpmc_prefetch_status); |
| 349 | r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count); | ||
| 279 | r_count = r_count >> 2; | 350 | r_count = r_count >> 2; |
| 280 | ioread32_rep(info->nand.IO_ADDR_R, p, r_count); | 351 | ioread32_rep(info->nand.IO_ADDR_R, p, r_count); |
| 281 | p += r_count; | 352 | p += r_count; |
| 282 | len -= r_count << 2; | 353 | len -= r_count << 2; |
| 283 | } while (len); | 354 | } while (len); |
| 284 | /* disable and stop the PFPW engine */ | 355 | /* disable and stop the PFPW engine */ |
| 285 | gpmc_prefetch_reset(info->gpmc_cs); | 356 | omap_prefetch_reset(info->gpmc_cs, info); |
| 286 | } | 357 | } |
| 287 | } | 358 | } |
| 288 | 359 | ||
| @@ -301,6 +372,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, | |||
| 301 | int i = 0, ret = 0; | 372 | int i = 0, ret = 0; |
| 302 | u16 *p = (u16 *)buf; | 373 | u16 *p = (u16 *)buf; |
| 303 | unsigned long tim, limit; | 374 | unsigned long tim, limit; |
| 375 | u32 val; | ||
| 304 | 376 | ||
| 305 | /* take care of subpage writes */ | 377 | /* take care of subpage writes */ |
| 306 | if (len % 2 != 0) { | 378 | if (len % 2 != 0) { |
| @@ -310,8 +382,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, | |||
| 310 | } | 382 | } |
| 311 | 383 | ||
| 312 | /* configure and start prefetch transfer */ | 384 | /* configure and start prefetch transfer */ |
| 313 | ret = gpmc_prefetch_enable(info->gpmc_cs, | 385 | ret = omap_prefetch_enable(info->gpmc_cs, |
| 314 | PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1); | 386 | PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info); |
| 315 | if (ret) { | 387 | if (ret) { |
| 316 | /* PFPW engine is busy, use cpu copy method */ | 388 | /* PFPW engine is busy, use cpu copy method */ |
| 317 | if (info->nand.options & NAND_BUSWIDTH_16) | 389 | if (info->nand.options & NAND_BUSWIDTH_16) |
| @@ -320,7 +392,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, | |||
| 320 | omap_write_buf8(mtd, (u_char *)p, len); | 392 | omap_write_buf8(mtd, (u_char *)p, len); |
| 321 | } else { | 393 | } else { |
| 322 | while (len) { | 394 | while (len) { |
| 323 | w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); | 395 | w_count = readl(info->reg.gpmc_prefetch_status); |
| 396 | w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); | ||
| 324 | w_count = w_count >> 1; | 397 | w_count = w_count >> 1; |
| 325 | for (i = 0; (i < w_count) && len; i++, len -= 2) | 398 | for (i = 0; (i < w_count) && len; i++, len -= 2) |
| 326 | iowrite16(*p++, info->nand.IO_ADDR_W); | 399 | iowrite16(*p++, info->nand.IO_ADDR_W); |
| @@ -329,11 +402,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd, | |||
| 329 | tim = 0; | 402 | tim = 0; |
| 330 | limit = (loops_per_jiffy * | 403 | limit = (loops_per_jiffy * |
| 331 | msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); | 404 | msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); |
| 332 | while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) | 405 | do { |
| 333 | cpu_relax(); | 406 | cpu_relax(); |
| 407 | val = readl(info->reg.gpmc_prefetch_status); | ||
| 408 | val = GPMC_PREFETCH_STATUS_COUNT(val); | ||
| 409 | } while (val && (tim++ < limit)); | ||
| 334 | 410 | ||
| 335 | /* disable and stop the PFPW engine */ | 411 | /* disable and stop the PFPW engine */ |
| 336 | gpmc_prefetch_reset(info->gpmc_cs); | 412 | omap_prefetch_reset(info->gpmc_cs, info); |
| 337 | } | 413 | } |
| 338 | } | 414 | } |
| 339 | 415 | ||
| @@ -365,6 +441,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | |||
| 365 | unsigned long tim, limit; | 441 | unsigned long tim, limit; |
| 366 | unsigned n; | 442 | unsigned n; |
| 367 | int ret; | 443 | int ret; |
| 444 | u32 val; | ||
| 368 | 445 | ||
| 369 | if (addr >= high_memory) { | 446 | if (addr >= high_memory) { |
| 370 | struct page *p1; | 447 | struct page *p1; |
| @@ -396,9 +473,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | |||
| 396 | tx->callback_param = &info->comp; | 473 | tx->callback_param = &info->comp; |
| 397 | dmaengine_submit(tx); | 474 | dmaengine_submit(tx); |
| 398 | 475 | ||
| 399 | /* configure and start prefetch transfer */ | 476 | /* configure and start prefetch transfer */ |
| 400 | ret = gpmc_prefetch_enable(info->gpmc_cs, | 477 | ret = omap_prefetch_enable(info->gpmc_cs, |
| 401 | PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); | 478 | PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info); |
| 402 | if (ret) | 479 | if (ret) |
| 403 | /* PFPW engine is busy, use cpu copy method */ | 480 | /* PFPW engine is busy, use cpu copy method */ |
| 404 | goto out_copy_unmap; | 481 | goto out_copy_unmap; |
| @@ -410,11 +487,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | |||
| 410 | wait_for_completion(&info->comp); | 487 | wait_for_completion(&info->comp); |
| 411 | tim = 0; | 488 | tim = 0; |
| 412 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); | 489 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); |
| 413 | while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) | 490 | |
| 491 | do { | ||
| 414 | cpu_relax(); | 492 | cpu_relax(); |
| 493 | val = readl(info->reg.gpmc_prefetch_status); | ||
| 494 | val = GPMC_PREFETCH_STATUS_COUNT(val); | ||
| 495 | } while (val && (tim++ < limit)); | ||
| 415 | 496 | ||
| 416 | /* disable and stop the PFPW engine */ | 497 | /* disable and stop the PFPW engine */ |
| 417 | gpmc_prefetch_reset(info->gpmc_cs); | 498 | omap_prefetch_reset(info->gpmc_cs, info); |
| 418 | 499 | ||
| 419 | dma_unmap_sg(info->dma->device->dev, &sg, 1, dir); | 500 | dma_unmap_sg(info->dma->device->dev, &sg, 1, dir); |
| 420 | return 0; | 501 | return 0; |
| @@ -474,7 +555,8 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) | |||
| 474 | u32 irq_stat; | 555 | u32 irq_stat; |
| 475 | 556 | ||
| 476 | irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); | 557 | irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); |
| 477 | bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); | 558 | bytes = readl(info->reg.gpmc_prefetch_status); |
| 559 | bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); | ||
| 478 | bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ | 560 | bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ |
| 479 | if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ | 561 | if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ |
| 480 | if (irq_stat & 0x2) | 562 | if (irq_stat & 0x2) |
| @@ -534,8 +616,8 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) | |||
| 534 | init_completion(&info->comp); | 616 | init_completion(&info->comp); |
| 535 | 617 | ||
| 536 | /* configure and start prefetch transfer */ | 618 | /* configure and start prefetch transfer */ |
| 537 | ret = gpmc_prefetch_enable(info->gpmc_cs, | 619 | ret = omap_prefetch_enable(info->gpmc_cs, |
| 538 | PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0); | 620 | PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info); |
| 539 | if (ret) | 621 | if (ret) |
| 540 | /* PFPW engine is busy, use cpu copy method */ | 622 | /* PFPW engine is busy, use cpu copy method */ |
| 541 | goto out_copy; | 623 | goto out_copy; |
| @@ -549,7 +631,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) | |||
| 549 | wait_for_completion(&info->comp); | 631 | wait_for_completion(&info->comp); |
| 550 | 632 | ||
| 551 | /* disable and stop the PFPW engine */ | 633 | /* disable and stop the PFPW engine */ |
| 552 | gpmc_prefetch_reset(info->gpmc_cs); | 634 | omap_prefetch_reset(info->gpmc_cs, info); |
| 553 | return; | 635 | return; |
| 554 | 636 | ||
| 555 | out_copy: | 637 | out_copy: |
| @@ -572,6 +654,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, | |||
| 572 | struct omap_nand_info, mtd); | 654 | struct omap_nand_info, mtd); |
| 573 | int ret = 0; | 655 | int ret = 0; |
| 574 | unsigned long tim, limit; | 656 | unsigned long tim, limit; |
| 657 | u32 val; | ||
| 575 | 658 | ||
| 576 | if (len <= mtd->oobsize) { | 659 | if (len <= mtd->oobsize) { |
| 577 | omap_write_buf_pref(mtd, buf, len); | 660 | omap_write_buf_pref(mtd, buf, len); |
| @@ -583,8 +666,8 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, | |||
| 583 | init_completion(&info->comp); | 666 | init_completion(&info->comp); |
| 584 | 667 | ||
| 585 | /* configure and start prefetch transfer : size=24 */ | 668 | /* configure and start prefetch transfer : size=24 */ |
| 586 | ret = gpmc_prefetch_enable(info->gpmc_cs, | 669 | ret = omap_prefetch_enable(info->gpmc_cs, |
| 587 | (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1); | 670 | (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info); |
| 588 | if (ret) | 671 | if (ret) |
| 589 | /* PFPW engine is busy, use cpu copy method */ | 672 | /* PFPW engine is busy, use cpu copy method */ |
| 590 | goto out_copy; | 673 | goto out_copy; |
| @@ -599,11 +682,14 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, | |||
| 599 | /* wait for data to flushed-out before reset the prefetch */ | 682 | /* wait for data to flushed-out before reset the prefetch */ |
| 600 | tim = 0; | 683 | tim = 0; |
| 601 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); | 684 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); |
| 602 | while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) | 685 | do { |
| 686 | val = readl(info->reg.gpmc_prefetch_status); | ||
| 687 | val = GPMC_PREFETCH_STATUS_COUNT(val); | ||
| 603 | cpu_relax(); | 688 | cpu_relax(); |
| 689 | } while (val && (tim++ < limit)); | ||
| 604 | 690 | ||
| 605 | /* disable and stop the PFPW engine */ | 691 | /* disable and stop the PFPW engine */ |
| 606 | gpmc_prefetch_reset(info->gpmc_cs); | 692 | omap_prefetch_reset(info->gpmc_cs, info); |
| 607 | return; | 693 | return; |
| 608 | 694 | ||
| 609 | out_copy: | 695 | out_copy: |
| @@ -843,7 +929,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | |||
| 843 | { | 929 | { |
| 844 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 930 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
| 845 | mtd); | 931 | mtd); |
| 846 | return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code); | 932 | u32 val; |
| 933 | |||
| 934 | val = readl(info->reg.gpmc_ecc_config); | ||
| 935 | if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs) | ||
| 936 | return -EINVAL; | ||
| 937 | |||
| 938 | /* read ecc result */ | ||
| 939 | val = readl(info->reg.gpmc_ecc1_result); | ||
| 940 | *ecc_code++ = val; /* P128e, ..., P1e */ | ||
| 941 | *ecc_code++ = val >> 16; /* P128o, ..., P1o */ | ||
| 942 | /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ | ||
| 943 | *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0); | ||
| 944 | |||
| 945 | return 0; | ||
| 847 | } | 946 | } |
| 848 | 947 | ||
| 849 | /** | 948 | /** |
| @@ -857,8 +956,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) | |||
| 857 | mtd); | 956 | mtd); |
| 858 | struct nand_chip *chip = mtd->priv; | 957 | struct nand_chip *chip = mtd->priv; |
| 859 | unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; | 958 | unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; |
| 959 | u32 val; | ||
| 860 | 960 | ||
| 861 | gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size); | 961 | /* clear ecc and enable bits */ |
| 962 | val = ECCCLEAR | ECC1; | ||
| 963 | writel(val, info->reg.gpmc_ecc_control); | ||
| 964 | |||
| 965 | /* program ecc and result sizes */ | ||
| 966 | val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) | | ||
| 967 | ECC1RESULTSIZE); | ||
| 968 | writel(val, info->reg.gpmc_ecc_size_config); | ||
| 969 | |||
| 970 | switch (mode) { | ||
| 971 | case NAND_ECC_READ: | ||
| 972 | case NAND_ECC_WRITE: | ||
| 973 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); | ||
| 974 | break; | ||
| 975 | case NAND_ECC_READSYN: | ||
| 976 | writel(ECCCLEAR, info->reg.gpmc_ecc_control); | ||
| 977 | break; | ||
| 978 | default: | ||
| 979 | dev_info(&info->pdev->dev, | ||
| 980 | "error: unrecognized Mode[%d]!\n", mode); | ||
| 981 | break; | ||
| 982 | } | ||
| 983 | |||
| 984 | /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ | ||
| 985 | val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); | ||
| 986 | writel(val, info->reg.gpmc_ecc_config); | ||
| 862 | } | 987 | } |
| 863 | 988 | ||
| 864 | /** | 989 | /** |
| @@ -886,10 +1011,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
| 886 | else | 1011 | else |
| 887 | timeo += (HZ * 20) / 1000; | 1012 | timeo += (HZ * 20) / 1000; |
| 888 | 1013 | ||
| 889 | gpmc_nand_write(info->gpmc_cs, | 1014 | writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); |
| 890 | GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF)); | ||
| 891 | while (time_before(jiffies, timeo)) { | 1015 | while (time_before(jiffies, timeo)) { |
| 892 | status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); | 1016 | status = readb(info->reg.gpmc_nand_data); |
| 893 | if (status & NAND_STATUS_READY) | 1017 | if (status & NAND_STATUS_READY) |
| 894 | break; | 1018 | break; |
| 895 | cond_resched(); | 1019 | cond_resched(); |
| @@ -909,22 +1033,13 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
| 909 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1033 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
| 910 | mtd); | 1034 | mtd); |
| 911 | 1035 | ||
| 912 | val = gpmc_read_status(GPMC_GET_IRQ_STATUS); | 1036 | val = readl(info->reg.gpmc_status); |
| 1037 | |||
| 913 | if ((val & 0x100) == 0x100) { | 1038 | if ((val & 0x100) == 0x100) { |
| 914 | /* Clear IRQ Interrupt */ | 1039 | return 1; |
| 915 | val |= 0x100; | ||
| 916 | val &= ~(0x0); | ||
| 917 | gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val); | ||
| 918 | } else { | 1040 | } else { |
| 919 | unsigned int cnt = 0; | 1041 | return 0; |
| 920 | while (cnt++ < 0x1FF) { | ||
| 921 | if ((val & 0x100) == 0x100) | ||
| 922 | return 0; | ||
| 923 | val = gpmc_read_status(GPMC_GET_IRQ_STATUS); | ||
| 924 | } | ||
| 925 | } | 1042 | } |
| 926 | |||
| 927 | return 1; | ||
| 928 | } | 1043 | } |
| 929 | 1044 | ||
| 930 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 1045 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
| @@ -1175,6 +1290,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1175 | 1290 | ||
| 1176 | info->gpmc_cs = pdata->cs; | 1291 | info->gpmc_cs = pdata->cs; |
| 1177 | info->phys_base = pdata->phys_base; | 1292 | info->phys_base = pdata->phys_base; |
| 1293 | info->reg = pdata->reg; | ||
| 1178 | 1294 | ||
| 1179 | info->mtd.priv = &info->nand; | 1295 | info->mtd.priv = &info->nand; |
| 1180 | info->mtd.name = dev_name(&pdev->dev); | 1296 | info->mtd.name = dev_name(&pdev->dev); |
