diff options
Diffstat (limited to 'drivers/mtd/nand/fsl_elbc_nand.c')
| -rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 75 |
1 files changed, 28 insertions, 47 deletions
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 33d8aad8bba5..eedd8ee2c9ac 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
| @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl { | |||
| 75 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ | 75 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ |
| 76 | unsigned int oob; /* Non zero if operating on OOB data */ | 76 | unsigned int oob; /* Non zero if operating on OOB data */ |
| 77 | unsigned int counter; /* counter for the initializations */ | 77 | unsigned int counter; /* counter for the initializations */ |
| 78 | char *oob_poi; /* Place to write ECC after read back */ | ||
| 79 | }; | 78 | }; |
| 80 | 79 | ||
| 81 | /* These map to the positions used by the FCM hardware ECC generator */ | 80 | /* These map to the positions used by the FCM hardware ECC generator */ |
| @@ -244,6 +243,25 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 244 | return -EIO; | 243 | return -EIO; |
| 245 | } | 244 | } |
| 246 | 245 | ||
| 246 | if (chip->ecc.mode != NAND_ECC_HW) | ||
| 247 | return 0; | ||
| 248 | |||
| 249 | if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { | ||
| 250 | uint32_t lteccr = in_be32(&lbc->lteccr); | ||
| 251 | /* | ||
| 252 | * if command was a full page read and the ELBC | ||
| 253 | * has the LTECCR register, then bits 12-15 (ppc order) of | ||
| 254 | * LTECCR indicates which 512 byte sub-pages had fixed errors. | ||
| 255 | * bits 28-31 are uncorrectable errors, marked elsewhere. | ||
| 256 | * for small page nand only 1 bit is used. | ||
| 257 | * if the ELBC doesn't have the lteccr register it reads 0 | ||
| 258 | */ | ||
| 259 | if (lteccr & 0x000F000F) | ||
| 260 | out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ | ||
| 261 | if (lteccr & 0x000F0000) | ||
| 262 | mtd->ecc_stats.corrected++; | ||
| 263 | } | ||
| 264 | |||
| 247 | return 0; | 265 | return 0; |
| 248 | } | 266 | } |
| 249 | 267 | ||
| @@ -435,7 +453,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 435 | 453 | ||
| 436 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ | 454 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ |
| 437 | case NAND_CMD_PAGEPROG: { | 455 | case NAND_CMD_PAGEPROG: { |
| 438 | int full_page; | ||
| 439 | dev_vdbg(priv->dev, | 456 | dev_vdbg(priv->dev, |
| 440 | "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " | 457 | "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " |
| 441 | "writing %d bytes.\n", elbc_fcm_ctrl->index); | 458 | "writing %d bytes.\n", elbc_fcm_ctrl->index); |
| @@ -445,34 +462,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 445 | * write so the HW generates the ECC. | 462 | * write so the HW generates the ECC. |
| 446 | */ | 463 | */ |
| 447 | if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || | 464 | if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || |
| 448 | elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { | 465 | elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) |
| 449 | out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); | 466 | out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); |
| 450 | full_page = 0; | 467 | else |
| 451 | } else { | ||
| 452 | out_be32(&lbc->fbcr, 0); | 468 | out_be32(&lbc->fbcr, 0); |
| 453 | full_page = 1; | ||
| 454 | } | ||
| 455 | 469 | ||
| 456 | fsl_elbc_run_command(mtd); | 470 | fsl_elbc_run_command(mtd); |
| 457 | |||
| 458 | /* Read back the page in order to fill in the ECC for the | ||
| 459 | * caller. Is this really needed? | ||
| 460 | */ | ||
| 461 | if (full_page && elbc_fcm_ctrl->oob_poi) { | ||
| 462 | out_be32(&lbc->fbcr, 3); | ||
| 463 | set_addr(mtd, 6, page_addr, 1); | ||
| 464 | |||
| 465 | elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; | ||
| 466 | |||
| 467 | fsl_elbc_do_read(chip, 1); | ||
| 468 | fsl_elbc_run_command(mtd); | ||
| 469 | |||
| 470 | memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, | ||
| 471 | &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); | ||
| 472 | elbc_fcm_ctrl->index += 3; | ||
| 473 | } | ||
| 474 | |||
| 475 | elbc_fcm_ctrl->oob_poi = NULL; | ||
| 476 | return; | 471 | return; |
| 477 | } | 472 | } |
| 478 | 473 | ||
| @@ -752,13 +747,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, | |||
| 752 | struct nand_chip *chip, | 747 | struct nand_chip *chip, |
| 753 | const uint8_t *buf) | 748 | const uint8_t *buf) |
| 754 | { | 749 | { |
| 755 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 756 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; | ||
| 757 | |||
| 758 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); | 750 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); |
| 759 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | 751 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 760 | |||
| 761 | elbc_fcm_ctrl->oob_poi = chip->oob_poi; | ||
| 762 | } | 752 | } |
| 763 | 753 | ||
| 764 | static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | 754 | static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) |
| @@ -791,8 +781,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 791 | chip->bbt_md = &bbt_mirror_descr; | 781 | chip->bbt_md = &bbt_mirror_descr; |
| 792 | 782 | ||
| 793 | /* set up nand options */ | 783 | /* set up nand options */ |
| 794 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | | 784 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; |
| 795 | NAND_USE_FLASH_BBT; | 785 | chip->bbt_options = NAND_BBT_USE_FLASH; |
| 796 | 786 | ||
| 797 | chip->controller = &elbc_fcm_ctrl->controller; | 787 | chip->controller = &elbc_fcm_ctrl->controller; |
| 798 | chip->priv = priv; | 788 | chip->priv = priv; |
| @@ -829,7 +819,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
| 829 | 819 | ||
| 830 | elbc_fcm_ctrl->chips[priv->bank] = NULL; | 820 | elbc_fcm_ctrl->chips[priv->bank] = NULL; |
| 831 | kfree(priv); | 821 | kfree(priv); |
| 832 | kfree(elbc_fcm_ctrl); | ||
| 833 | return 0; | 822 | return 0; |
| 834 | } | 823 | } |
| 835 | 824 | ||
| @@ -842,13 +831,14 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) | |||
| 842 | struct resource res; | 831 | struct resource res; |
| 843 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; | 832 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; |
| 844 | static const char *part_probe_types[] | 833 | static const char *part_probe_types[] |
| 845 | = { "cmdlinepart", "RedBoot", NULL }; | 834 | = { "cmdlinepart", "RedBoot", "ofpart", NULL }; |
| 846 | struct mtd_partition *parts; | ||
| 847 | int ret; | 835 | int ret; |
| 848 | int bank; | 836 | int bank; |
| 849 | struct device *dev; | 837 | struct device *dev; |
| 850 | struct device_node *node = pdev->dev.of_node; | 838 | struct device_node *node = pdev->dev.of_node; |
| 839 | struct mtd_part_parser_data ppdata; | ||
| 851 | 840 | ||
| 841 | ppdata.of_node = pdev->dev.of_node; | ||
| 852 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) | 842 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
| 853 | return -ENODEV; | 843 | return -ENODEV; |
| 854 | lbc = fsl_lbc_ctrl_dev->regs; | 844 | lbc = fsl_lbc_ctrl_dev->regs; |
| @@ -934,17 +924,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) | |||
| 934 | 924 | ||
| 935 | /* First look for RedBoot table or partitions on the command | 925 | /* First look for RedBoot table or partitions on the command |
| 936 | * line, these take precedence over device tree information */ | 926 | * line, these take precedence over device tree information */ |
| 937 | ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); | 927 | mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, |
| 938 | if (ret < 0) | 928 | NULL, 0); |
| 939 | goto err; | ||
| 940 | |||
| 941 | if (ret == 0) { | ||
| 942 | ret = of_mtd_parse_partitions(priv->dev, node, &parts); | ||
| 943 | if (ret < 0) | ||
| 944 | goto err; | ||
| 945 | } | ||
| 946 | |||
| 947 | mtd_device_register(&priv->mtd, parts, ret); | ||
| 948 | 929 | ||
| 949 | printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", | 930 | printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", |
| 950 | (unsigned long long)res.start, priv->bank); | 931 | (unsigned long long)res.start, priv->bank); |
