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 | |
| 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>
| -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)) { |
