diff options
author | Huang Shijie <b32955@freescale.com> | 2012-08-28 13:53:49 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-09-13 16:25:22 +0800 |
commit | 9bba02d47489f2455bae09815b779bdc494efabb (patch) | |
tree | e43358f9d911f7840a3dff36f5962e16f26847fe | |
parent | e99dbb43193c818271b456741e5e3a65c93cd9a3 (diff) |
ENGR00223349-4 gpmi: enable the EDO support for mx6q
Enable the EDO mode for mx6q.
The following is the test result with the same nand chip (Micron MT29F32G08QAA)
in mode 4:
The test result without enable the EDO mode:
=================================================
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: scanned 400 eraseblocks, 6 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 1945 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 3384 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 1841 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 3136 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 1853 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 3164 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 145441 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 146711 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 147139 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 147786 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 147569 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 147677 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 147677 KiB/s
mtd_speedtest: finished
=================================================
The test result enable the EDO mode:
=================================================
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: scanned 400 eraseblocks, 6 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 3733 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 20413 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 3603 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 18966 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 3668 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 19686 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 146604 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 147354 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 147677 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 148002 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 147894 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 148329 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 148220 KiB/s
mtd_speedtest: finished
=================================================
We can see that there is 6 times performance improvement for reading
when we enable the EDO mode.
Signed-off-by: Huang Shijie <b32955@freescale.com>
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 164 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 |
2 files changed, 166 insertions, 2 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index c13ae42a137d..01c81faffa4a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -30,6 +30,9 @@ #define FEATURE_SIZE 4 /* p1, p2, p3, p4 */ #define NAND_CMD_SET_FEATURE 0xef +#define NAND_CMD_GET_FEATURE 0xee +#define ONFI_ASYNC_MODE_4 (1 << 4) +#define ONFI_ASYNC_MODE_5 (1 << 5) struct timing_threshod timing_default_threshold = { .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >> @@ -308,6 +311,139 @@ inline bool is_ddr_nand(struct gpmi_nand_data *this) return this->nand.onfi_version; } +/* + * Firstly, we should know what's the GPMI-clock-period means. + * The GPMI-clock-period is the internal clock in the gpmi nand controller. + * If you set 100MHz to gpmi nand controller, the GPMI-clock-period is 10ns. + * + * Now, we begin to describe how to compute the right RDN_DELAY. + * + * 1) From the aspect of the nand chip pin: + * Delay = (tREA + C - tRP) [1] + * + * tREA : the maximum read access time. From the ONFI nand standards, + * we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4. + * Please check it in : www.onfi.org + * C : a constant for adjust the delay. Choose 4 or 3. + * tRP : the read pulse width. + * Specified by the HW_GPMI_TIMING0:DATA_SETUP: + * tRP = (GPMI-clock-period) * DATA_SETUP + * + * 2) From the aspect of the GPMI nand controller: + * Delay = RDN_DELAY * 0.125 * RP [2] + * + * RP : the DLL reference period. + * if (GPMI-clock-period > 12ns) + * RP = GPMI-clock-period / 2; + * else + * RP = GPMI-clock-period; + * + * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period + * is greater 12ns. + * + * 3) since [1] equals [2], we get: + * + * (tREA + 4 - tRP) * 8 + * RDN_DELAY = --------------------- [3] + * RP + * + * 4) We only support the fastest asynchronous mode of ONFI nand. + * For some ONFI nand, the mode 4 is the fastest mode; + * while for some ONFI nand, the mode 5 is the fastest mode. + * So we only support the mode 4 and mode 5. It is no need to + * support other modes. + */ +static void set_edo_timing(struct gpmi_nand_data *this, + struct gpmi_nfc_hardware_timing *hw) +{ + int mode = this->timing_mode; + + /* for GPMI_HW_GPMI_TIMING0 */ + hw->data_setup_in_cycles = 1; + hw->data_hold_in_cycles = 1; + hw->address_setup_in_cycles = ((5 == mode) ? 1 : 0); + + /* for GPMI_HW_GPMI_TIMING1 */ + hw->device_busy_timeout = 0x9000; + + /* for GPMI_HW_GPMI_CTRL1 */ + hw->wrn_dly_sel = 3; /* no delay for write strobe. */ + if (GPMI_IS_MX6Q(this)) { + /* + * for mx6q, we give a parameter table about the delay: + * delay | half_period + * + -------------------------+ + * (mode 5) | 8 | 0 | + * ------ | -------------------------+ + * (mode 4) | 0xe | 1 | + * + -------------------------+ + */ + if (mode == 5) { + hw->sample_delay_factor = 8; + hw->use_half_periods = 0; + } else /* mode == 4 */{ + hw->sample_delay_factor = 0xe; + hw->use_half_periods = 1; + } + } +} + +static int enable_edo_mode(struct gpmi_nand_data *this, int mode) +{ + struct resources *r = &this->resources; + struct nand_chip *nand = &this->nand; + struct mtd_info *mtd = &this->mtd; + uint8_t device_feature[FEATURE_SIZE]; + int status; + + nand->select_chip(mtd, 0); + + /* [1] send SET FEATURE commond to NAND */ + memset(device_feature, 0, sizeof(device_feature)); + device_feature[0] = mode & 0x7; + + nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand->cmdfunc(mtd, NAND_CMD_SET_FEATURE, 1, -1); + nand->write_buf(mtd, device_feature, FEATURE_SIZE); + status = nand->waitfunc(mtd, nand); + if (status & 1) { + printk(KERN_ERR "fail !!\n"); + return -EINVAL; + } + + memset(device_feature, 0, 4); + nand->cmdfunc(mtd, NAND_CMD_GET_FEATURE, 1, -1); + nand->read_buf(mtd, device_feature, 4); + if (device_feature[0] != mode) { + printk(KERN_ERR "failed in set feature of mode : %d\n", mode); + return -EINVAL; + + } + + nand->select_chip(mtd, -1); + + /* [2] about the clock, pay attention! */ + { + unsigned long rate; + struct clk *enfc_clk; + + enfc_clk = clk_get(NULL, "enfc_clk"); + if (IS_ERR(enfc_clk)) { + printk(KERN_INFO "No enfc_clk clock\n"); + return -EINVAL; + } + + clk_set_parent(r->clock, enfc_clk); + rate = (mode == 5) ? 100000000 : 80000000; + clk_set_rate(enfc_clk, enfc_clk->round_rate(enfc_clk, rate)); + clk_set_rate(r->clock, rate); + } + + this->flags |= ASYNC_EDO_ENABLED; + this->timing_mode = mode; + dev_info(this->dev, "enable asynchronous EDO mode %d\n", mode); + return 0; +} /* To check if we need to initialize something else*/ int extra_init(struct gpmi_nand_data *this) { @@ -317,6 +453,24 @@ int extra_init(struct gpmi_nand_data *this) if (0) return enable_ddr_toggle(this); } + + /* Enable the asynchronous EDO mode, we only support the mode 4 and 5 */ + if (is_ddr_nand(this)) { + struct nand_chip *nand = &this->nand; + int mode; + + mode = le16_to_cpu(nand->onfi_params.async_timing_mode); + + if (mode & ONFI_ASYNC_MODE_5) + mode = 5; + else if (mode & ONFI_ASYNC_MODE_4) + mode = 4; + else + return 0; + + return enable_edo_mode(this, mode); + } + return 0; } @@ -1023,8 +1177,14 @@ void gpmi_begin(struct gpmi_nand_data *this) } } - /* calculate the timings. */ - gpmi_nfc_compute_hardware_timing(this, &hw); + if (this->flags & ASYNC_EDO_ENABLED) { + if (this->flags & ASYNC_EDO_TIMING_CONFIGED) + return; + set_edo_timing(this, &hw); + this->flags |= ASYNC_EDO_TIMING_CONFIGED; + } else { + gpmi_nfc_compute_hardware_timing(this, &hw); + } /* [1] Set HW_GPMI_TIMING0 */ reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 19b049f64d60..21e1f6569211 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -120,6 +120,8 @@ struct nand_timing { int8_t tRHOH_in_ns; }; +#define ASYNC_EDO_ENABLED 1 +#define ASYNC_EDO_TIMING_CONFIGED 2 struct gpmi_nand_data { /* System Interface */ struct device *dev; @@ -181,6 +183,8 @@ struct gpmi_nand_data { /* private */ void *private; + int flags; + int timing_mode; }; /** |