diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 72 |
1 files changed, 44 insertions, 28 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index b6aa7e3a967a..5130a8531024 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -115,6 +115,13 @@ struct mxc_nand_host { | |||
115 | uint8_t *data_buf; | 115 | uint8_t *data_buf; |
116 | unsigned int buf_start; | 116 | unsigned int buf_start; |
117 | int spare_len; | 117 | int spare_len; |
118 | |||
119 | void (*preset)(struct mtd_info *); | ||
120 | void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); | ||
121 | void (*send_addr)(struct mxc_nand_host *, uint16_t, int); | ||
122 | void (*send_page)(struct mtd_info *, unsigned int); | ||
123 | void (*send_read_id)(struct mxc_nand_host *); | ||
124 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | ||
118 | }; | 125 | }; |
119 | 126 | ||
120 | /* OOB placement block for use with hardware ecc generation */ | 127 | /* OOB placement block for use with hardware ecc generation */ |
@@ -212,7 +219,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) | |||
212 | 219 | ||
213 | /* This function issues the specified command to the NAND device and | 220 | /* This function issues the specified command to the NAND device and |
214 | * waits for completion. */ | 221 | * waits for completion. */ |
215 | static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | 222 | static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) |
216 | { | 223 | { |
217 | DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); | 224 | DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); |
218 | 225 | ||
@@ -241,7 +248,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
241 | /* This function sends an address (or partial address) to the | 248 | /* This function sends an address (or partial address) to the |
242 | * NAND device. The address is used to select the source/destination for | 249 | * NAND device. The address is used to select the source/destination for |
243 | * a NAND command. */ | 250 | * a NAND command. */ |
244 | static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) | 251 | static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast) |
245 | { | 252 | { |
246 | DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); | 253 | DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); |
247 | 254 | ||
@@ -252,7 +259,7 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) | |||
252 | wait_op_done(host, islast); | 259 | wait_op_done(host, islast); |
253 | } | 260 | } |
254 | 261 | ||
255 | static void send_page(struct mtd_info *mtd, unsigned int ops) | 262 | static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) |
256 | { | 263 | { |
257 | struct nand_chip *nand_chip = mtd->priv; | 264 | struct nand_chip *nand_chip = mtd->priv; |
258 | struct mxc_nand_host *host = nand_chip->priv; | 265 | struct mxc_nand_host *host = nand_chip->priv; |
@@ -276,7 +283,7 @@ static void send_page(struct mtd_info *mtd, unsigned int ops) | |||
276 | } | 283 | } |
277 | 284 | ||
278 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 285 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
279 | static void send_read_id(struct mxc_nand_host *host) | 286 | static void send_read_id_v1_v2(struct mxc_nand_host *host) |
280 | { | 287 | { |
281 | struct nand_chip *this = &host->nand; | 288 | struct nand_chip *this = &host->nand; |
282 | 289 | ||
@@ -302,7 +309,7 @@ static void send_read_id(struct mxc_nand_host *host) | |||
302 | 309 | ||
303 | /* This function requests the NANDFC to perform a read of the | 310 | /* This function requests the NANDFC to perform a read of the |
304 | * NAND device status and returns the current status. */ | 311 | * NAND device status and returns the current status. */ |
305 | static uint16_t get_dev_status(struct mxc_nand_host *host) | 312 | static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host) |
306 | { | 313 | { |
307 | void __iomem *main_buf = host->main_area0; | 314 | void __iomem *main_buf = host->main_area0; |
308 | uint32_t store; | 315 | uint32_t store; |
@@ -381,7 +388,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
381 | 388 | ||
382 | /* Check for status request */ | 389 | /* Check for status request */ |
383 | if (host->status_request) | 390 | if (host->status_request) |
384 | return get_dev_status(host) & 0xFF; | 391 | return host->get_dev_status(host) & 0xFF; |
385 | 392 | ||
386 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | 393 | ret = *(uint8_t *)(host->data_buf + host->buf_start); |
387 | host->buf_start++; | 394 | host->buf_start++; |
@@ -517,39 +524,39 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | |||
517 | * we will used the saved column address to index into | 524 | * we will used the saved column address to index into |
518 | * the full page. | 525 | * the full page. |
519 | */ | 526 | */ |
520 | send_addr(host, 0, page_addr == -1); | 527 | host->send_addr(host, 0, page_addr == -1); |
521 | if (mtd->writesize > 512) | 528 | if (mtd->writesize > 512) |
522 | /* another col addr cycle for 2k page */ | 529 | /* another col addr cycle for 2k page */ |
523 | send_addr(host, 0, false); | 530 | host->send_addr(host, 0, false); |
524 | } | 531 | } |
525 | 532 | ||
526 | /* Write out page address, if necessary */ | 533 | /* Write out page address, if necessary */ |
527 | if (page_addr != -1) { | 534 | if (page_addr != -1) { |
528 | /* paddr_0 - p_addr_7 */ | 535 | /* paddr_0 - p_addr_7 */ |
529 | send_addr(host, (page_addr & 0xff), false); | 536 | host->send_addr(host, (page_addr & 0xff), false); |
530 | 537 | ||
531 | if (mtd->writesize > 512) { | 538 | if (mtd->writesize > 512) { |
532 | if (mtd->size >= 0x10000000) { | 539 | if (mtd->size >= 0x10000000) { |
533 | /* paddr_8 - paddr_15 */ | 540 | /* paddr_8 - paddr_15 */ |
534 | send_addr(host, (page_addr >> 8) & 0xff, false); | 541 | host->send_addr(host, (page_addr >> 8) & 0xff, false); |
535 | send_addr(host, (page_addr >> 16) & 0xff, true); | 542 | host->send_addr(host, (page_addr >> 16) & 0xff, true); |
536 | } else | 543 | } else |
537 | /* paddr_8 - paddr_15 */ | 544 | /* paddr_8 - paddr_15 */ |
538 | send_addr(host, (page_addr >> 8) & 0xff, true); | 545 | host->send_addr(host, (page_addr >> 8) & 0xff, true); |
539 | } else { | 546 | } else { |
540 | /* One more address cycle for higher density devices */ | 547 | /* One more address cycle for higher density devices */ |
541 | if (mtd->size >= 0x4000000) { | 548 | if (mtd->size >= 0x4000000) { |
542 | /* paddr_8 - paddr_15 */ | 549 | /* paddr_8 - paddr_15 */ |
543 | send_addr(host, (page_addr >> 8) & 0xff, false); | 550 | host->send_addr(host, (page_addr >> 8) & 0xff, false); |
544 | send_addr(host, (page_addr >> 16) & 0xff, true); | 551 | host->send_addr(host, (page_addr >> 16) & 0xff, true); |
545 | } else | 552 | } else |
546 | /* paddr_8 - paddr_15 */ | 553 | /* paddr_8 - paddr_15 */ |
547 | send_addr(host, (page_addr >> 8) & 0xff, true); | 554 | host->send_addr(host, (page_addr >> 8) & 0xff, true); |
548 | } | 555 | } |
549 | } | 556 | } |
550 | } | 557 | } |
551 | 558 | ||
552 | static void preset(struct mtd_info *mtd) | 559 | static void preset_v1_v2(struct mtd_info *mtd) |
553 | { | 560 | { |
554 | struct nand_chip *nand_chip = mtd->priv; | 561 | struct nand_chip *nand_chip = mtd->priv; |
555 | struct mxc_nand_host *host = nand_chip->priv; | 562 | struct mxc_nand_host *host = nand_chip->priv; |
@@ -602,15 +609,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
602 | /* Command pre-processing step */ | 609 | /* Command pre-processing step */ |
603 | switch (command) { | 610 | switch (command) { |
604 | case NAND_CMD_RESET: | 611 | case NAND_CMD_RESET: |
605 | preset(mtd); | 612 | host->preset(mtd); |
606 | send_cmd(host, command, false); | 613 | host->send_cmd(host, command, false); |
607 | break; | 614 | break; |
608 | 615 | ||
609 | case NAND_CMD_STATUS: | 616 | case NAND_CMD_STATUS: |
610 | host->buf_start = 0; | 617 | host->buf_start = 0; |
611 | host->status_request = true; | 618 | host->status_request = true; |
612 | 619 | ||
613 | send_cmd(host, command, true); | 620 | host->send_cmd(host, command, true); |
614 | mxc_do_addr_cycle(mtd, column, page_addr); | 621 | mxc_do_addr_cycle(mtd, column, page_addr); |
615 | break; | 622 | break; |
616 | 623 | ||
@@ -623,13 +630,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
623 | 630 | ||
624 | command = NAND_CMD_READ0; /* only READ0 is valid */ | 631 | command = NAND_CMD_READ0; /* only READ0 is valid */ |
625 | 632 | ||
626 | send_cmd(host, command, false); | 633 | host->send_cmd(host, command, false); |
627 | mxc_do_addr_cycle(mtd, column, page_addr); | 634 | mxc_do_addr_cycle(mtd, column, page_addr); |
628 | 635 | ||
629 | if (mtd->writesize > 512) | 636 | if (mtd->writesize > 512) |
630 | send_cmd(host, NAND_CMD_READSTART, true); | 637 | host->send_cmd(host, NAND_CMD_READSTART, true); |
631 | 638 | ||
632 | send_page(mtd, NFC_OUTPUT); | 639 | host->send_page(mtd, NFC_OUTPUT); |
633 | 640 | ||
634 | memcpy(host->data_buf, host->main_area0, mtd->writesize); | 641 | memcpy(host->data_buf, host->main_area0, mtd->writesize); |
635 | copy_spare(mtd, true); | 642 | copy_spare(mtd, true); |
@@ -642,28 +649,28 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
642 | 649 | ||
643 | host->buf_start = column; | 650 | host->buf_start = column; |
644 | 651 | ||
645 | send_cmd(host, command, false); | 652 | host->send_cmd(host, command, false); |
646 | mxc_do_addr_cycle(mtd, column, page_addr); | 653 | mxc_do_addr_cycle(mtd, column, page_addr); |
647 | break; | 654 | break; |
648 | 655 | ||
649 | case NAND_CMD_PAGEPROG: | 656 | case NAND_CMD_PAGEPROG: |
650 | memcpy(host->main_area0, host->data_buf, mtd->writesize); | 657 | memcpy(host->main_area0, host->data_buf, mtd->writesize); |
651 | copy_spare(mtd, false); | 658 | copy_spare(mtd, false); |
652 | send_page(mtd, NFC_INPUT); | 659 | host->send_page(mtd, NFC_INPUT); |
653 | send_cmd(host, command, true); | 660 | host->send_cmd(host, command, true); |
654 | mxc_do_addr_cycle(mtd, column, page_addr); | 661 | mxc_do_addr_cycle(mtd, column, page_addr); |
655 | break; | 662 | break; |
656 | 663 | ||
657 | case NAND_CMD_READID: | 664 | case NAND_CMD_READID: |
658 | send_cmd(host, command, true); | 665 | host->send_cmd(host, command, true); |
659 | mxc_do_addr_cycle(mtd, column, page_addr); | 666 | mxc_do_addr_cycle(mtd, column, page_addr); |
660 | send_read_id(host); | 667 | host->send_read_id(host); |
661 | host->buf_start = column; | 668 | host->buf_start = column; |
662 | break; | 669 | break; |
663 | 670 | ||
664 | case NAND_CMD_ERASE1: | 671 | case NAND_CMD_ERASE1: |
665 | case NAND_CMD_ERASE2: | 672 | case NAND_CMD_ERASE2: |
666 | send_cmd(host, command, false); | 673 | host->send_cmd(host, command, false); |
667 | mxc_do_addr_cycle(mtd, column, page_addr); | 674 | mxc_do_addr_cycle(mtd, column, page_addr); |
668 | 675 | ||
669 | break; | 676 | break; |
@@ -760,6 +767,15 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
760 | 767 | ||
761 | host->main_area0 = host->base; | 768 | host->main_area0 = host->base; |
762 | 769 | ||
770 | if (nfc_is_v1() || nfc_is_v21()) { | ||
771 | host->preset = preset_v1_v2; | ||
772 | host->send_cmd = send_cmd_v1_v2; | ||
773 | host->send_addr = send_addr_v1_v2; | ||
774 | host->send_page = send_page_v1_v2; | ||
775 | host->send_read_id = send_read_id_v1_v2; | ||
776 | host->get_dev_status = get_dev_status_v1_v2; | ||
777 | } | ||
778 | |||
763 | if (nfc_is_v21()) { | 779 | if (nfc_is_v21()) { |
764 | host->regs = host->base + 0x1e00; | 780 | host->regs = host->base + 0x1e00; |
765 | host->spare0 = host->base + 0x1000; | 781 | host->spare0 = host->base + 0x1000; |