diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-10-05 06:14:21 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-11-12 02:33:18 -0500 |
commit | 9467114ef43c971f0ae8aee3729d412125a2f432 (patch) | |
tree | 51f0abdfb14cd5b89fabdd1b5bf6efa6307a24a9 /drivers/mtd/nand | |
parent | 2d69c7fadd8580a7cea3ae0caa90a1c2a92ab021 (diff) |
mxc_nand: Add NFC V2 support
The v2 version of this controller is used on i.MX35/25 SoCs.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 81 |
1 files changed, 68 insertions, 13 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 09b9aab6823d..4a696820d6d4 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -33,9 +33,13 @@ | |||
33 | 33 | ||
34 | #include <asm/mach/flash.h> | 34 | #include <asm/mach/flash.h> |
35 | #include <mach/mxc_nand.h> | 35 | #include <mach/mxc_nand.h> |
36 | #include <mach/hardware.h> | ||
36 | 37 | ||
37 | #define DRIVER_NAME "mxc_nand" | 38 | #define DRIVER_NAME "mxc_nand" |
38 | 39 | ||
40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | ||
41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27()) | ||
42 | |||
39 | /* Addresses for NFC registers */ | 43 | /* Addresses for NFC registers */ |
40 | #define NFC_BUF_SIZE 0xE00 | 44 | #define NFC_BUF_SIZE 0xE00 |
41 | #define NFC_BUF_ADDR 0xE04 | 45 | #define NFC_BUF_ADDR 0xE04 |
@@ -46,8 +50,10 @@ | |||
46 | #define NFC_RSLTMAIN_AREA 0xE0E | 50 | #define NFC_RSLTMAIN_AREA 0xE0E |
47 | #define NFC_RSLTSPARE_AREA 0xE10 | 51 | #define NFC_RSLTSPARE_AREA 0xE10 |
48 | #define NFC_WRPROT 0xE12 | 52 | #define NFC_WRPROT 0xE12 |
49 | #define NFC_UNLOCKSTART_BLKADDR 0xE14 | 53 | #define NFC_V1_UNLOCKSTART_BLKADDR 0xe14 |
50 | #define NFC_UNLOCKEND_BLKADDR 0xE16 | 54 | #define NFC_V1_UNLOCKEND_BLKADDR 0xe16 |
55 | #define NFC_V21_UNLOCKSTART_BLKADDR 0xe20 | ||
56 | #define NFC_V21_UNLOCKEND_BLKADDR 0xe22 | ||
51 | #define NFC_NF_WRPRST 0xE18 | 57 | #define NFC_NF_WRPRST 0xE18 |
52 | #define NFC_CONFIG1 0xE1A | 58 | #define NFC_CONFIG1 0xE1A |
53 | #define NFC_CONFIG2 0xE1C | 59 | #define NFC_CONFIG2 0xE1C |
@@ -116,19 +122,47 @@ struct mxc_nand_host { | |||
116 | #define TROP_US_DELAY 2000 | 122 | #define TROP_US_DELAY 2000 |
117 | 123 | ||
118 | /* OOB placement block for use with hardware ecc generation */ | 124 | /* OOB placement block for use with hardware ecc generation */ |
119 | static struct nand_ecclayout nand_hw_eccoob_smallpage = { | 125 | static struct nand_ecclayout nandv1_hw_eccoob_smallpage = { |
120 | .eccbytes = 5, | 126 | .eccbytes = 5, |
121 | .eccpos = {6, 7, 8, 9, 10}, | 127 | .eccpos = {6, 7, 8, 9, 10}, |
122 | .oobfree = {{0, 5}, {12, 4}, } | 128 | .oobfree = {{0, 5}, {12, 4}, } |
123 | }; | 129 | }; |
124 | 130 | ||
125 | static struct nand_ecclayout nand_hw_eccoob_largepage = { | 131 | static struct nand_ecclayout nandv1_hw_eccoob_largepage = { |
126 | .eccbytes = 20, | 132 | .eccbytes = 20, |
127 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, | 133 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, |
128 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, | 134 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, |
129 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } | 135 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } |
130 | }; | 136 | }; |
131 | 137 | ||
138 | /* OOB description for 512 byte pages with 16 byte OOB */ | ||
139 | static struct nand_ecclayout nandv2_hw_eccoob_smallpage = { | ||
140 | .eccbytes = 1 * 9, | ||
141 | .eccpos = { | ||
142 | 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
143 | }, | ||
144 | .oobfree = { | ||
145 | {.offset = 0, .length = 5} | ||
146 | } | ||
147 | }; | ||
148 | |||
149 | /* OOB description for 2048 byte pages with 64 byte OOB */ | ||
150 | static struct nand_ecclayout nandv2_hw_eccoob_largepage = { | ||
151 | .eccbytes = 4 * 9, | ||
152 | .eccpos = { | ||
153 | 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
154 | 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
155 | 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
156 | 55, 56, 57, 58, 59, 60, 61, 62, 63 | ||
157 | }, | ||
158 | .oobfree = { | ||
159 | {.offset = 2, .length = 4}, | ||
160 | {.offset = 16, .length = 7}, | ||
161 | {.offset = 32, .length = 7}, | ||
162 | {.offset = 48, .length = 7} | ||
163 | } | ||
164 | }; | ||
165 | |||
132 | #ifdef CONFIG_MTD_PARTITIONS | 166 | #ifdef CONFIG_MTD_PARTITIONS |
133 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 167 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; |
134 | #endif | 168 | #endif |
@@ -219,7 +253,7 @@ static void send_page(struct mtd_info *mtd, unsigned int ops) | |||
219 | struct mxc_nand_host *host = nand_chip->priv; | 253 | struct mxc_nand_host *host = nand_chip->priv; |
220 | int bufs, i; | 254 | int bufs, i; |
221 | 255 | ||
222 | if (mtd->writesize > 512) | 256 | if (nfc_is_v1() && mtd->writesize > 512) |
223 | bufs = 4; | 257 | bufs = 4; |
224 | else | 258 | else |
225 | bufs = 1; | 259 | bufs = 1; |
@@ -613,6 +647,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
613 | send_cmd(host, command, true); | 647 | send_cmd(host, command, true); |
614 | mxc_do_addr_cycle(mtd, column, page_addr); | 648 | mxc_do_addr_cycle(mtd, column, page_addr); |
615 | send_read_id(host); | 649 | send_read_id(host); |
650 | host->buf_start = column; | ||
616 | break; | 651 | break; |
617 | 652 | ||
618 | case NAND_CMD_ERASE1: | 653 | case NAND_CMD_ERASE1: |
@@ -633,6 +668,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
633 | struct resource *res; | 668 | struct resource *res; |
634 | uint16_t tmp; | 669 | uint16_t tmp; |
635 | int err = 0, nr_parts = 0; | 670 | int err = 0, nr_parts = 0; |
671 | struct nand_ecclayout *oob_smallpage, *oob_largepage; | ||
636 | 672 | ||
637 | /* Allocate memory for MTD device structure and private data */ | 673 | /* Allocate memory for MTD device structure and private data */ |
638 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + | 674 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + |
@@ -641,7 +677,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
641 | return -ENOMEM; | 677 | return -ENOMEM; |
642 | 678 | ||
643 | host->data_buf = (uint8_t *)(host + 1); | 679 | host->data_buf = (uint8_t *)(host + 1); |
644 | host->spare_len = 16; | ||
645 | 680 | ||
646 | host->dev = &pdev->dev; | 681 | host->dev = &pdev->dev; |
647 | /* structures must be linked */ | 682 | /* structures must be linked */ |
@@ -686,10 +721,23 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
686 | goto eres; | 721 | goto eres; |
687 | } | 722 | } |
688 | 723 | ||
689 | host->regs = host->base; | ||
690 | host->main_area0 = host->base; | 724 | host->main_area0 = host->base; |
691 | host->main_area1 = host->base + 0x200; | 725 | host->main_area1 = host->base + 0x200; |
692 | host->spare0 = host->base + 0x800; | 726 | |
727 | if (nfc_is_v21()) { | ||
728 | host->regs = host->base + 0x1000; | ||
729 | host->spare0 = host->base + 0x1000; | ||
730 | host->spare_len = 64; | ||
731 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
732 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
733 | } else if (nfc_is_v1()) { | ||
734 | host->regs = host->base; | ||
735 | host->spare0 = host->base + 0x800; | ||
736 | host->spare_len = 16; | ||
737 | oob_smallpage = &nandv1_hw_eccoob_smallpage; | ||
738 | oob_largepage = &nandv1_hw_eccoob_largepage; | ||
739 | } else | ||
740 | BUG(); | ||
693 | 741 | ||
694 | tmp = readw(host->regs + NFC_CONFIG1); | 742 | tmp = readw(host->regs + NFC_CONFIG1); |
695 | tmp |= NFC_INT_MSK; | 743 | tmp |= NFC_INT_MSK; |
@@ -711,15 +759,22 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
711 | writew(0x2, host->regs + NFC_CONFIG); | 759 | writew(0x2, host->regs + NFC_CONFIG); |
712 | 760 | ||
713 | /* Blocks to be unlocked */ | 761 | /* Blocks to be unlocked */ |
714 | writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); | 762 | if (nfc_is_v21()) { |
715 | writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); | 763 | writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); |
764 | writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); | ||
765 | this->ecc.bytes = 9; | ||
766 | } else if (nfc_is_v1()) { | ||
767 | writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); | ||
768 | writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); | ||
769 | this->ecc.bytes = 3; | ||
770 | } else | ||
771 | BUG(); | ||
716 | 772 | ||
717 | /* Unlock Block Command for given address range */ | 773 | /* Unlock Block Command for given address range */ |
718 | writew(0x4, host->regs + NFC_WRPROT); | 774 | writew(0x4, host->regs + NFC_WRPROT); |
719 | 775 | ||
720 | this->ecc.size = 512; | 776 | this->ecc.size = 512; |
721 | this->ecc.bytes = 3; | 777 | this->ecc.layout = oob_smallpage; |
722 | this->ecc.layout = &nand_hw_eccoob_smallpage; | ||
723 | 778 | ||
724 | if (pdata->hw_ecc) { | 779 | if (pdata->hw_ecc) { |
725 | this->ecc.calculate = mxc_nand_calculate_ecc; | 780 | this->ecc.calculate = mxc_nand_calculate_ecc; |
@@ -747,7 +802,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
747 | } | 802 | } |
748 | 803 | ||
749 | if (mtd->writesize == 2048) | 804 | if (mtd->writesize == 2048) |
750 | this->ecc.layout = &nand_hw_eccoob_largepage; | 805 | this->ecc.layout = oob_largepage; |
751 | 806 | ||
752 | /* second phase scan */ | 807 | /* second phase scan */ |
753 | if (nand_scan_tail(mtd)) { | 808 | if (nand_scan_tail(mtd)) { |