aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorLothar Waßmann <LW@KARO-electronics.de>2011-12-08 03:15:44 -0500
committerVinod Koul <vinod.koul@linux.intel.com>2011-12-23 10:24:55 -0500
commit7ad7a345a4f17c08a1bb9bfdbb62f7793d84aa36 (patch)
tree83839c0af2da4529d5fdec1b9c961b541d572c66 /drivers/dma
parent6d23ea4b1906f28f5d99ad6aeef7207c48be6bfd (diff)
dma: mxs-dma: Don't use CLKGATE bits in CTRL0 to disable DMA channels
This is how the original Freescale code (unintentionally) worked, because the code path which would have asserted the CLKGATE bit was never actually reached in their code. This fixes the nefarious "DMA timout" bug when multiple DMA channels (e.g. GPMI NAND and MMC) are used at the same time. If a better fix for this problem should be found, the clkgate handling could be reinstated. See http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/065228.html Also reverse the order of mxs_dma_disable_chan() and mxs_dma_reset_chan() in mxs_dma_control() because mxs_dma_reset_chan() can only work when the DMA channel is enabled. Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de> Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/mxs-dma.c29
1 files changed, 1 insertions, 28 deletions
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 1b4c6be3aacb..6548595c26dc 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -44,7 +44,6 @@
44#define HW_APBHX_CTRL0 0x000 44#define HW_APBHX_CTRL0 0x000
45#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29) 45#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
46#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28) 46#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28)
47#define BP_APBH_CTRL0_CLKGATE_CHANNEL 8
48#define BP_APBH_CTRL0_RESET_CHANNEL 16 47#define BP_APBH_CTRL0_RESET_CHANNEL 16
49#define HW_APBHX_CTRL1 0x010 48#define HW_APBHX_CTRL1 0x010
50#define HW_APBHX_CTRL2 0x020 49#define HW_APBHX_CTRL2 0x020
@@ -131,23 +130,6 @@ struct mxs_dma_engine {
131 struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; 130 struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS];
132}; 131};
133 132
134static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable)
135{
136 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
137 int chan_id = mxs_chan->chan.chan_id;
138 int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR;
139
140 /* enable apbh channel clock */
141 if (dma_is_apbh()) {
142 if (apbh_is_old())
143 writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
144 mxs_dma->base + HW_APBHX_CTRL0 + set_clr);
145 else
146 writel(1 << chan_id,
147 mxs_dma->base + HW_APBHX_CTRL0 + set_clr);
148 }
149}
150
151static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) 133static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
152{ 134{
153 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; 135 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -166,9 +148,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
166 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; 148 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
167 int chan_id = mxs_chan->chan.chan_id; 149 int chan_id = mxs_chan->chan.chan_id;
168 150
169 /* clkgate needs to be enabled before writing other registers */
170 mxs_dma_clkgate(mxs_chan, 1);
171
172 /* set cmd_addr up */ 151 /* set cmd_addr up */
173 writel(mxs_chan->ccw_phys, 152 writel(mxs_chan->ccw_phys,
174 mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); 153 mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
@@ -179,9 +158,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
179 158
180static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) 159static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
181{ 160{
182 /* disable apbh channel clock */
183 mxs_dma_clkgate(mxs_chan, 0);
184
185 mxs_chan->status = DMA_SUCCESS; 161 mxs_chan->status = DMA_SUCCESS;
186} 162}
187 163
@@ -339,10 +315,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
339 if (ret) 315 if (ret)
340 goto err_clk; 316 goto err_clk;
341 317
342 /* clkgate needs to be enabled for reset to finish */
343 mxs_dma_clkgate(mxs_chan, 1);
344 mxs_dma_reset_chan(mxs_chan); 318 mxs_dma_reset_chan(mxs_chan);
345 mxs_dma_clkgate(mxs_chan, 0);
346 319
347 dma_async_tx_descriptor_init(&mxs_chan->desc, chan); 320 dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
348 mxs_chan->desc.tx_submit = mxs_dma_tx_submit; 321 mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
@@ -542,8 +515,8 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
542 515
543 switch (cmd) { 516 switch (cmd) {
544 case DMA_TERMINATE_ALL: 517 case DMA_TERMINATE_ALL:
545 mxs_dma_disable_chan(mxs_chan);
546 mxs_dma_reset_chan(mxs_chan); 518 mxs_dma_reset_chan(mxs_chan);
519 mxs_dma_disable_chan(mxs_chan);
547 break; 520 break;
548 case DMA_PAUSE: 521 case DMA_PAUSE:
549 mxs_dma_pause_chan(mxs_chan); 522 mxs_dma_pause_chan(mxs_chan);