diff options
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 40c26080ecda..76beea40d2cf 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -138,7 +138,14 @@ static struct nand_ecclayout nand_hw_eccoob_8 = { | |||
138 | static struct nand_ecclayout nand_hw_eccoob_16 = { | 138 | static struct nand_ecclayout nand_hw_eccoob_16 = { |
139 | .eccbytes = 5, | 139 | .eccbytes = 5, |
140 | .eccpos = {6, 7, 8, 9, 10}, | 140 | .eccpos = {6, 7, 8, 9, 10}, |
141 | .oobfree = {{0, 6}, {12, 4}, } | 141 | .oobfree = {{0, 5}, {11, 5}, } |
142 | }; | ||
143 | |||
144 | static struct nand_ecclayout nand_hw_eccoob_64 = { | ||
145 | .eccbytes = 20, | ||
146 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, | ||
147 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, | ||
148 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } | ||
142 | }; | 149 | }; |
143 | 150 | ||
144 | #ifdef CONFIG_MTD_PARTITIONS | 151 | #ifdef CONFIG_MTD_PARTITIONS |
@@ -192,7 +199,7 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, | |||
192 | } | 199 | } |
193 | udelay(1); | 200 | udelay(1); |
194 | } | 201 | } |
195 | if (max_retries <= 0) | 202 | if (max_retries < 0) |
196 | DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", | 203 | DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", |
197 | __func__, param); | 204 | __func__, param); |
198 | } | 205 | } |
@@ -795,9 +802,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
795 | send_addr(host, (page_addr & 0xff), false); | 802 | send_addr(host, (page_addr & 0xff), false); |
796 | 803 | ||
797 | if (host->pagesize_2k) { | 804 | if (host->pagesize_2k) { |
798 | send_addr(host, (page_addr >> 8) & 0xFF, false); | 805 | if (mtd->size >= 0x10000000) { |
799 | if (mtd->size >= 0x40000000) | 806 | /* paddr_8 - paddr_15 */ |
807 | send_addr(host, (page_addr >> 8) & 0xff, false); | ||
800 | send_addr(host, (page_addr >> 16) & 0xff, true); | 808 | send_addr(host, (page_addr >> 16) & 0xff, true); |
809 | } else | ||
810 | /* paddr_8 - paddr_15 */ | ||
811 | send_addr(host, (page_addr >> 8) & 0xff, true); | ||
801 | } else { | 812 | } else { |
802 | /* One more address cycle for higher density devices */ | 813 | /* One more address cycle for higher density devices */ |
803 | if (mtd->size >= 0x4000000) { | 814 | if (mtd->size >= 0x4000000) { |
@@ -923,7 +934,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
923 | this->ecc.mode = NAND_ECC_HW; | 934 | this->ecc.mode = NAND_ECC_HW; |
924 | this->ecc.size = 512; | 935 | this->ecc.size = 512; |
925 | this->ecc.bytes = 3; | 936 | this->ecc.bytes = 3; |
926 | this->ecc.layout = &nand_hw_eccoob_8; | ||
927 | tmp = readw(host->regs + NFC_CONFIG1); | 937 | tmp = readw(host->regs + NFC_CONFIG1); |
928 | tmp |= NFC_ECC_EN; | 938 | tmp |= NFC_ECC_EN; |
929 | writew(tmp, host->regs + NFC_CONFIG1); | 939 | writew(tmp, host->regs + NFC_CONFIG1); |
@@ -957,12 +967,44 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
957 | this->ecc.layout = &nand_hw_eccoob_16; | 967 | this->ecc.layout = &nand_hw_eccoob_16; |
958 | } | 968 | } |
959 | 969 | ||
960 | host->pagesize_2k = 0; | 970 | /* first scan to find the device and get the page size */ |
971 | if (nand_scan_ident(mtd, 1)) { | ||
972 | err = -ENXIO; | ||
973 | goto escan; | ||
974 | } | ||
961 | 975 | ||
962 | /* Scan to find existence of the device */ | 976 | host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0; |
963 | if (nand_scan(mtd, 1)) { | 977 | |
964 | DEBUG(MTD_DEBUG_LEVEL0, | 978 | if (this->ecc.mode == NAND_ECC_HW) { |
965 | "MXC_ND: Unable to find any NAND device.\n"); | 979 | switch (mtd->oobsize) { |
980 | case 8: | ||
981 | this->ecc.layout = &nand_hw_eccoob_8; | ||
982 | break; | ||
983 | case 16: | ||
984 | this->ecc.layout = &nand_hw_eccoob_16; | ||
985 | break; | ||
986 | case 64: | ||
987 | this->ecc.layout = &nand_hw_eccoob_64; | ||
988 | break; | ||
989 | default: | ||
990 | /* page size not handled by HW ECC */ | ||
991 | /* switching back to soft ECC */ | ||
992 | this->ecc.size = 512; | ||
993 | this->ecc.bytes = 3; | ||
994 | this->ecc.layout = &nand_hw_eccoob_8; | ||
995 | this->ecc.mode = NAND_ECC_SOFT; | ||
996 | this->ecc.calculate = NULL; | ||
997 | this->ecc.correct = NULL; | ||
998 | this->ecc.hwctl = NULL; | ||
999 | tmp = readw(host->regs + NFC_CONFIG1); | ||
1000 | tmp &= ~NFC_ECC_EN; | ||
1001 | writew(tmp, host->regs + NFC_CONFIG1); | ||
1002 | break; | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | /* second phase scan */ | ||
1007 | if (nand_scan_tail(mtd)) { | ||
966 | err = -ENXIO; | 1008 | err = -ENXIO; |
967 | goto escan; | 1009 | goto escan; |
968 | } | 1010 | } |
@@ -985,7 +1027,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
985 | return 0; | 1027 | return 0; |
986 | 1028 | ||
987 | escan: | 1029 | escan: |
988 | free_irq(host->irq, NULL); | 1030 | free_irq(host->irq, host); |
989 | eirq: | 1031 | eirq: |
990 | iounmap(host->regs); | 1032 | iounmap(host->regs); |
991 | eres: | 1033 | eres: |
@@ -1005,7 +1047,7 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
1005 | platform_set_drvdata(pdev, NULL); | 1047 | platform_set_drvdata(pdev, NULL); |
1006 | 1048 | ||
1007 | nand_release(&host->mtd); | 1049 | nand_release(&host->mtd); |
1008 | free_irq(host->irq, NULL); | 1050 | free_irq(host->irq, host); |
1009 | iounmap(host->regs); | 1051 | iounmap(host->regs); |
1010 | kfree(host); | 1052 | kfree(host); |
1011 | 1053 | ||