diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-17 14:15:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-17 14:15:30 -0500 |
commit | ab2020f2f11fc7fb81e6c71298b0830d85412011 (patch) | |
tree | c9a6342063461dcf31278d65585bca73bdda4a84 /drivers/mtd/onenand | |
parent | 235646a486d10891bd86af28d8eac75d9f22bd2d (diff) | |
parent | 154bf89f5e3e3dc59666926f27ca4a0866f39157 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (59 commits)
mtd: mtdpart: disallow reading OOB past the end of the partition
mtd: pxa3xx_nand: NULL dereference in pxa3xx_nand_probe
UBI: use mtd->writebufsize to set minimal I/O unit size
mtd: initialize writebufsize in the MTD object of a partition
mtd: onenand: add mtd->writebufsize initialization
mtd: nand: add mtd->writebufsize initialization
mtd: cfi: add writebufsize initialization
mtd: add writebufsize field to mtd_info struct
mtd: OneNAND: OMAP2/3: prevent regulator sleeping while OneNAND is in use
mtd: OneNAND: add enable / disable methods to onenand_chip
mtd: m25p80: Fix JEDEC ID for AT26DF321
mtd: txx9ndfmc: limit transfer bytes to 512 (ECC provides 6 bytes max)
mtd: cfi_cmdset_0002: add support for Samsung K8D3x16UxC NOR chips
mtd: cfi_cmdset_0002: add support for Samsung K8D6x16UxM NOR chips
mtd: nand: ams-delta: drop omap_read/write, use ioremap
mtd: m25p80: add debugging trace in sst_write
mtd: nand: ams-delta: select for built-in by default
mtd: OneNAND: lighten scary initial bad block messages
mtd: OneNAND: OMAP2/3: add support for command line partitioning
mtd: nand: rearrange ONFI revision checking, add ONFI 2.3
...
Fix up trivial conflict in drivers/mtd/Kconfig as per DavidW.
Diffstat (limited to 'drivers/mtd/onenand')
-rw-r--r-- | drivers/mtd/onenand/omap2.c | 80 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 81 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_bbt.c | 10 | ||||
-rw-r--r-- | drivers/mtd/onenand/samsung.c | 7 |
4 files changed, 126 insertions, 52 deletions
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index d0894ca7798..ac31f461cc1 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | #include <linux/io.h> | 36 | #include <linux/io.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/regulator/consumer.h> | ||
38 | 39 | ||
39 | #include <asm/mach/flash.h> | 40 | #include <asm/mach/flash.h> |
40 | #include <plat/gpmc.h> | 41 | #include <plat/gpmc.h> |
@@ -63,8 +64,13 @@ struct omap2_onenand { | |||
63 | int dma_channel; | 64 | int dma_channel; |
64 | int freq; | 65 | int freq; |
65 | int (*setup)(void __iomem *base, int freq); | 66 | int (*setup)(void __iomem *base, int freq); |
67 | struct regulator *regulator; | ||
66 | }; | 68 | }; |
67 | 69 | ||
70 | #ifdef CONFIG_MTD_PARTITIONS | ||
71 | static const char *part_probes[] = { "cmdlinepart", NULL, }; | ||
72 | #endif | ||
73 | |||
68 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) | 74 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) |
69 | { | 75 | { |
70 | struct omap2_onenand *c = data; | 76 | struct omap2_onenand *c = data; |
@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, | |||
108 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) | 114 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) |
109 | { | 115 | { |
110 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | 116 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); |
117 | struct onenand_chip *this = mtd->priv; | ||
111 | unsigned int intr = 0; | 118 | unsigned int intr = 0; |
112 | unsigned int ctrl; | 119 | unsigned int ctrl, ctrl_mask; |
113 | unsigned long timeout; | 120 | unsigned long timeout; |
114 | u32 syscfg; | 121 | u32 syscfg; |
115 | 122 | ||
@@ -180,7 +187,8 @@ retry: | |||
180 | if (result == 0) { | 187 | if (result == 0) { |
181 | /* Timeout after 20ms */ | 188 | /* Timeout after 20ms */ |
182 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | 189 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); |
183 | if (ctrl & ONENAND_CTRL_ONGO) { | 190 | if (ctrl & ONENAND_CTRL_ONGO && |
191 | !this->ongoing) { | ||
184 | /* | 192 | /* |
185 | * The operation seems to be still going | 193 | * The operation seems to be still going |
186 | * so give it some more time. | 194 | * so give it some more time. |
@@ -269,7 +277,11 @@ retry: | |||
269 | return -EIO; | 277 | return -EIO; |
270 | } | 278 | } |
271 | 279 | ||
272 | if (ctrl & 0xFE9F) | 280 | ctrl_mask = 0xFE9F; |
281 | if (this->ongoing) | ||
282 | ctrl_mask &= ~0x8000; | ||
283 | |||
284 | if (ctrl & ctrl_mask) | ||
273 | wait_warn("unexpected controller status", state, ctrl, intr); | 285 | wait_warn("unexpected controller status", state, ctrl, intr); |
274 | 286 | ||
275 | return 0; | 287 | return 0; |
@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) | |||
591 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); | 603 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); |
592 | } | 604 | } |
593 | 605 | ||
606 | static int omap2_onenand_enable(struct mtd_info *mtd) | ||
607 | { | ||
608 | int ret; | ||
609 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
610 | |||
611 | ret = regulator_enable(c->regulator); | ||
612 | if (ret != 0) | ||
613 | dev_err(&c->pdev->dev, "cant enable regulator\n"); | ||
614 | |||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static int omap2_onenand_disable(struct mtd_info *mtd) | ||
619 | { | ||
620 | int ret; | ||
621 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
622 | |||
623 | ret = regulator_disable(c->regulator); | ||
624 | if (ret != 0) | ||
625 | dev_err(&c->pdev->dev, "cant disable regulator\n"); | ||
626 | |||
627 | return ret; | ||
628 | } | ||
629 | |||
594 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) | 630 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) |
595 | { | 631 | { |
596 | struct omap_onenand_platform_data *pdata; | 632 | struct omap_onenand_platform_data *pdata; |
@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
705 | } | 741 | } |
706 | } | 742 | } |
707 | 743 | ||
744 | if (pdata->regulator_can_sleep) { | ||
745 | c->regulator = regulator_get(&pdev->dev, "vonenand"); | ||
746 | if (IS_ERR(c->regulator)) { | ||
747 | dev_err(&pdev->dev, "Failed to get regulator\n"); | ||
748 | goto err_release_dma; | ||
749 | } | ||
750 | c->onenand.enable = omap2_onenand_enable; | ||
751 | c->onenand.disable = omap2_onenand_disable; | ||
752 | } | ||
753 | |||
708 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | 754 | if ((r = onenand_scan(&c->mtd, 1)) < 0) |
709 | goto err_release_dma; | 755 | goto err_release_regulator; |
710 | 756 | ||
711 | switch ((c->onenand.version_id >> 4) & 0xf) { | 757 | switch ((c->onenand.version_id >> 4) & 0xf) { |
712 | case 0: | 758 | case 0: |
@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
727 | } | 773 | } |
728 | 774 | ||
729 | #ifdef CONFIG_MTD_PARTITIONS | 775 | #ifdef CONFIG_MTD_PARTITIONS |
730 | if (pdata->parts != NULL) | 776 | r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); |
731 | r = add_mtd_partitions(&c->mtd, pdata->parts, | 777 | if (r > 0) |
732 | pdata->nr_parts); | 778 | r = add_mtd_partitions(&c->mtd, c->parts, r); |
779 | else if (pdata->parts != NULL) | ||
780 | r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); | ||
733 | else | 781 | else |
734 | #endif | 782 | #endif |
735 | r = add_mtd_device(&c->mtd); | 783 | r = add_mtd_device(&c->mtd); |
736 | if (r < 0) | 784 | if (r) |
737 | goto err_release_onenand; | 785 | goto err_release_onenand; |
738 | 786 | ||
739 | platform_set_drvdata(pdev, c); | 787 | platform_set_drvdata(pdev, c); |
@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
742 | 790 | ||
743 | err_release_onenand: | 791 | err_release_onenand: |
744 | onenand_release(&c->mtd); | 792 | onenand_release(&c->mtd); |
793 | err_release_regulator: | ||
794 | regulator_put(c->regulator); | ||
745 | err_release_dma: | 795 | err_release_dma: |
746 | if (c->dma_channel != -1) | 796 | if (c->dma_channel != -1) |
747 | omap_free_dma(c->dma_channel); | 797 | omap_free_dma(c->dma_channel); |
@@ -757,6 +807,7 @@ err_release_mem_region: | |||
757 | err_free_cs: | 807 | err_free_cs: |
758 | gpmc_cs_free(c->gpmc_cs); | 808 | gpmc_cs_free(c->gpmc_cs); |
759 | err_kfree: | 809 | err_kfree: |
810 | kfree(c->parts); | ||
760 | kfree(c); | 811 | kfree(c); |
761 | 812 | ||
762 | return r; | 813 | return r; |
@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
766 | { | 817 | { |
767 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); | 818 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); |
768 | 819 | ||
769 | BUG_ON(c == NULL); | ||
770 | |||
771 | #ifdef CONFIG_MTD_PARTITIONS | ||
772 | if (c->parts) | ||
773 | del_mtd_partitions(&c->mtd); | ||
774 | else | ||
775 | del_mtd_device(&c->mtd); | ||
776 | #else | ||
777 | del_mtd_device(&c->mtd); | ||
778 | #endif | ||
779 | |||
780 | onenand_release(&c->mtd); | 820 | onenand_release(&c->mtd); |
821 | regulator_put(c->regulator); | ||
781 | if (c->dma_channel != -1) | 822 | if (c->dma_channel != -1) |
782 | omap_free_dma(c->dma_channel); | 823 | omap_free_dma(c->dma_channel); |
783 | omap2_onenand_shutdown(pdev); | 824 | omap2_onenand_shutdown(pdev); |
@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
789 | iounmap(c->onenand.base); | 830 | iounmap(c->onenand.base); |
790 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); | 831 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); |
791 | gpmc_cs_free(c->gpmc_cs); | 832 | gpmc_cs_free(c->gpmc_cs); |
833 | kfree(c->parts); | ||
792 | kfree(c); | 834 | kfree(c); |
793 | 835 | ||
794 | return 0; | 836 | return 0; |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6b3a875647c..bac41caa8df 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
400 | value = onenand_bufferram_address(this, block); | 400 | value = onenand_bufferram_address(this, block); |
401 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | 401 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); |
402 | 402 | ||
403 | if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || | 403 | if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) |
404 | ONENAND_IS_4KB_PAGE(this)) | ||
405 | /* It is always BufferRAM0 */ | 404 | /* It is always BufferRAM0 */ |
406 | ONENAND_SET_BUFFERRAM0(this); | 405 | ONENAND_SET_BUFFERRAM0(this); |
407 | else | 406 | else |
@@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
430 | case FLEXONENAND_CMD_RECOVER_LSB: | 429 | case FLEXONENAND_CMD_RECOVER_LSB: |
431 | case ONENAND_CMD_READ: | 430 | case ONENAND_CMD_READ: |
432 | case ONENAND_CMD_READOOB: | 431 | case ONENAND_CMD_READOOB: |
433 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 432 | if (ONENAND_IS_4KB_PAGE(this)) |
434 | /* It is always BufferRAM0 */ | 433 | /* It is always BufferRAM0 */ |
435 | dataram = ONENAND_SET_BUFFERRAM0(this); | 434 | dataram = ONENAND_SET_BUFFERRAM0(this); |
436 | else | 435 | else |
@@ -949,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state) | |||
949 | if (this->state == FL_READY) { | 948 | if (this->state == FL_READY) { |
950 | this->state = new_state; | 949 | this->state = new_state; |
951 | spin_unlock(&this->chip_lock); | 950 | spin_unlock(&this->chip_lock); |
951 | if (new_state != FL_PM_SUSPENDED && this->enable) | ||
952 | this->enable(mtd); | ||
952 | break; | 953 | break; |
953 | } | 954 | } |
954 | if (new_state == FL_PM_SUSPENDED) { | 955 | if (new_state == FL_PM_SUSPENDED) { |
@@ -975,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd) | |||
975 | { | 976 | { |
976 | struct onenand_chip *this = mtd->priv; | 977 | struct onenand_chip *this = mtd->priv; |
977 | 978 | ||
979 | if (this->state != FL_PM_SUSPENDED && this->disable) | ||
980 | this->disable(mtd); | ||
978 | /* Release the chip */ | 981 | /* Release the chip */ |
979 | spin_lock(&this->chip_lock); | 982 | spin_lock(&this->chip_lock); |
980 | this->state = FL_READY; | 983 | this->state = FL_READY; |
@@ -1353,7 +1356,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
1353 | 1356 | ||
1354 | stats = mtd->ecc_stats; | 1357 | stats = mtd->ecc_stats; |
1355 | 1358 | ||
1356 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1359 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1357 | 1360 | ||
1358 | while (read < len) { | 1361 | while (read < len) { |
1359 | cond_resched(); | 1362 | cond_resched(); |
@@ -1429,7 +1432,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1429 | int ret; | 1432 | int ret; |
1430 | 1433 | ||
1431 | onenand_get_device(mtd, FL_READING); | 1434 | onenand_get_device(mtd, FL_READING); |
1432 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 1435 | ret = ONENAND_IS_4KB_PAGE(this) ? |
1433 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : | 1436 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : |
1434 | onenand_read_ops_nolock(mtd, from, &ops); | 1437 | onenand_read_ops_nolock(mtd, from, &ops); |
1435 | onenand_release_device(mtd); | 1438 | onenand_release_device(mtd); |
@@ -1464,7 +1467,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1464 | 1467 | ||
1465 | onenand_get_device(mtd, FL_READING); | 1468 | onenand_get_device(mtd, FL_READING); |
1466 | if (ops->datbuf) | 1469 | if (ops->datbuf) |
1467 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 1470 | ret = ONENAND_IS_4KB_PAGE(this) ? |
1468 | onenand_mlc_read_ops_nolock(mtd, from, ops) : | 1471 | onenand_mlc_read_ops_nolock(mtd, from, ops) : |
1469 | onenand_read_ops_nolock(mtd, from, ops); | 1472 | onenand_read_ops_nolock(mtd, from, ops); |
1470 | else | 1473 | else |
@@ -1485,8 +1488,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1485 | { | 1488 | { |
1486 | struct onenand_chip *this = mtd->priv; | 1489 | struct onenand_chip *this = mtd->priv; |
1487 | unsigned long timeout; | 1490 | unsigned long timeout; |
1488 | unsigned int interrupt; | 1491 | unsigned int interrupt, ctrl, ecc, addr1, addr8; |
1489 | unsigned int ctrl; | ||
1490 | 1492 | ||
1491 | /* The 20 msec is enough */ | 1493 | /* The 20 msec is enough */ |
1492 | timeout = jiffies + msecs_to_jiffies(20); | 1494 | timeout = jiffies + msecs_to_jiffies(20); |
@@ -1498,25 +1500,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1498 | /* To get correct interrupt status in timeout case */ | 1500 | /* To get correct interrupt status in timeout case */ |
1499 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1501 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
1500 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1502 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
1503 | addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1); | ||
1504 | addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8); | ||
1501 | 1505 | ||
1502 | if (interrupt & ONENAND_INT_READ) { | 1506 | if (interrupt & ONENAND_INT_READ) { |
1503 | int ecc = onenand_read_ecc(this); | 1507 | ecc = onenand_read_ecc(this); |
1504 | if (ecc & ONENAND_ECC_2BIT_ALL) { | 1508 | if (ecc & ONENAND_ECC_2BIT_ALL) { |
1505 | printk(KERN_WARNING "%s: ecc error = 0x%04x, " | 1509 | printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x " |
1506 | "controller error 0x%04x\n", | 1510 | "intr 0x%04x addr1 %#x addr8 %#x\n", |
1507 | __func__, ecc, ctrl); | 1511 | __func__, ecc, ctrl, interrupt, addr1, addr8); |
1508 | return ONENAND_BBT_READ_ECC_ERROR; | 1512 | return ONENAND_BBT_READ_ECC_ERROR; |
1509 | } | 1513 | } |
1510 | } else { | 1514 | } else { |
1511 | printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", | 1515 | printk(KERN_ERR "%s: read timeout! ctrl 0x%04x " |
1512 | __func__, ctrl, interrupt); | 1516 | "intr 0x%04x addr1 %#x addr8 %#x\n", |
1517 | __func__, ctrl, interrupt, addr1, addr8); | ||
1513 | return ONENAND_BBT_READ_FATAL_ERROR; | 1518 | return ONENAND_BBT_READ_FATAL_ERROR; |
1514 | } | 1519 | } |
1515 | 1520 | ||
1516 | /* Initial bad block case: 0x2400 or 0x0400 */ | 1521 | /* Initial bad block case: 0x2400 or 0x0400 */ |
1517 | if (ctrl & ONENAND_CTRL_ERROR) { | 1522 | if (ctrl & ONENAND_CTRL_ERROR) { |
1518 | printk(KERN_DEBUG "%s: controller error = 0x%04x\n", | 1523 | printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x " |
1519 | __func__, ctrl); | 1524 | "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8); |
1520 | return ONENAND_BBT_READ_ERROR; | 1525 | return ONENAND_BBT_READ_ERROR; |
1521 | } | 1526 | } |
1522 | 1527 | ||
@@ -1558,7 +1563,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1558 | 1563 | ||
1559 | column = from & (mtd->oobsize - 1); | 1564 | column = from & (mtd->oobsize - 1); |
1560 | 1565 | ||
1561 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1566 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1562 | 1567 | ||
1563 | while (read < len) { | 1568 | while (read < len) { |
1564 | cond_resched(); | 1569 | cond_resched(); |
@@ -1612,7 +1617,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1612 | u_char *oob_buf = this->oob_buf; | 1617 | u_char *oob_buf = this->oob_buf; |
1613 | int status, i, readcmd; | 1618 | int status, i, readcmd; |
1614 | 1619 | ||
1615 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1620 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1616 | 1621 | ||
1617 | this->command(mtd, readcmd, to, mtd->oobsize); | 1622 | this->command(mtd, readcmd, to, mtd->oobsize); |
1618 | onenand_update_bufferram(mtd, to, 0); | 1623 | onenand_update_bufferram(mtd, to, 0); |
@@ -1845,7 +1850,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1845 | const u_char *buf = ops->datbuf; | 1850 | const u_char *buf = ops->datbuf; |
1846 | const u_char *oob = ops->oobbuf; | 1851 | const u_char *oob = ops->oobbuf; |
1847 | u_char *oobbuf; | 1852 | u_char *oobbuf; |
1848 | int ret = 0; | 1853 | int ret = 0, cmd; |
1849 | 1854 | ||
1850 | DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", | 1855 | DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", |
1851 | __func__, (unsigned int) to, (int) len); | 1856 | __func__, (unsigned int) to, (int) len); |
@@ -1954,7 +1959,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1954 | ONENAND_SET_NEXT_BUFFERRAM(this); | 1959 | ONENAND_SET_NEXT_BUFFERRAM(this); |
1955 | } | 1960 | } |
1956 | 1961 | ||
1957 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | 1962 | this->ongoing = 0; |
1963 | cmd = ONENAND_CMD_PROG; | ||
1964 | |||
1965 | /* Exclude 1st OTP and OTP blocks for cache program feature */ | ||
1966 | if (ONENAND_IS_CACHE_PROGRAM(this) && | ||
1967 | likely(onenand_block(this, to) != 0) && | ||
1968 | ONENAND_IS_4KB_PAGE(this) && | ||
1969 | ((written + thislen) < len)) { | ||
1970 | cmd = ONENAND_CMD_2X_CACHE_PROG; | ||
1971 | this->ongoing = 1; | ||
1972 | } | ||
1973 | |||
1974 | this->command(mtd, cmd, to, mtd->writesize); | ||
1958 | 1975 | ||
1959 | /* | 1976 | /* |
1960 | * 2 PLANE, MLC, and Flex-OneNAND wait here | 1977 | * 2 PLANE, MLC, and Flex-OneNAND wait here |
@@ -2067,7 +2084,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, | |||
2067 | 2084 | ||
2068 | oobbuf = this->oob_buf; | 2085 | oobbuf = this->oob_buf; |
2069 | 2086 | ||
2070 | oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; | 2087 | oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; |
2071 | 2088 | ||
2072 | /* Loop until all data write */ | 2089 | /* Loop until all data write */ |
2073 | while (written < len) { | 2090 | while (written < len) { |
@@ -2086,7 +2103,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, | |||
2086 | memcpy(oobbuf + column, buf, thislen); | 2103 | memcpy(oobbuf + column, buf, thislen); |
2087 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | 2104 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); |
2088 | 2105 | ||
2089 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { | 2106 | if (ONENAND_IS_4KB_PAGE(this)) { |
2090 | /* Set main area of DataRAM to 0xff*/ | 2107 | /* Set main area of DataRAM to 0xff*/ |
2091 | memset(this->page_buf, 0xff, mtd->writesize); | 2108 | memset(this->page_buf, 0xff, mtd->writesize); |
2092 | this->write_bufferram(mtd, ONENAND_DATARAM, | 2109 | this->write_bufferram(mtd, ONENAND_DATARAM, |
@@ -2481,7 +2498,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2481 | /* Grab the lock and see if the device is available */ | 2498 | /* Grab the lock and see if the device is available */ |
2482 | onenand_get_device(mtd, FL_ERASING); | 2499 | onenand_get_device(mtd, FL_ERASING); |
2483 | 2500 | ||
2484 | if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { | 2501 | if (ONENAND_IS_4KB_PAGE(this) || region || |
2502 | instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { | ||
2485 | /* region is set for Flex-OneNAND (no mb erase) */ | 2503 | /* region is set for Flex-OneNAND (no mb erase) */ |
2486 | ret = onenand_block_by_block_erase(mtd, instr, | 2504 | ret = onenand_block_by_block_erase(mtd, instr, |
2487 | region, block_size); | 2505 | region, block_size); |
@@ -3029,7 +3047,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
3029 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 3047 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
3030 | this->wait(mtd, FL_OTPING); | 3048 | this->wait(mtd, FL_OTPING); |
3031 | 3049 | ||
3032 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 3050 | ret = ONENAND_IS_4KB_PAGE(this) ? |
3033 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : | 3051 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : |
3034 | onenand_read_ops_nolock(mtd, from, &ops); | 3052 | onenand_read_ops_nolock(mtd, from, &ops); |
3035 | 3053 | ||
@@ -3377,8 +3395,10 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3377 | case ONENAND_DEVICE_DENSITY_4Gb: | 3395 | case ONENAND_DEVICE_DENSITY_4Gb: |
3378 | if (ONENAND_IS_DDP(this)) | 3396 | if (ONENAND_IS_DDP(this)) |
3379 | this->options |= ONENAND_HAS_2PLANE; | 3397 | this->options |= ONENAND_HAS_2PLANE; |
3380 | else if (numbufs == 1) | 3398 | else if (numbufs == 1) { |
3381 | this->options |= ONENAND_HAS_4KB_PAGE; | 3399 | this->options |= ONENAND_HAS_4KB_PAGE; |
3400 | this->options |= ONENAND_HAS_CACHE_PROGRAM; | ||
3401 | } | ||
3382 | 3402 | ||
3383 | case ONENAND_DEVICE_DENSITY_2Gb: | 3403 | case ONENAND_DEVICE_DENSITY_2Gb: |
3384 | /* 2Gb DDP does not have 2 plane */ | 3404 | /* 2Gb DDP does not have 2 plane */ |
@@ -3399,7 +3419,11 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3399 | break; | 3419 | break; |
3400 | } | 3420 | } |
3401 | 3421 | ||
3402 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 3422 | /* The MLC has 4KiB pagesize. */ |
3423 | if (ONENAND_IS_MLC(this)) | ||
3424 | this->options |= ONENAND_HAS_4KB_PAGE; | ||
3425 | |||
3426 | if (ONENAND_IS_4KB_PAGE(this)) | ||
3403 | this->options &= ~ONENAND_HAS_2PLANE; | 3427 | this->options &= ~ONENAND_HAS_2PLANE; |
3404 | 3428 | ||
3405 | if (FLEXONENAND(this)) { | 3429 | if (FLEXONENAND(this)) { |
@@ -3415,6 +3439,8 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3415 | printk(KERN_DEBUG "Chip has 2 plane\n"); | 3439 | printk(KERN_DEBUG "Chip has 2 plane\n"); |
3416 | if (this->options & ONENAND_HAS_4KB_PAGE) | 3440 | if (this->options & ONENAND_HAS_4KB_PAGE) |
3417 | printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); | 3441 | printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); |
3442 | if (this->options & ONENAND_HAS_CACHE_PROGRAM) | ||
3443 | printk(KERN_DEBUG "Chip has cache program feature\n"); | ||
3418 | } | 3444 | } |
3419 | 3445 | ||
3420 | /** | 3446 | /** |
@@ -3831,7 +3857,7 @@ static int onenand_probe(struct mtd_info *mtd) | |||
3831 | /* The data buffer size is equal to page size */ | 3857 | /* The data buffer size is equal to page size */ |
3832 | mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); | 3858 | mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); |
3833 | /* We use the full BufferRAM */ | 3859 | /* We use the full BufferRAM */ |
3834 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 3860 | if (ONENAND_IS_4KB_PAGE(this)) |
3835 | mtd->writesize <<= 1; | 3861 | mtd->writesize <<= 1; |
3836 | 3862 | ||
3837 | mtd->oobsize = mtd->writesize >> 5; | 3863 | mtd->oobsize = mtd->writesize >> 5; |
@@ -4054,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
4054 | mtd->block_isbad = onenand_block_isbad; | 4080 | mtd->block_isbad = onenand_block_isbad; |
4055 | mtd->block_markbad = onenand_block_markbad; | 4081 | mtd->block_markbad = onenand_block_markbad; |
4056 | mtd->owner = THIS_MODULE; | 4082 | mtd->owner = THIS_MODULE; |
4083 | mtd->writebufsize = mtd->writesize; | ||
4057 | 4084 | ||
4058 | /* Unlock whole block */ | 4085 | /* Unlock whole block */ |
4059 | this->unlock_all(mtd); | 4086 | this->unlock_all(mtd); |
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 01ab5b3c453..fc2c16a0fd1 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -91,16 +91,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
91 | for (j = 0; j < len; j++) { | 91 | for (j = 0; j < len; j++) { |
92 | /* No need to read pages fully, | 92 | /* No need to read pages fully, |
93 | * just read required OOB bytes */ | 93 | * just read required OOB bytes */ |
94 | ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); | 94 | ret = onenand_bbt_read_oob(mtd, |
95 | from + j * this->writesize + bd->offs, &ops); | ||
95 | 96 | ||
96 | /* If it is a initial bad block, just ignore it */ | 97 | /* If it is a initial bad block, just ignore it */ |
97 | if (ret == ONENAND_BBT_READ_FATAL_ERROR) | 98 | if (ret == ONENAND_BBT_READ_FATAL_ERROR) |
98 | return -EIO; | 99 | return -EIO; |
99 | 100 | ||
100 | if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { | 101 | if (ret || check_short_pattern(&buf[j * scanlen], |
102 | scanlen, this->writesize, bd)) { | ||
101 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); | 103 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); |
102 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 104 | printk(KERN_INFO "OneNAND eraseblock %d is an " |
103 | i >> 1, (unsigned int) from); | 105 | "initial bad block\n", i >> 1); |
104 | mtd->ecc_stats.badblocks++; | 106 | mtd->ecc_stats.badblocks++; |
105 | break; | 107 | break; |
106 | } | 108 | } |
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 0de7a05e6de..a4c74a9ba43 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c | |||
@@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
651 | void __iomem *p; | 651 | void __iomem *p; |
652 | void *buf = (void *) buffer; | 652 | void *buf = (void *) buffer; |
653 | dma_addr_t dma_src, dma_dst; | 653 | dma_addr_t dma_src, dma_dst; |
654 | int err, page_dma = 0; | 654 | int err, ofs, page_dma = 0; |
655 | struct device *dev = &onenand->pdev->dev; | 655 | struct device *dev = &onenand->pdev->dev; |
656 | 656 | ||
657 | p = this->base + area; | 657 | p = this->base + area; |
@@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
677 | if (!page) | 677 | if (!page) |
678 | goto normal; | 678 | goto normal; |
679 | 679 | ||
680 | /* Page offset */ | ||
681 | ofs = ((size_t) buf & ~PAGE_MASK); | ||
680 | page_dma = 1; | 682 | page_dma = 1; |
683 | |||
681 | /* DMA routine */ | 684 | /* DMA routine */ |
682 | dma_src = onenand->phys_base + (p - this->base); | 685 | dma_src = onenand->phys_base + (p - this->base); |
683 | dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); | 686 | dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE); |
684 | } else { | 687 | } else { |
685 | /* DMA routine */ | 688 | /* DMA routine */ |
686 | dma_src = onenand->phys_base + (p - this->base); | 689 | dma_src = onenand->phys_base + (p - this->base); |