aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Shijie <b32955@freescale.com>2012-02-16 01:17:33 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-03-26 19:37:28 -0400
commit921de864b7c6413f15224d8f5e677541e8e1ac6d (patch)
tree325815e4a65a26b961796314fdb0b2cd6e0b9975
parent3946860409130038ef6e0e5c50f2203053eae2b7 (diff)
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>
-rw-r--r--drivers/dma/mxs-dma.c32
-rw-r--r--drivers/mmc/host/mxs-mmc.c10
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c19
3 files changed, 46 insertions, 15 deletions
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 0afcedbe2471..0ddfd30b56ad 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -349,10 +349,32 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
349 clk_disable_unprepare(mxs_dma->clk); 349 clk_disable_unprepare(mxs_dma->clk);
350} 350}
351 351
352/*
353 * How to use the flags for ->device_prep_slave_sg() :
354 * [1] If there is only one DMA command in the DMA chain, the code should be:
355 * ......
356 * ->device_prep_slave_sg(DMA_CTRL_ACK);
357 * ......
358 * [2] If there are two DMA commands in the DMA chain, the code should be
359 * ......
360 * ->device_prep_slave_sg(0);
361 * ......
362 * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
363 * ......
364 * [3] If there are more than two DMA commands in the DMA chain, the code
365 * should be:
366 * ......
367 * ->device_prep_slave_sg(0); // First
368 * ......
369 * ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]);
370 * ......
371 * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last
372 * ......
373 */
352static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( 374static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
353 struct dma_chan *chan, struct scatterlist *sgl, 375 struct dma_chan *chan, struct scatterlist *sgl,
354 unsigned int sg_len, enum dma_transfer_direction direction, 376 unsigned int sg_len, enum dma_transfer_direction direction,
355 unsigned long append) 377 unsigned long flags)
356{ 378{
357 struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); 379 struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
358 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; 380 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -360,6 +382,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
360 struct scatterlist *sg; 382 struct scatterlist *sg;
361 int i, j; 383 int i, j;
362 u32 *pio; 384 u32 *pio;
385 bool append = flags & DMA_PREP_INTERRUPT;
363 int idx = append ? mxs_chan->desc_count : 0; 386 int idx = append ? mxs_chan->desc_count : 0;
364 387
365 if (mxs_chan->status == DMA_IN_PROGRESS && !append) 388 if (mxs_chan->status == DMA_IN_PROGRESS && !append)
@@ -386,7 +409,6 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
386 ccw->bits |= CCW_CHAIN; 409 ccw->bits |= CCW_CHAIN;
387 ccw->bits &= ~CCW_IRQ; 410 ccw->bits &= ~CCW_IRQ;
388 ccw->bits &= ~CCW_DEC_SEM; 411 ccw->bits &= ~CCW_DEC_SEM;
389 ccw->bits &= ~CCW_WAIT4END;
390 } else { 412 } else {
391 idx = 0; 413 idx = 0;
392 } 414 }
@@ -401,7 +423,8 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
401 ccw->bits = 0; 423 ccw->bits = 0;
402 ccw->bits |= CCW_IRQ; 424 ccw->bits |= CCW_IRQ;
403 ccw->bits |= CCW_DEC_SEM; 425 ccw->bits |= CCW_DEC_SEM;
404 ccw->bits |= CCW_WAIT4END; 426 if (flags & DMA_CTRL_ACK)
427 ccw->bits |= CCW_WAIT4END;
405 ccw->bits |= CCW_HALT_ON_TERM; 428 ccw->bits |= CCW_HALT_ON_TERM;
406 ccw->bits |= CCW_TERM_FLUSH; 429 ccw->bits |= CCW_TERM_FLUSH;
407 ccw->bits |= BF_CCW(sg_len, PIO_NUM); 430 ccw->bits |= BF_CCW(sg_len, PIO_NUM);
@@ -432,7 +455,8 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
432 ccw->bits &= ~CCW_CHAIN; 455 ccw->bits &= ~CCW_CHAIN;
433 ccw->bits |= CCW_IRQ; 456 ccw->bits |= CCW_IRQ;
434 ccw->bits |= CCW_DEC_SEM; 457 ccw->bits |= CCW_DEC_SEM;
435 ccw->bits |= CCW_WAIT4END; 458 if (flags & DMA_CTRL_ACK)
459 ccw->bits |= CCW_WAIT4END;
436 } 460 }
437 } 461 }
438 } 462 }
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index e5ea2b177e59..4062812136ef 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -305,7 +305,7 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
305} 305}
306 306
307static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( 307static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
308 struct mxs_mmc_host *host, unsigned int append) 308 struct mxs_mmc_host *host, unsigned long flags)
309{ 309{
310 struct dma_async_tx_descriptor *desc; 310 struct dma_async_tx_descriptor *desc;
311 struct mmc_data *data = host->data; 311 struct mmc_data *data = host->data;
@@ -325,7 +325,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
325 } 325 }
326 326
327 desc = host->dmach->device->device_prep_slave_sg(host->dmach, 327 desc = host->dmach->device->device_prep_slave_sg(host->dmach,
328 sgl, sg_len, host->slave_dirn, append); 328 sgl, sg_len, host->slave_dirn, flags);
329 if (desc) { 329 if (desc) {
330 desc->callback = mxs_mmc_dma_irq_callback; 330 desc->callback = mxs_mmc_dma_irq_callback;
331 desc->callback_param = host; 331 desc->callback_param = host;
@@ -358,7 +358,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
358 host->ssp_pio_words[2] = cmd1; 358 host->ssp_pio_words[2] = cmd1;
359 host->dma_dir = DMA_NONE; 359 host->dma_dir = DMA_NONE;
360 host->slave_dirn = DMA_TRANS_NONE; 360 host->slave_dirn = DMA_TRANS_NONE;
361 desc = mxs_mmc_prep_dma(host, 0); 361 desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
362 if (!desc) 362 if (!desc)
363 goto out; 363 goto out;
364 364
@@ -398,7 +398,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
398 host->ssp_pio_words[2] = cmd1; 398 host->ssp_pio_words[2] = cmd1;
399 host->dma_dir = DMA_NONE; 399 host->dma_dir = DMA_NONE;
400 host->slave_dirn = DMA_TRANS_NONE; 400 host->slave_dirn = DMA_TRANS_NONE;
401 desc = mxs_mmc_prep_dma(host, 0); 401 desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
402 if (!desc) 402 if (!desc)
403 goto out; 403 goto out;
404 404
@@ -526,7 +526,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
526 host->data = data; 526 host->data = data;
527 host->dma_dir = dma_data_dir; 527 host->dma_dir = dma_data_dir;
528 host->slave_dirn = slave_dirn; 528 host->slave_dirn = slave_dirn;
529 desc = mxs_mmc_prep_dma(host, 1); 529 desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
530 if (!desc) 530 if (!desc)
531 goto out; 531 goto out;
532 532
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)
849 sg_init_one(sgl, this->cmd_buffer, this->command_length); 849 sg_init_one(sgl, this->cmd_buffer, this->command_length);
850 dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); 850 dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
851 desc = channel->device->device_prep_slave_sg(channel, 851 desc = channel->device->device_prep_slave_sg(channel,
852 sgl, 1, DMA_MEM_TO_DEV, 1); 852 sgl, 1, DMA_MEM_TO_DEV,
853 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
854
853 if (!desc) { 855 if (!desc) {
854 pr_err("step 2 error\n"); 856 pr_err("step 2 error\n");
855 return -1; 857 return -1;
@@ -891,7 +893,8 @@ int gpmi_send_data(struct gpmi_nand_data *this)
891 /* [2] send DMA request */ 893 /* [2] send DMA request */
892 prepare_data_dma(this, DMA_TO_DEVICE); 894 prepare_data_dma(this, DMA_TO_DEVICE);
893 desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, 895 desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
894 1, DMA_MEM_TO_DEV, 1); 896 1, DMA_MEM_TO_DEV,
897 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
895 if (!desc) { 898 if (!desc) {
896 pr_err("step 2 error\n"); 899 pr_err("step 2 error\n");
897 return -1; 900 return -1;
@@ -927,7 +930,8 @@ int gpmi_read_data(struct gpmi_nand_data *this)
927 /* [2] : send DMA request */ 930 /* [2] : send DMA request */
928 prepare_data_dma(this, DMA_FROM_DEVICE); 931 prepare_data_dma(this, DMA_FROM_DEVICE);
929 desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, 932 desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
930 1, DMA_DEV_TO_MEM, 1); 933 1, DMA_DEV_TO_MEM,
934 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
931 if (!desc) { 935 if (!desc) {
932 pr_err("step 2 error\n"); 936 pr_err("step 2 error\n");
933 return -1; 937 return -1;
@@ -974,7 +978,8 @@ int gpmi_send_page(struct gpmi_nand_data *this,
974 978
975 desc = channel->device->device_prep_slave_sg(channel, 979 desc = channel->device->device_prep_slave_sg(channel,
976 (struct scatterlist *)pio, 980 (struct scatterlist *)pio,
977 ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); 981 ARRAY_SIZE(pio), DMA_TRANS_NONE,
982 DMA_CTRL_ACK);
978 if (!desc) { 983 if (!desc) {
979 pr_err("step 2 error\n"); 984 pr_err("step 2 error\n");
980 return -1; 985 return -1;
@@ -1038,7 +1043,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
1038 pio[5] = auxiliary; 1043 pio[5] = auxiliary;
1039 desc = channel->device->device_prep_slave_sg(channel, 1044 desc = channel->device->device_prep_slave_sg(channel,
1040 (struct scatterlist *)pio, 1045 (struct scatterlist *)pio,
1041 ARRAY_SIZE(pio), DMA_TRANS_NONE, 1); 1046 ARRAY_SIZE(pio), DMA_TRANS_NONE,
1047 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1042 if (!desc) { 1048 if (!desc) {
1043 pr_err("step 2 error\n"); 1049 pr_err("step 2 error\n");
1044 return -1; 1050 return -1;
@@ -1057,7 +1063,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
1057 pio[1] = 0; 1063 pio[1] = 0;
1058 desc = channel->device->device_prep_slave_sg(channel, 1064 desc = channel->device->device_prep_slave_sg(channel,
1059 (struct scatterlist *)pio, 2, 1065 (struct scatterlist *)pio, 2,
1060 DMA_TRANS_NONE, 1); 1066 DMA_TRANS_NONE,
1067 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1061 if (!desc) { 1068 if (!desc) {
1062 pr_err("step 3 error\n"); 1069 pr_err("step 3 error\n");
1063 return -1; 1070 return -1;