diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 17:25:53 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-23 17:25:53 -0400 |
commit | 7abd3ef9875eb2afcdcd4f450680298a2983a55e (patch) | |
tree | 64c19d2e5ecca182938acfcb8a172efb7d907d85 /drivers/mtd/nand/nand_base.c | |
parent | 3821720d51b5f304d2c33021a82c8da70f6d6ac9 (diff) |
[MTD] Refactor NAND hwcontrol to cmd_ctrl
The hwcontrol function enforced a step by step state machine
for any kind of hardware chip access. Let the hardware driver
know which control bits are set and inform it about a change
of the control lines. Let the hardware driver write out the
command and address bytes directly. This gives a peformance
advantage for address bus controlled chips and simplifies the
quirks in the hardware drivers.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 115 |
1 files changed, 54 insertions, 61 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index aa2e14538bf4..f6997fb77b91 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -276,10 +276,10 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) | |||
276 | struct nand_chip *this = mtd->priv; | 276 | struct nand_chip *this = mtd->priv; |
277 | switch (chip) { | 277 | switch (chip) { |
278 | case -1: | 278 | case -1: |
279 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | 279 | this->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); |
280 | break; | 280 | break; |
281 | case 0: | 281 | case 0: |
282 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | 282 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
283 | break; | 283 | break; |
284 | 284 | ||
285 | default: | 285 | default: |
@@ -548,13 +548,12 @@ static void nand_wait_ready(struct mtd_info *mtd) | |||
548 | * Send command to NAND device. This function is used for small page | 548 | * Send command to NAND device. This function is used for small page |
549 | * devices (256/512 Bytes per page) | 549 | * devices (256/512 Bytes per page) |
550 | */ | 550 | */ |
551 | static void nand_command(struct mtd_info *mtd, unsigned command, int column, | 551 | static void nand_command(struct mtd_info *mtd, unsigned int command, |
552 | int page_addr) | 552 | int column, int page_addr) |
553 | { | 553 | { |
554 | register struct nand_chip *this = mtd->priv; | 554 | register struct nand_chip *this = mtd->priv; |
555 | int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; | ||
555 | 556 | ||
556 | /* Begin command latch cycle */ | ||
557 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
558 | /* | 557 | /* |
559 | * Write out the command to the device. | 558 | * Write out the command to the device. |
560 | */ | 559 | */ |
@@ -572,33 +571,32 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, | |||
572 | column -= 256; | 571 | column -= 256; |
573 | readcmd = NAND_CMD_READ1; | 572 | readcmd = NAND_CMD_READ1; |
574 | } | 573 | } |
575 | this->write_byte(mtd, readcmd); | 574 | this->cmd_ctrl(mtd, readcmd, ctrl); |
575 | ctrl &= ~NAND_CTRL_CHANGE; | ||
576 | } | 576 | } |
577 | this->write_byte(mtd, command); | 577 | this->cmd_ctrl(mtd, command, ctrl); |
578 | 578 | ||
579 | /* Set ALE and clear CLE to start address cycle */ | 579 | /* |
580 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 580 | * Address cycle, when necessary |
581 | 581 | */ | |
582 | if (column != -1 || page_addr != -1) { | 582 | ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; |
583 | this->hwcontrol(mtd, NAND_CTL_SETALE); | 583 | /* Serially input address */ |
584 | 584 | if (column != -1) { | |
585 | /* Serially input address */ | 585 | /* Adjust columns for 16 bit buswidth */ |
586 | if (column != -1) { | 586 | if (this->options & NAND_BUSWIDTH_16) |
587 | /* Adjust columns for 16 bit buswidth */ | 587 | column >>= 1; |
588 | if (this->options & NAND_BUSWIDTH_16) | 588 | this->cmd_ctrl(mtd, column, ctrl); |
589 | column >>= 1; | 589 | ctrl &= ~NAND_CTRL_CHANGE; |
590 | this->write_byte(mtd, column); | 590 | } |
591 | } | 591 | if (page_addr != -1) { |
592 | if (page_addr != -1) { | 592 | this->cmd_ctrl(mtd, page_addr, ctrl); |
593 | this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); | 593 | ctrl &= ~NAND_CTRL_CHANGE; |
594 | this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); | 594 | this->cmd_ctrl(mtd, page_addr >> 8, ctrl); |
595 | /* One more address cycle for devices > 32MiB */ | 595 | /* One more address cycle for devices > 32MiB */ |
596 | if (this->chipsize > (32 << 20)) | 596 | if (this->chipsize > (32 << 20)) |
597 | this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f)); | 597 | this->cmd_ctrl(mtd, page_addr >> 16, ctrl); |
598 | } | ||
599 | /* Latch in address */ | ||
600 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
601 | } | 598 | } |
599 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | ||
602 | 600 | ||
603 | /* | 601 | /* |
604 | * program and erase have their own busy handlers | 602 | * program and erase have their own busy handlers |
@@ -611,15 +609,16 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, | |||
611 | case NAND_CMD_ERASE2: | 609 | case NAND_CMD_ERASE2: |
612 | case NAND_CMD_SEQIN: | 610 | case NAND_CMD_SEQIN: |
613 | case NAND_CMD_STATUS: | 611 | case NAND_CMD_STATUS: |
612 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); | ||
614 | return; | 613 | return; |
615 | 614 | ||
616 | case NAND_CMD_RESET: | 615 | case NAND_CMD_RESET: |
617 | if (this->dev_ready) | 616 | if (this->dev_ready) |
618 | break; | 617 | break; |
619 | udelay(this->chip_delay); | 618 | udelay(this->chip_delay); |
620 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 619 | this->cmd_ctrl(mtd, NAND_CMD_STATUS, |
621 | this->write_byte(mtd, NAND_CMD_STATUS); | 620 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
622 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 621 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
623 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; | 622 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; |
624 | return; | 623 | return; |
625 | 624 | ||
@@ -648,12 +647,13 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, | |||
648 | * @column: the column address for this command, -1 if none | 647 | * @column: the column address for this command, -1 if none |
649 | * @page_addr: the page address for this command, -1 if none | 648 | * @page_addr: the page address for this command, -1 if none |
650 | * | 649 | * |
651 | * Send command to NAND device. This is the version for the new large page devices | 650 | * Send command to NAND device. This is the version for the new large page |
652 | * We dont have the separate regions as we have in the small page devices. | 651 | * devices We dont have the separate regions as we have in the small page |
653 | * We must emulate NAND_CMD_READOOB to keep the code compatible. | 652 | * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. |
654 | * | 653 | * |
655 | */ | 654 | */ |
656 | static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) | 655 | static void nand_command_lp(struct mtd_info *mtd, unsigned int command, |
656 | int column, int page_addr) | ||
657 | { | 657 | { |
658 | register struct nand_chip *this = mtd->priv; | 658 | register struct nand_chip *this = mtd->priv; |
659 | 659 | ||
@@ -663,34 +663,33 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, | |||
663 | command = NAND_CMD_READ0; | 663 | command = NAND_CMD_READ0; |
664 | } | 664 | } |
665 | 665 | ||
666 | /* Begin command latch cycle */ | 666 | /* Command latch cycle */ |
667 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 667 | this->cmd_ctrl(mtd, command & 0xff, |
668 | /* Write out the command to the device. */ | 668 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
669 | this->write_byte(mtd, (command & 0xff)); | ||
670 | /* End command latch cycle */ | ||
671 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
672 | 669 | ||
673 | if (column != -1 || page_addr != -1) { | 670 | if (column != -1 || page_addr != -1) { |
674 | this->hwcontrol(mtd, NAND_CTL_SETALE); | 671 | int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; |
675 | 672 | ||
676 | /* Serially input address */ | 673 | /* Serially input address */ |
677 | if (column != -1) { | 674 | if (column != -1) { |
678 | /* Adjust columns for 16 bit buswidth */ | 675 | /* Adjust columns for 16 bit buswidth */ |
679 | if (this->options & NAND_BUSWIDTH_16) | 676 | if (this->options & NAND_BUSWIDTH_16) |
680 | column >>= 1; | 677 | column >>= 1; |
681 | this->write_byte(mtd, column & 0xff); | 678 | this->cmd_ctrl(mtd, column, ctrl); |
682 | this->write_byte(mtd, column >> 8); | 679 | ctrl &= ~NAND_CTRL_CHANGE; |
680 | this->cmd_ctrl(mtd, column >> 8, ctrl); | ||
683 | } | 681 | } |
684 | if (page_addr != -1) { | 682 | if (page_addr != -1) { |
685 | this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); | 683 | this->cmd_ctrl(mtd, page_addr, ctrl); |
686 | this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); | 684 | this->cmd_ctrl(mtd, page_addr >> 8, |
685 | NAND_NCE | NAND_ALE); | ||
687 | /* One more address cycle for devices > 128MiB */ | 686 | /* One more address cycle for devices > 128MiB */ |
688 | if (this->chipsize > (128 << 20)) | 687 | if (this->chipsize > (128 << 20)) |
689 | this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff)); | 688 | this->cmd_ctrl(mtd, page_addr >> 16, |
689 | NAND_NCE | NAND_ALE); | ||
690 | } | 690 | } |
691 | /* Latch in address */ | ||
692 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
693 | } | 691 | } |
692 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | ||
694 | 693 | ||
695 | /* | 694 | /* |
696 | * program and erase have their own busy handlers | 695 | * program and erase have their own busy handlers |
@@ -722,20 +721,14 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, | |||
722 | if (this->dev_ready) | 721 | if (this->dev_ready) |
723 | break; | 722 | break; |
724 | udelay(this->chip_delay); | 723 | udelay(this->chip_delay); |
725 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 724 | this->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE); |
726 | this->write_byte(mtd, NAND_CMD_STATUS); | 725 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
727 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
728 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; | 726 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; |
729 | return; | 727 | return; |
730 | 728 | ||
731 | case NAND_CMD_READ0: | 729 | case NAND_CMD_READ0: |
732 | /* Begin command latch cycle */ | 730 | this->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE); |
733 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 731 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
734 | /* Write out the start read command */ | ||
735 | this->write_byte(mtd, NAND_CMD_READSTART); | ||
736 | /* End command latch cycle */ | ||
737 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
738 | /* Fall through into ready check */ | ||
739 | 732 | ||
740 | /* This applies to read commands */ | 733 | /* This applies to read commands */ |
741 | default: | 734 | default: |