diff options
| -rw-r--r-- | drivers/mtd/nand/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 222 |
2 files changed, 222 insertions, 2 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1d69920a2c93..79afdc1b3377 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
| @@ -481,7 +481,7 @@ config MTD_NAND_MPC5121_NFC | |||
| 481 | 481 | ||
| 482 | config MTD_NAND_MXC | 482 | config MTD_NAND_MXC |
| 483 | tristate "MXC NAND support" | 483 | tristate "MXC NAND support" |
| 484 | depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 | 484 | depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX51 |
| 485 | help | 485 | help |
| 486 | This enables the driver for the NAND flash controller on the | 486 | This enables the driver for the NAND flash controller on the |
| 487 | MXC processors. | 487 | MXC processors. |
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 1433a8389109..3657a6eb026f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
| @@ -39,6 +39,8 @@ | |||
| 39 | 39 | ||
| 40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | 40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) |
| 41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) | 41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) |
| 42 | #define nfc_is_v3_2() cpu_is_mx51() | ||
| 43 | #define nfc_is_v3() nfc_is_v3_2() | ||
| 42 | 44 | ||
| 43 | /* Addresses for NFC registers */ | 45 | /* Addresses for NFC registers */ |
| 44 | #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) | 46 | #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) |
| @@ -80,6 +82,54 @@ | |||
| 80 | #define NFC_ID (1 << 4) | 82 | #define NFC_ID (1 << 4) |
| 81 | #define NFC_STATUS (1 << 5) | 83 | #define NFC_STATUS (1 << 5) |
| 82 | 84 | ||
| 85 | #define NFC_V3_FLASH_CMD (host->regs_axi + 0x00) | ||
| 86 | #define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04) | ||
| 87 | |||
| 88 | #define NFC_V3_CONFIG1 (host->regs_axi + 0x34) | ||
| 89 | #define NFC_V3_CONFIG1_SP_EN (1 << 0) | ||
| 90 | #define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4) | ||
| 91 | |||
| 92 | #define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38) | ||
| 93 | |||
| 94 | #define NFC_V3_LAUNCH (host->regs_axi + 0x40) | ||
| 95 | |||
| 96 | #define NFC_V3_WRPROT (host->regs_ip + 0x0) | ||
| 97 | #define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0) | ||
| 98 | #define NFC_V3_WRPROT_LOCK (1 << 1) | ||
| 99 | #define NFC_V3_WRPROT_UNLOCK (1 << 2) | ||
| 100 | #define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6) | ||
| 101 | |||
| 102 | #define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04) | ||
| 103 | |||
| 104 | #define NFC_V3_CONFIG2 (host->regs_ip + 0x24) | ||
| 105 | #define NFC_V3_CONFIG2_PS_512 (0 << 0) | ||
| 106 | #define NFC_V3_CONFIG2_PS_2048 (1 << 0) | ||
| 107 | #define NFC_V3_CONFIG2_PS_4096 (2 << 0) | ||
| 108 | #define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2) | ||
| 109 | #define NFC_V3_CONFIG2_ECC_EN (1 << 3) | ||
| 110 | #define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) | ||
| 111 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5) | ||
| 112 | #define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) | ||
| 113 | #define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) | ||
| 114 | #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12) | ||
| 115 | #define NFC_V3_CONFIG2_INT_MSK (1 << 15) | ||
| 116 | #define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) | ||
| 117 | #define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16) | ||
| 118 | |||
| 119 | #define NFC_V3_CONFIG3 (host->regs_ip + 0x28) | ||
| 120 | #define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0) | ||
| 121 | #define NFC_V3_CONFIG3_FW8 (1 << 3) | ||
| 122 | #define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8) | ||
| 123 | #define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12) | ||
| 124 | #define NFC_V3_CONFIG3_RBB_MODE (1 << 15) | ||
| 125 | #define NFC_V3_CONFIG3_NO_SDMA (1 << 20) | ||
| 126 | |||
| 127 | #define NFC_V3_IPC (host->regs_ip + 0x2C) | ||
| 128 | #define NFC_V3_IPC_CREQ (1 << 0) | ||
| 129 | #define NFC_V3_IPC_INT (1 << 31) | ||
| 130 | |||
| 131 | #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) | ||
| 132 | |||
| 83 | struct mxc_nand_host { | 133 | struct mxc_nand_host { |
| 84 | struct mtd_info mtd; | 134 | struct mtd_info mtd; |
| 85 | struct nand_chip nand; | 135 | struct nand_chip nand; |
| @@ -91,6 +141,8 @@ struct mxc_nand_host { | |||
| 91 | 141 | ||
| 92 | void __iomem *base; | 142 | void __iomem *base; |
| 93 | void __iomem *regs; | 143 | void __iomem *regs; |
| 144 | void __iomem *regs_axi; | ||
| 145 | void __iomem *regs_ip; | ||
| 94 | int status_request; | 146 | int status_request; |
| 95 | struct clk *clk; | 147 | struct clk *clk; |
| 96 | int clk_act; | 148 | int clk_act; |
| @@ -169,6 +221,20 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
| 169 | return IRQ_HANDLED; | 221 | return IRQ_HANDLED; |
| 170 | } | 222 | } |
| 171 | 223 | ||
| 224 | static int check_int_v3(struct mxc_nand_host *host) | ||
| 225 | { | ||
| 226 | uint32_t tmp; | ||
| 227 | |||
| 228 | tmp = readl(NFC_V3_IPC); | ||
| 229 | if (!(tmp & NFC_V3_IPC_INT)) | ||
| 230 | return 0; | ||
| 231 | |||
| 232 | tmp &= ~NFC_V3_IPC_INT; | ||
| 233 | writel(tmp, NFC_V3_IPC); | ||
| 234 | |||
| 235 | return 1; | ||
| 236 | } | ||
| 237 | |||
| 172 | static int check_int_v1_v2(struct mxc_nand_host *host) | 238 | static int check_int_v1_v2(struct mxc_nand_host *host) |
| 173 | { | 239 | { |
| 174 | uint32_t tmp; | 240 | uint32_t tmp; |
| @@ -209,6 +275,18 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) | |||
| 209 | } | 275 | } |
| 210 | } | 276 | } |
| 211 | 277 | ||
| 278 | static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) | ||
| 279 | { | ||
| 280 | /* fill command */ | ||
| 281 | writel(cmd, NFC_V3_FLASH_CMD); | ||
| 282 | |||
| 283 | /* send out command */ | ||
| 284 | writel(NFC_CMD, NFC_V3_LAUNCH); | ||
| 285 | |||
| 286 | /* Wait for operation to complete */ | ||
| 287 | wait_op_done(host, useirq); | ||
| 288 | } | ||
| 289 | |||
| 212 | /* This function issues the specified command to the NAND device and | 290 | /* This function issues the specified command to the NAND device and |
| 213 | * waits for completion. */ | 291 | * waits for completion. */ |
| 214 | static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) | 292 | static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) |
| @@ -237,6 +315,17 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
| 237 | } | 315 | } |
| 238 | } | 316 | } |
| 239 | 317 | ||
| 318 | static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast) | ||
| 319 | { | ||
| 320 | /* fill address */ | ||
| 321 | writel(addr, NFC_V3_FLASH_ADDR0); | ||
| 322 | |||
| 323 | /* send out address */ | ||
| 324 | writel(NFC_ADDR, NFC_V3_LAUNCH); | ||
| 325 | |||
| 326 | wait_op_done(host, 0); | ||
| 327 | } | ||
| 328 | |||
| 240 | /* This function sends an address (or partial address) to the | 329 | /* This function sends an address (or partial address) to the |
| 241 | * NAND device. The address is used to select the source/destination for | 330 | * NAND device. The address is used to select the source/destination for |
| 242 | * a NAND command. */ | 331 | * a NAND command. */ |
| @@ -251,6 +340,22 @@ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islas | |||
| 251 | wait_op_done(host, islast); | 340 | wait_op_done(host, islast); |
| 252 | } | 341 | } |
| 253 | 342 | ||
| 343 | static void send_page_v3(struct mtd_info *mtd, unsigned int ops) | ||
| 344 | { | ||
| 345 | struct nand_chip *nand_chip = mtd->priv; | ||
| 346 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 347 | uint32_t tmp; | ||
| 348 | |||
| 349 | tmp = readl(NFC_V3_CONFIG1); | ||
| 350 | tmp &= ~(7 << 4); | ||
| 351 | writel(tmp, NFC_V3_CONFIG1); | ||
| 352 | |||
| 353 | /* transfer data from NFC ram to nand */ | ||
| 354 | writel(ops, NFC_V3_LAUNCH); | ||
| 355 | |||
| 356 | wait_op_done(host, false); | ||
| 357 | } | ||
| 358 | |||
| 254 | static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) | 359 | static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) |
| 255 | { | 360 | { |
| 256 | struct nand_chip *nand_chip = mtd->priv; | 361 | struct nand_chip *nand_chip = mtd->priv; |
| @@ -274,6 +379,16 @@ static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) | |||
| 274 | } | 379 | } |
| 275 | } | 380 | } |
| 276 | 381 | ||
| 382 | static void send_read_id_v3(struct mxc_nand_host *host) | ||
| 383 | { | ||
| 384 | /* Read ID into main buffer */ | ||
| 385 | writel(NFC_ID, NFC_V3_LAUNCH); | ||
| 386 | |||
| 387 | wait_op_done(host, true); | ||
| 388 | |||
| 389 | memcpy(host->data_buf, host->main_area0, 16); | ||
| 390 | } | ||
| 391 | |||
| 277 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 392 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
| 278 | static void send_read_id_v1_v2(struct mxc_nand_host *host) | 393 | static void send_read_id_v1_v2(struct mxc_nand_host *host) |
| 279 | { | 394 | { |
| @@ -299,6 +414,14 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) | |||
| 299 | memcpy(host->data_buf, host->main_area0, 16); | 414 | memcpy(host->data_buf, host->main_area0, 16); |
| 300 | } | 415 | } |
| 301 | 416 | ||
| 417 | static uint16_t get_dev_status_v3(struct mxc_nand_host *host) | ||
| 418 | { | ||
| 419 | writew(NFC_STATUS, NFC_V3_LAUNCH); | ||
| 420 | wait_op_done(host, true); | ||
| 421 | |||
| 422 | return readl(NFC_V3_CONFIG1) >> 16; | ||
| 423 | } | ||
| 424 | |||
| 302 | /* This function requests the NANDFC to perform a read of the | 425 | /* This function requests the NANDFC to perform a read of the |
| 303 | * NAND device status and returns the current status. */ | 426 | * NAND device status and returns the current status. */ |
| 304 | static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host) | 427 | static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host) |
| @@ -381,7 +504,10 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, | |||
| 381 | 504 | ||
| 382 | no_subpages = mtd->writesize >> 9; | 505 | no_subpages = mtd->writesize >> 9; |
| 383 | 506 | ||
| 384 | ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); | 507 | if (nfc_is_v21()) |
| 508 | ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); | ||
| 509 | else | ||
| 510 | ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT); | ||
| 385 | 511 | ||
| 386 | do { | 512 | do { |
| 387 | err = ecc_stat & ecc_bit_mask; | 513 | err = ecc_stat & ecc_bit_mask; |
| @@ -643,6 +769,72 @@ static void preset_v1_v2(struct mtd_info *mtd) | |||
| 643 | writew(0x4, NFC_V1_V2_WRPROT); | 769 | writew(0x4, NFC_V1_V2_WRPROT); |
| 644 | } | 770 | } |
| 645 | 771 | ||
| 772 | static void preset_v3(struct mtd_info *mtd) | ||
| 773 | { | ||
| 774 | struct nand_chip *chip = mtd->priv; | ||
| 775 | struct mxc_nand_host *host = chip->priv; | ||
| 776 | uint32_t config2, config3; | ||
| 777 | int i, addr_phases; | ||
| 778 | |||
| 779 | writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1); | ||
| 780 | writel(NFC_V3_IPC_CREQ, NFC_V3_IPC); | ||
| 781 | |||
| 782 | /* Unlock the internal RAM Buffer */ | ||
| 783 | writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, | ||
| 784 | NFC_V3_WRPROT); | ||
| 785 | |||
| 786 | /* Blocks to be unlocked */ | ||
| 787 | for (i = 0; i < NAND_MAX_CHIPS; i++) | ||
| 788 | writel(0x0 | (0xffff << 16), | ||
| 789 | NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2)); | ||
| 790 | |||
| 791 | writel(0, NFC_V3_IPC); | ||
| 792 | |||
| 793 | config2 = NFC_V3_CONFIG2_ONE_CYCLE | | ||
| 794 | NFC_V3_CONFIG2_2CMD_PHASES | | ||
| 795 | NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) | | ||
| 796 | NFC_V3_CONFIG2_ST_CMD(0x70) | | ||
| 797 | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; | ||
| 798 | |||
| 799 | if (chip->ecc.mode == NAND_ECC_HW) | ||
| 800 | config2 |= NFC_V3_CONFIG2_ECC_EN; | ||
| 801 | |||
| 802 | addr_phases = fls(chip->pagemask) >> 3; | ||
| 803 | |||
| 804 | if (mtd->writesize == 2048) { | ||
| 805 | config2 |= NFC_V3_CONFIG2_PS_2048; | ||
| 806 | config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases); | ||
| 807 | } else if (mtd->writesize == 4096) { | ||
| 808 | config2 |= NFC_V3_CONFIG2_PS_4096; | ||
| 809 | config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases); | ||
| 810 | } else { | ||
| 811 | config2 |= NFC_V3_CONFIG2_PS_512; | ||
| 812 | config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1); | ||
| 813 | } | ||
| 814 | |||
| 815 | if (mtd->writesize) { | ||
| 816 | config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6); | ||
| 817 | host->eccsize = get_eccsize(mtd); | ||
| 818 | if (host->eccsize == 8) | ||
| 819 | config2 |= NFC_V3_CONFIG2_ECC_MODE_8; | ||
| 820 | } | ||
| 821 | |||
| 822 | writel(config2, NFC_V3_CONFIG2); | ||
| 823 | |||
| 824 | config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) | | ||
| 825 | NFC_V3_CONFIG3_NO_SDMA | | ||
| 826 | NFC_V3_CONFIG3_RBB_MODE | | ||
| 827 | NFC_V3_CONFIG3_SBB(6) | /* Reset default */ | ||
| 828 | NFC_V3_CONFIG3_ADD_OP(0); | ||
| 829 | |||
| 830 | if (!(chip->options & NAND_BUSWIDTH_16)) | ||
| 831 | config3 |= NFC_V3_CONFIG3_FW8; | ||
| 832 | |||
| 833 | writel(config3, NFC_V3_CONFIG3); | ||
| 834 | |||
| 835 | writel(0, NFC_V3_DELAY_LINE); | ||
| 836 | } | ||
| 837 | |||
| 646 | /* Used by the upper layer to write command to NAND Flash for | 838 | /* Used by the upper layer to write command to NAND Flash for |
| 647 | * different operations to be carried out on NAND Flash */ | 839 | * different operations to be carried out on NAND Flash */ |
| 648 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | 840 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, |
| @@ -843,6 +1035,30 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 843 | oob_smallpage = &nandv1_hw_eccoob_smallpage; | 1035 | oob_smallpage = &nandv1_hw_eccoob_smallpage; |
| 844 | oob_largepage = &nandv1_hw_eccoob_largepage; | 1036 | oob_largepage = &nandv1_hw_eccoob_largepage; |
| 845 | this->ecc.bytes = 3; | 1037 | this->ecc.bytes = 3; |
| 1038 | host->eccsize = 1; | ||
| 1039 | } else if (nfc_is_v3_2()) { | ||
| 1040 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
| 1041 | if (!res) { | ||
| 1042 | err = -ENODEV; | ||
| 1043 | goto eirq; | ||
| 1044 | } | ||
| 1045 | host->regs_ip = ioremap(res->start, resource_size(res)); | ||
| 1046 | if (!host->regs_ip) { | ||
| 1047 | err = -ENOMEM; | ||
| 1048 | goto eirq; | ||
| 1049 | } | ||
| 1050 | host->regs_axi = host->base + 0x1e00; | ||
| 1051 | host->spare0 = host->base + 0x1000; | ||
| 1052 | host->spare_len = 64; | ||
| 1053 | host->preset = preset_v3; | ||
| 1054 | host->send_cmd = send_cmd_v3; | ||
| 1055 | host->send_addr = send_addr_v3; | ||
| 1056 | host->send_page = send_page_v3; | ||
| 1057 | host->send_read_id = send_read_id_v3; | ||
| 1058 | host->check_int = check_int_v3; | ||
| 1059 | host->get_dev_status = get_dev_status_v3; | ||
| 1060 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
| 1061 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
| 846 | } else | 1062 | } else |
| 847 | BUG(); | 1063 | BUG(); |
| 848 | 1064 | ||
| @@ -918,6 +1134,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 918 | escan: | 1134 | escan: |
| 919 | free_irq(host->irq, host); | 1135 | free_irq(host->irq, host); |
| 920 | eirq: | 1136 | eirq: |
| 1137 | if (host->regs_ip) | ||
| 1138 | iounmap(host->regs_ip); | ||
| 921 | iounmap(host->base); | 1139 | iounmap(host->base); |
| 922 | eres: | 1140 | eres: |
| 923 | clk_put(host->clk); | 1141 | clk_put(host->clk); |
| @@ -937,6 +1155,8 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
| 937 | 1155 | ||
| 938 | nand_release(&host->mtd); | 1156 | nand_release(&host->mtd); |
| 939 | free_irq(host->irq, host); | 1157 | free_irq(host->irq, host); |
| 1158 | if (host->regs_ip) | ||
| 1159 | iounmap(host->regs_ip); | ||
| 940 | iounmap(host->base); | 1160 | iounmap(host->base); |
| 941 | kfree(host); | 1161 | kfree(host); |
| 942 | 1162 | ||
