diff options
Diffstat (limited to 'drivers/mtd/nand/mxc_nand.c')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 146 |
1 files changed, 93 insertions, 53 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a8f550fec35e..372e0e38f59b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
386 | /* This function polls the NANDFC to wait for the basic operation to | 386 | /* This function polls the NANDFC to wait for the basic operation to |
387 | * complete by checking the INT bit of config2 register. | 387 | * complete by checking the INT bit of config2 register. |
388 | */ | 388 | */ |
389 | static void wait_op_done(struct mxc_nand_host *host, int useirq) | 389 | static int wait_op_done(struct mxc_nand_host *host, int useirq) |
390 | { | 390 | { |
391 | int max_retries = 8000; | 391 | int ret = 0; |
392 | |||
393 | /* | ||
394 | * If operation is already complete, don't bother to setup an irq or a | ||
395 | * loop. | ||
396 | */ | ||
397 | if (host->devtype_data->check_int(host)) | ||
398 | return 0; | ||
392 | 399 | ||
393 | if (useirq) { | 400 | if (useirq) { |
394 | if (!host->devtype_data->check_int(host)) { | 401 | unsigned long timeout; |
395 | reinit_completion(&host->op_completion); | 402 | |
396 | irq_control(host, 1); | 403 | reinit_completion(&host->op_completion); |
397 | wait_for_completion(&host->op_completion); | 404 | |
405 | irq_control(host, 1); | ||
406 | |||
407 | timeout = wait_for_completion_timeout(&host->op_completion, HZ); | ||
408 | if (!timeout && !host->devtype_data->check_int(host)) { | ||
409 | dev_dbg(host->dev, "timeout waiting for irq\n"); | ||
410 | ret = -ETIMEDOUT; | ||
398 | } | 411 | } |
399 | } else { | 412 | } else { |
400 | while (max_retries-- > 0) { | 413 | int max_retries = 8000; |
401 | if (host->devtype_data->check_int(host)) | 414 | int done; |
402 | break; | ||
403 | 415 | ||
416 | do { | ||
404 | udelay(1); | 417 | udelay(1); |
418 | |||
419 | done = host->devtype_data->check_int(host); | ||
420 | if (done) | ||
421 | break; | ||
422 | |||
423 | } while (--max_retries); | ||
424 | |||
425 | if (!done) { | ||
426 | dev_dbg(host->dev, "timeout polling for completion\n"); | ||
427 | ret = -ETIMEDOUT; | ||
405 | } | 428 | } |
406 | if (max_retries < 0) | ||
407 | pr_debug("%s: INT not set\n", __func__); | ||
408 | } | 429 | } |
430 | |||
431 | WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq); | ||
432 | |||
433 | return ret; | ||
409 | } | 434 | } |
410 | 435 | ||
411 | static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) | 436 | static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) |
@@ -527,30 +552,17 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops) | |||
527 | 552 | ||
528 | static void send_read_id_v3(struct mxc_nand_host *host) | 553 | static void send_read_id_v3(struct mxc_nand_host *host) |
529 | { | 554 | { |
530 | struct nand_chip *this = &host->nand; | ||
531 | |||
532 | /* Read ID into main buffer */ | 555 | /* Read ID into main buffer */ |
533 | writel(NFC_ID, NFC_V3_LAUNCH); | 556 | writel(NFC_ID, NFC_V3_LAUNCH); |
534 | 557 | ||
535 | wait_op_done(host, true); | 558 | wait_op_done(host, true); |
536 | 559 | ||
537 | memcpy32_fromio(host->data_buf, host->main_area0, 16); | 560 | memcpy32_fromio(host->data_buf, host->main_area0, 16); |
538 | |||
539 | if (this->options & NAND_BUSWIDTH_16) { | ||
540 | /* compress the ID info */ | ||
541 | host->data_buf[1] = host->data_buf[2]; | ||
542 | host->data_buf[2] = host->data_buf[4]; | ||
543 | host->data_buf[3] = host->data_buf[6]; | ||
544 | host->data_buf[4] = host->data_buf[8]; | ||
545 | host->data_buf[5] = host->data_buf[10]; | ||
546 | } | ||
547 | } | 561 | } |
548 | 562 | ||
549 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 563 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
550 | static void send_read_id_v1_v2(struct mxc_nand_host *host) | 564 | static void send_read_id_v1_v2(struct mxc_nand_host *host) |
551 | { | 565 | { |
552 | struct nand_chip *this = &host->nand; | ||
553 | |||
554 | /* NANDFC buffer 0 is used for device ID output */ | 566 | /* NANDFC buffer 0 is used for device ID output */ |
555 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); | 567 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); |
556 | 568 | ||
@@ -560,15 +572,6 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) | |||
560 | wait_op_done(host, true); | 572 | wait_op_done(host, true); |
561 | 573 | ||
562 | memcpy32_fromio(host->data_buf, host->main_area0, 16); | 574 | memcpy32_fromio(host->data_buf, host->main_area0, 16); |
563 | |||
564 | if (this->options & NAND_BUSWIDTH_16) { | ||
565 | /* compress the ID info */ | ||
566 | host->data_buf[1] = host->data_buf[2]; | ||
567 | host->data_buf[2] = host->data_buf[4]; | ||
568 | host->data_buf[3] = host->data_buf[6]; | ||
569 | host->data_buf[4] = host->data_buf[8]; | ||
570 | host->data_buf[5] = host->data_buf[10]; | ||
571 | } | ||
572 | } | 575 | } |
573 | 576 | ||
574 | static uint16_t get_dev_status_v3(struct mxc_nand_host *host) | 577 | static uint16_t get_dev_status_v3(struct mxc_nand_host *host) |
@@ -694,9 +697,17 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
694 | if (host->status_request) | 697 | if (host->status_request) |
695 | return host->devtype_data->get_dev_status(host) & 0xFF; | 698 | return host->devtype_data->get_dev_status(host) & 0xFF; |
696 | 699 | ||
697 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | 700 | if (nand_chip->options & NAND_BUSWIDTH_16) { |
698 | host->buf_start++; | 701 | /* only take the lower byte of each word */ |
702 | ret = *(uint16_t *)(host->data_buf + host->buf_start); | ||
703 | |||
704 | host->buf_start += 2; | ||
705 | } else { | ||
706 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | ||
707 | host->buf_start++; | ||
708 | } | ||
699 | 709 | ||
710 | pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); | ||
700 | return ret; | 711 | return ret; |
701 | } | 712 | } |
702 | 713 | ||
@@ -825,6 +836,12 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) | |||
825 | } | 836 | } |
826 | } | 837 | } |
827 | 838 | ||
839 | /* | ||
840 | * MXC NANDFC can only perform full page+spare or spare-only read/write. When | ||
841 | * the upper layers perform a read/write buf operation, the saved column address | ||
842 | * is used to index into the full page. So usually this function is called with | ||
843 | * column == 0 (unless no column cycle is needed indicated by column == -1) | ||
844 | */ | ||
828 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | 845 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) |
829 | { | 846 | { |
830 | struct nand_chip *nand_chip = mtd->priv; | 847 | struct nand_chip *nand_chip = mtd->priv; |
@@ -832,16 +849,13 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | |||
832 | 849 | ||
833 | /* Write out column address, if necessary */ | 850 | /* Write out column address, if necessary */ |
834 | if (column != -1) { | 851 | if (column != -1) { |
835 | /* | 852 | host->devtype_data->send_addr(host, column & 0xff, |
836 | * MXC NANDFC can only perform full page+spare or | 853 | page_addr == -1); |
837 | * spare-only read/write. When the upper layers | ||
838 | * perform a read/write buf operation, the saved column | ||
839 | * address is used to index into the full page. | ||
840 | */ | ||
841 | host->devtype_data->send_addr(host, 0, page_addr == -1); | ||
842 | if (mtd->writesize > 512) | 854 | if (mtd->writesize > 512) |
843 | /* another col addr cycle for 2k page */ | 855 | /* another col addr cycle for 2k page */ |
844 | host->devtype_data->send_addr(host, 0, false); | 856 | host->devtype_data->send_addr(host, |
857 | (column >> 8) & 0xff, | ||
858 | false); | ||
845 | } | 859 | } |
846 | 860 | ||
847 | /* Write out page address, if necessary */ | 861 | /* Write out page address, if necessary */ |
@@ -903,7 +917,7 @@ static void preset_v1(struct mtd_info *mtd) | |||
903 | struct mxc_nand_host *host = nand_chip->priv; | 917 | struct mxc_nand_host *host = nand_chip->priv; |
904 | uint16_t config1 = 0; | 918 | uint16_t config1 = 0; |
905 | 919 | ||
906 | if (nand_chip->ecc.mode == NAND_ECC_HW) | 920 | if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize) |
907 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | 921 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; |
908 | 922 | ||
909 | if (!host->devtype_data->irqpending_quirk) | 923 | if (!host->devtype_data->irqpending_quirk) |
@@ -931,9 +945,6 @@ static void preset_v2(struct mtd_info *mtd) | |||
931 | struct mxc_nand_host *host = nand_chip->priv; | 945 | struct mxc_nand_host *host = nand_chip->priv; |
932 | uint16_t config1 = 0; | 946 | uint16_t config1 = 0; |
933 | 947 | ||
934 | if (nand_chip->ecc.mode == NAND_ECC_HW) | ||
935 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | ||
936 | |||
937 | config1 |= NFC_V2_CONFIG1_FP_INT; | 948 | config1 |= NFC_V2_CONFIG1_FP_INT; |
938 | 949 | ||
939 | if (!host->devtype_data->irqpending_quirk) | 950 | if (!host->devtype_data->irqpending_quirk) |
@@ -942,6 +953,9 @@ static void preset_v2(struct mtd_info *mtd) | |||
942 | if (mtd->writesize) { | 953 | if (mtd->writesize) { |
943 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; | 954 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; |
944 | 955 | ||
956 | if (nand_chip->ecc.mode == NAND_ECC_HW) | ||
957 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | ||
958 | |||
945 | host->eccsize = get_eccsize(mtd); | 959 | host->eccsize = get_eccsize(mtd); |
946 | if (host->eccsize == 4) | 960 | if (host->eccsize == 4) |
947 | config1 |= NFC_V2_CONFIG1_ECC_MODE_4; | 961 | config1 |= NFC_V2_CONFIG1_ECC_MODE_4; |
@@ -999,9 +1013,6 @@ static void preset_v3(struct mtd_info *mtd) | |||
999 | NFC_V3_CONFIG2_INT_MSK | | 1013 | NFC_V3_CONFIG2_INT_MSK | |
1000 | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; | 1014 | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; |
1001 | 1015 | ||
1002 | if (chip->ecc.mode == NAND_ECC_HW) | ||
1003 | config2 |= NFC_V3_CONFIG2_ECC_EN; | ||
1004 | |||
1005 | addr_phases = fls(chip->pagemask) >> 3; | 1016 | addr_phases = fls(chip->pagemask) >> 3; |
1006 | 1017 | ||
1007 | if (mtd->writesize == 2048) { | 1018 | if (mtd->writesize == 2048) { |
@@ -1016,6 +1027,9 @@ static void preset_v3(struct mtd_info *mtd) | |||
1016 | } | 1027 | } |
1017 | 1028 | ||
1018 | if (mtd->writesize) { | 1029 | if (mtd->writesize) { |
1030 | if (chip->ecc.mode == NAND_ECC_HW) | ||
1031 | config2 |= NFC_V3_CONFIG2_ECC_EN; | ||
1032 | |||
1019 | config2 |= NFC_V3_CONFIG2_PPB( | 1033 | config2 |= NFC_V3_CONFIG2_PPB( |
1020 | ffs(mtd->erasesize / mtd->writesize) - 6, | 1034 | ffs(mtd->erasesize / mtd->writesize) - 6, |
1021 | host->devtype_data->ppb_shift); | 1035 | host->devtype_data->ppb_shift); |
@@ -1066,6 +1080,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
1066 | host->status_request = true; | 1080 | host->status_request = true; |
1067 | 1081 | ||
1068 | host->devtype_data->send_cmd(host, command, true); | 1082 | host->devtype_data->send_cmd(host, command, true); |
1083 | WARN_ONCE(column != -1 || page_addr != -1, | ||
1084 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
1085 | command, column, page_addr); | ||
1069 | mxc_do_addr_cycle(mtd, column, page_addr); | 1086 | mxc_do_addr_cycle(mtd, column, page_addr); |
1070 | break; | 1087 | break; |
1071 | 1088 | ||
@@ -1079,7 +1096,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
1079 | command = NAND_CMD_READ0; /* only READ0 is valid */ | 1096 | command = NAND_CMD_READ0; /* only READ0 is valid */ |
1080 | 1097 | ||
1081 | host->devtype_data->send_cmd(host, command, false); | 1098 | host->devtype_data->send_cmd(host, command, false); |
1082 | mxc_do_addr_cycle(mtd, column, page_addr); | 1099 | WARN_ONCE(column < 0, |
1100 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
1101 | command, column, page_addr); | ||
1102 | mxc_do_addr_cycle(mtd, 0, page_addr); | ||
1083 | 1103 | ||
1084 | if (mtd->writesize > 512) | 1104 | if (mtd->writesize > 512) |
1085 | host->devtype_data->send_cmd(host, | 1105 | host->devtype_data->send_cmd(host, |
@@ -1100,7 +1120,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
1100 | host->buf_start = column; | 1120 | host->buf_start = column; |
1101 | 1121 | ||
1102 | host->devtype_data->send_cmd(host, command, false); | 1122 | host->devtype_data->send_cmd(host, command, false); |
1103 | mxc_do_addr_cycle(mtd, column, page_addr); | 1123 | WARN_ONCE(column < -1, |
1124 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
1125 | command, column, page_addr); | ||
1126 | mxc_do_addr_cycle(mtd, 0, page_addr); | ||
1104 | break; | 1127 | break; |
1105 | 1128 | ||
1106 | case NAND_CMD_PAGEPROG: | 1129 | case NAND_CMD_PAGEPROG: |
@@ -1108,6 +1131,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
1108 | copy_spare(mtd, false); | 1131 | copy_spare(mtd, false); |
1109 | host->devtype_data->send_page(mtd, NFC_INPUT); | 1132 | host->devtype_data->send_page(mtd, NFC_INPUT); |
1110 | host->devtype_data->send_cmd(host, command, true); | 1133 | host->devtype_data->send_cmd(host, command, true); |
1134 | WARN_ONCE(column != -1 || page_addr != -1, | ||
1135 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
1136 | command, column, page_addr); | ||
1111 | mxc_do_addr_cycle(mtd, column, page_addr); | 1137 | mxc_do_addr_cycle(mtd, column, page_addr); |
1112 | break; | 1138 | break; |
1113 | 1139 | ||
@@ -1115,15 +1141,29 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
1115 | host->devtype_data->send_cmd(host, command, true); | 1141 | host->devtype_data->send_cmd(host, command, true); |
1116 | mxc_do_addr_cycle(mtd, column, page_addr); | 1142 | mxc_do_addr_cycle(mtd, column, page_addr); |
1117 | host->devtype_data->send_read_id(host); | 1143 | host->devtype_data->send_read_id(host); |
1118 | host->buf_start = column; | 1144 | host->buf_start = 0; |
1119 | break; | 1145 | break; |
1120 | 1146 | ||
1121 | case NAND_CMD_ERASE1: | 1147 | case NAND_CMD_ERASE1: |
1122 | case NAND_CMD_ERASE2: | 1148 | case NAND_CMD_ERASE2: |
1123 | host->devtype_data->send_cmd(host, command, false); | 1149 | host->devtype_data->send_cmd(host, command, false); |
1150 | WARN_ONCE(column != -1, | ||
1151 | "Unexpected column value (cmd=%u, col=%d)\n", | ||
1152 | command, column); | ||
1124 | mxc_do_addr_cycle(mtd, column, page_addr); | 1153 | mxc_do_addr_cycle(mtd, column, page_addr); |
1125 | 1154 | ||
1126 | break; | 1155 | break; |
1156 | case NAND_CMD_PARAM: | ||
1157 | host->devtype_data->send_cmd(host, command, false); | ||
1158 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
1159 | host->devtype_data->send_page(mtd, NFC_OUTPUT); | ||
1160 | memcpy32_fromio(host->data_buf, host->main_area0, 512); | ||
1161 | host->buf_start = 0; | ||
1162 | break; | ||
1163 | default: | ||
1164 | WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", | ||
1165 | command); | ||
1166 | break; | ||
1127 | } | 1167 | } |
1128 | } | 1168 | } |
1129 | 1169 | ||