diff options
author | Huang Shijie <b32955@freescale.com> | 2012-02-16 10:17:33 +0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-03-27 03:37:28 +0400 |
commit | 921de864b7c6413f15224d8f5e677541e8e1ac6d (patch) | |
tree | 325815e4a65a26b961796314fdb0b2cd6e0b9975 /drivers/mtd | |
parent | 3946860409130038ef6e0e5c50f2203053eae2b7 (diff) | |
download | linux-921de864b7c6413f15224d8f5e677541e8e1ac6d.tar.xz |
mxs-dma : rewrite the last parameter of mxs_dma_prep_slave_sg()
[1] Background :
The GPMI does ECC read page operation with a DMA chain consist of three DMA
Command Structures. The middle one of the chain is used to enable the BCH,
and read out the NAND page.
The WAIT4END(wait for command end) is a comunication signal between
the GPMI and MXS-DMA.
[2] The current DMA code sets the WAIT4END bit at the last one, such as:
+-----+ +-----+ +-----+
| cmd | ------------> | cmd | ------------------> | cmd |
+-----+ +-----+ +-----+
^
|
|
set WAIT4END here
This chain works fine in the mx23/mx28.
[3] But in the new GPMI version (used in MX50/MX60), the WAIT4END bit should
be set not only at the last DMA Command Structure,
but also at the middle one, such as:
+-----+ +-----+ +-----+
| cmd | ------------> | cmd | ------------------> | cmd |
+-----+ +-----+ +-----+
^ ^
| |
| |
set WAIT4END here too set WAIT4END here
If we do not set WAIT4END, the BCH maybe stalls in "ECC reading page" state.
In the next ECC write page operation, a DMA-timeout occurs.
This has been catched in the MX6Q board.
[4] In order to fix the bug, rewrite the last parameter of mxs_dma_prep_slave_sg(),
and use the dma_ctrl_flags:
---------------------------------------------------------
DMA_PREP_INTERRUPT : append a new DMA Command Structrue.
DMA_CTRL_ACK : set the WAIT4END bit for this DMA Command Structure.
---------------------------------------------------------
[5] changes to the relative drivers:
<1> For mxs-mmc driver, just use the new flags, do not change any logic.
<2> For gpmi-nand driver, and use the new flags to set the DMA
chain, especially for ecc read page.
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Huang Shijie <b32955@freescale.com>
Acked-by: Vinod Koul <vinod.koul@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 7db6555ed3ba..5e3c5051e6a2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -849,7 +849,9 @@ int gpmi_send_command(struct gpmi_nand_data *this) sg_init_one(sgl, this->cmd_buffer, this->command_length); dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); desc = channel->device->device_prep_slave_sg(channel, - sgl, 1, DMA_MEM_TO_DEV, 1); + sgl, 1, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { pr_err("step 2 error\n"); return -1; @@ -891,7 +893,8 @@ int gpmi_send_data(struct gpmi_nand_data *this) /* [2] send DMA request */ prepare_data_dma(this, DMA_TO_DEVICE); desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_MEM_TO_DEV, 1); + 1, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -927,7 +930,8 @@ int gpmi_read_data(struct gpmi_nand_data *this) /* [2] : send DMA request */ prepare_data_dma(this, DMA_FROM_DEVICE); desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_DEV_TO_MEM, 1); + 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -974,7 +978,8 @@ int gpmi_send_page(struct gpmi_nand_data *this, desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); + ARRAY_SIZE(pio), DMA_TRANS_NONE, + DMA_CTRL_ACK); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -1038,7 +1043,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, pio[5] = auxiliary; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, 1); + ARRAY_SIZE(pio), DMA_TRANS_NONE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -1057,7 +1063,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, pio[1] = 0; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, 2, - DMA_TRANS_NONE, 1); + DMA_TRANS_NONE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { pr_err("step 3 error\n"); return -1; |