diff options
author | Huang Shijie <b32955@freescale.com> | 2012-09-13 02:57:59 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-09-29 10:56:36 -0400 |
commit | 995fbbf563fcec058a1135bdd112ac969c817e65 (patch) | |
tree | 5c384059d0ab90fe4c001296f32ddff94ef0e6ca | |
parent | e1ca95e3a93c9a0392163a7a6791deda48b5eeca (diff) |
mtd: gpmi: add EDO feature for imx6q
When the frequency on the nand chip pins is above 33MHz,
the nand EDO(extended Data Out) timing could be applied.
The GPMI implements a Feedback read strobe to sample the read data in
the EDO timing mode.
This patch adds the EDO feature for the gpmi-nand driver.
For some onfi nand chips, the mode 4 is the fastest;
while for other onfi nand chips, the mode 5 is the fastest.
This patch only adds the support for the fastest asynchronous timing mode.
So this patch only supports the mode 4 and mode 5.
I tested several Micron's ONFI nand chips with EDO enabled,
take Micron MT29F32G08MAA for example (in mode 5, 100MHz):
1) The test result BEFORE we add the EDO feature:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 209715200, eraseblock size 524288,
page size 4096, count of eraseblocks 400,
pages per eraseblock 128, OOB size 218
.......................................
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 3632 KiB/s
.......................................
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 3554 KiB/s
.......................................
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 3592 KiB/s
.......................................
=================================================
2) The test result AFTER we add the EDO feature:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 209715200, eraseblock size 524288,
page size 4096, count of eraseblocks 400,
pages per eraseblock 128, OOB size 218
.......................................
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 19555 KiB/s
.......................................
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 17319 KiB/s
.......................................
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 18339 KiB/s
.......................................
=================================================
3) The read data performance is much improved by more then 5 times.
Signed-off-by: Huang Shijie <b32955@freescale.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 214 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 8 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 6 |
3 files changed, 227 insertions, 1 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 010665ca631a..c036e51f3200 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c | |||
@@ -737,6 +737,215 @@ return_results: | |||
737 | return 0; | 737 | return 0; |
738 | } | 738 | } |
739 | 739 | ||
740 | /* | ||
741 | * <1> Firstly, we should know what's the GPMI-clock means. | ||
742 | * The GPMI-clock is the internal clock in the gpmi nand controller. | ||
743 | * If you set 100MHz to gpmi nand controller, the GPMI-clock's period | ||
744 | * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period. | ||
745 | * | ||
746 | * <2> Secondly, we should know what's the frequency on the nand chip pins. | ||
747 | * The frequency on the nand chip pins is derived from the GPMI-clock. | ||
748 | * We can get it from the following equation: | ||
749 | * | ||
750 | * F = G / (DS + DH) | ||
751 | * | ||
752 | * F : the frequency on the nand chip pins. | ||
753 | * G : the GPMI clock, such as 100MHz. | ||
754 | * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP | ||
755 | * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD | ||
756 | * | ||
757 | * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz, | ||
758 | * the nand EDO(extended Data Out) timing could be applied. | ||
759 | * The GPMI implements a feedback read strobe to sample the read data. | ||
760 | * The feedback read strobe can be delayed to support the nand EDO timing | ||
761 | * where the read strobe may deasserts before the read data is valid, and | ||
762 | * read data is valid for some time after read strobe. | ||
763 | * | ||
764 | * The following figure illustrates some aspects of a NAND Flash read: | ||
765 | * | ||
766 | * |<---tREA---->| | ||
767 | * | | | ||
768 | * | | | | ||
769 | * |<--tRP-->| | | ||
770 | * | | | | ||
771 | * __ ___|__________________________________ | ||
772 | * RDN \________/ | | ||
773 | * | | ||
774 | * /---------\ | ||
775 | * Read Data --------------< >--------- | ||
776 | * \---------/ | ||
777 | * | | | ||
778 | * |<-D->| | ||
779 | * FeedbackRDN ________ ____________ | ||
780 | * \___________/ | ||
781 | * | ||
782 | * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY. | ||
783 | * | ||
784 | * | ||
785 | * <4> Now, we begin to describe how to compute the right RDN_DELAY. | ||
786 | * | ||
787 | * 4.1) From the aspect of the nand chip pins: | ||
788 | * Delay = (tREA + C - tRP) {1} | ||
789 | * | ||
790 | * tREA : the maximum read access time. From the ONFI nand standards, | ||
791 | * we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4. | ||
792 | * Please check it in : www.onfi.org | ||
793 | * C : a constant for adjust the delay. default is 4. | ||
794 | * tRP : the read pulse width. | ||
795 | * Specified by the HW_GPMI_TIMING0:DATA_SETUP: | ||
796 | * tRP = (GPMI-clock-period) * DATA_SETUP | ||
797 | * | ||
798 | * 4.2) From the aspect of the GPMI nand controller: | ||
799 | * Delay = RDN_DELAY * 0.125 * RP {2} | ||
800 | * | ||
801 | * RP : the DLL reference period. | ||
802 | * if (GPMI-clock-period > DLL_THRETHOLD) | ||
803 | * RP = GPMI-clock-period / 2; | ||
804 | * else | ||
805 | * RP = GPMI-clock-period; | ||
806 | * | ||
807 | * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period | ||
808 | * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD | ||
809 | * is 16ns, but in mx6q, we use 12ns. | ||
810 | * | ||
811 | * 4.3) since {1} equals {2}, we get: | ||
812 | * | ||
813 | * (tREA + 4 - tRP) * 8 | ||
814 | * RDN_DELAY = --------------------- {3} | ||
815 | * RP | ||
816 | * | ||
817 | * 4.4) We only support the fastest asynchronous mode of ONFI nand. | ||
818 | * For some ONFI nand, the mode 4 is the fastest mode; | ||
819 | * while for some ONFI nand, the mode 5 is the fastest mode. | ||
820 | * So we only support the mode 4 and mode 5. It is no need to | ||
821 | * support other modes. | ||
822 | */ | ||
823 | static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, | ||
824 | struct gpmi_nfc_hardware_timing *hw) | ||
825 | { | ||
826 | struct resources *r = &this->resources; | ||
827 | unsigned long rate = clk_get_rate(r->clock[0]); | ||
828 | int mode = this->timing_mode; | ||
829 | int dll_threshold = 16; /* in ns */ | ||
830 | unsigned long delay; | ||
831 | unsigned long clk_period; | ||
832 | int t_rea; | ||
833 | int c = 4; | ||
834 | int t_rp; | ||
835 | int rp; | ||
836 | |||
837 | /* | ||
838 | * [1] for GPMI_HW_GPMI_TIMING0: | ||
839 | * The async mode requires 40MHz for mode 4, 50MHz for mode 5. | ||
840 | * The GPMI can support 100MHz at most. So if we want to | ||
841 | * get the 40MHz or 50MHz, we have to set DS=1, DH=1. | ||
842 | * Set the ADDRESS_SETUP to 0 in mode 4. | ||
843 | */ | ||
844 | hw->data_setup_in_cycles = 1; | ||
845 | hw->data_hold_in_cycles = 1; | ||
846 | hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0); | ||
847 | |||
848 | /* [2] for GPMI_HW_GPMI_TIMING1 */ | ||
849 | hw->device_busy_timeout = 0x9000; | ||
850 | |||
851 | /* [3] for GPMI_HW_GPMI_CTRL1 */ | ||
852 | hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; | ||
853 | |||
854 | if (GPMI_IS_MX6Q(this)) | ||
855 | dll_threshold = 12; | ||
856 | |||
857 | /* | ||
858 | * Enlarge 10 times for the numerator and denominator in {3}. | ||
859 | * This make us to get more accurate result. | ||
860 | */ | ||
861 | clk_period = NSEC_PER_SEC / (rate / 10); | ||
862 | dll_threshold *= 10; | ||
863 | t_rea = ((mode == 5) ? 16 : 20) * 10; | ||
864 | c *= 10; | ||
865 | |||
866 | t_rp = clk_period * 1; /* DATA_SETUP is 1 */ | ||
867 | |||
868 | if (clk_period > dll_threshold) { | ||
869 | hw->use_half_periods = 1; | ||
870 | rp = clk_period / 2; | ||
871 | } else { | ||
872 | hw->use_half_periods = 0; | ||
873 | rp = clk_period; | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * Multiply the numerator with 10, we could do a round off: | ||
878 | * 7.8 round up to 8; 7.4 round down to 7. | ||
879 | */ | ||
880 | delay = (((t_rea + c - t_rp) * 8) * 10) / rp; | ||
881 | delay = (delay + 5) / 10; | ||
882 | |||
883 | hw->sample_delay_factor = delay; | ||
884 | } | ||
885 | |||
886 | static int enable_edo_mode(struct gpmi_nand_data *this, int mode) | ||
887 | { | ||
888 | struct resources *r = &this->resources; | ||
889 | struct nand_chip *nand = &this->nand; | ||
890 | struct mtd_info *mtd = &this->mtd; | ||
891 | uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; | ||
892 | unsigned long rate; | ||
893 | int ret; | ||
894 | |||
895 | nand->select_chip(mtd, 0); | ||
896 | |||
897 | /* [1] send SET FEATURE commond to NAND */ | ||
898 | feature[0] = mode; | ||
899 | ret = nand->onfi_set_features(mtd, nand, | ||
900 | ONFI_FEATURE_ADDR_TIMING_MODE, feature); | ||
901 | if (ret) | ||
902 | goto err_out; | ||
903 | |||
904 | /* [2] send GET FEATURE command to double-check the timing mode */ | ||
905 | memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN); | ||
906 | ret = nand->onfi_get_features(mtd, nand, | ||
907 | ONFI_FEATURE_ADDR_TIMING_MODE, feature); | ||
908 | if (ret || feature[0] != mode) | ||
909 | goto err_out; | ||
910 | |||
911 | nand->select_chip(mtd, -1); | ||
912 | |||
913 | /* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */ | ||
914 | rate = (mode == 5) ? 100000000 : 80000000; | ||
915 | clk_set_rate(r->clock[0], rate); | ||
916 | |||
917 | this->flags |= GPMI_ASYNC_EDO_ENABLED; | ||
918 | this->timing_mode = mode; | ||
919 | dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode); | ||
920 | return 0; | ||
921 | |||
922 | err_out: | ||
923 | nand->select_chip(mtd, -1); | ||
924 | dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode); | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | |||
928 | int gpmi_extra_init(struct gpmi_nand_data *this) | ||
929 | { | ||
930 | struct nand_chip *chip = &this->nand; | ||
931 | |||
932 | /* Enable the asynchronous EDO feature. */ | ||
933 | if (GPMI_IS_MX6Q(this) && chip->onfi_version) { | ||
934 | int mode = onfi_get_async_timing_mode(chip); | ||
935 | |||
936 | /* We only support the timing mode 4 and mode 5. */ | ||
937 | if (mode & ONFI_TIMING_MODE_5) | ||
938 | mode = 5; | ||
939 | else if (mode & ONFI_TIMING_MODE_4) | ||
940 | mode = 4; | ||
941 | else | ||
942 | return 0; | ||
943 | |||
944 | return enable_edo_mode(this, mode); | ||
945 | } | ||
946 | return 0; | ||
947 | } | ||
948 | |||
740 | /* Begin the I/O */ | 949 | /* Begin the I/O */ |
741 | void gpmi_begin(struct gpmi_nand_data *this) | 950 | void gpmi_begin(struct gpmi_nand_data *this) |
742 | { | 951 | { |
@@ -755,7 +964,10 @@ void gpmi_begin(struct gpmi_nand_data *this) | |||
755 | goto err_out; | 964 | goto err_out; |
756 | } | 965 | } |
757 | 966 | ||
758 | gpmi_nfc_compute_hardware_timing(this, &hw); | 967 | if (this->flags & GPMI_ASYNC_EDO_ENABLED) |
968 | gpmi_compute_edo_timing(this, &hw); | ||
969 | else | ||
970 | gpmi_nfc_compute_hardware_timing(this, &hw); | ||
759 | 971 | ||
760 | /* [1] Set HW_GPMI_TIMING0 */ | 972 | /* [1] Set HW_GPMI_TIMING0 */ |
761 | reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | | 973 | reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 2bfd44876f81..d79696b2f19b 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
@@ -1517,6 +1517,14 @@ static int gpmi_scan_bbt(struct mtd_info *mtd) | |||
1517 | if (ret) | 1517 | if (ret) |
1518 | return ret; | 1518 | return ret; |
1519 | 1519 | ||
1520 | /* | ||
1521 | * Can we enable the extra features? such as EDO or Sync mode. | ||
1522 | * | ||
1523 | * We do not check the return value now. That's means if we fail in | ||
1524 | * enable the extra features, we still can run in the normal way. | ||
1525 | */ | ||
1526 | gpmi_extra_init(this); | ||
1527 | |||
1520 | /* use the default BBT implementation */ | 1528 | /* use the default BBT implementation */ |
1521 | return nand_default_bbt(mtd); | 1529 | return nand_default_bbt(mtd); |
1522 | } | 1530 | } |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 5c11e761a32e..5b6d546711a6 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h | |||
@@ -122,6 +122,10 @@ struct nand_timing { | |||
122 | }; | 122 | }; |
123 | 123 | ||
124 | struct gpmi_nand_data { | 124 | struct gpmi_nand_data { |
125 | /* flags */ | ||
126 | #define GPMI_ASYNC_EDO_ENABLED (1 << 0) | ||
127 | int flags; | ||
128 | |||
125 | /* System Interface */ | 129 | /* System Interface */ |
126 | struct device *dev; | 130 | struct device *dev; |
127 | struct platform_device *pdev; | 131 | struct platform_device *pdev; |
@@ -132,6 +136,7 @@ struct gpmi_nand_data { | |||
132 | 136 | ||
133 | /* Flash Hardware */ | 137 | /* Flash Hardware */ |
134 | struct nand_timing timing; | 138 | struct nand_timing timing; |
139 | int timing_mode; | ||
135 | 140 | ||
136 | /* BCH */ | 141 | /* BCH */ |
137 | struct bch_geometry bch_geometry; | 142 | struct bch_geometry bch_geometry; |
@@ -259,6 +264,7 @@ extern int start_dma_with_bch_irq(struct gpmi_nand_data *, | |||
259 | 264 | ||
260 | /* GPMI-NAND helper function library */ | 265 | /* GPMI-NAND helper function library */ |
261 | extern int gpmi_init(struct gpmi_nand_data *); | 266 | extern int gpmi_init(struct gpmi_nand_data *); |
267 | extern int gpmi_extra_init(struct gpmi_nand_data *); | ||
262 | extern void gpmi_clear_bch(struct gpmi_nand_data *); | 268 | extern void gpmi_clear_bch(struct gpmi_nand_data *); |
263 | extern void gpmi_dump_info(struct gpmi_nand_data *); | 269 | extern void gpmi_dump_info(struct gpmi_nand_data *); |
264 | extern int bch_set_geometry(struct gpmi_nand_data *); | 270 | extern int bch_set_geometry(struct gpmi_nand_data *); |