aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>2011-07-13 20:52:38 -0400
committerVinod Koul <vinod.koul@intel.com>2011-07-25 09:41:12 -0400
commit0b052f4a088ddc47a5da23dd733522241314cfb4 (patch)
tree8367cd4cb3dd7fd7e5c01c2b6117755c6e9ea72e /drivers/dma
parent95bfea1675c02d83cf1923272e62f91db11cbb8f (diff)
pch_dma: Fix CTL register access issue
Currently, Mode-Control register is accessed by read-modify-write. According to DMA hardware specifications datasheet, prohibits this method. Because this register resets to 0 by DMA HW after DMA transfer completes. Thus, current read-modify-write processing can cause unexpected behavior. The datasheet says in case of writing Mode-Control register, set the value for only target channel, the others must set '11b'. e.g. Set DMA0=01b DMA11=10b CTL0=33333331h CTL2=00002333h NOTE: CTL0 includes DMA0~7 Mode-Control register. CTL2 includes DMA8~11 Mode-Control register. This patch modifies the issue. Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/pch_dma.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index d9d95a4dd854..1ac8d4b580b7 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -62,6 +62,9 @@
62 62
63#define MAX_CHAN_NR 8 63#define MAX_CHAN_NR 8
64 64
65#define DMA_MASK_CTL0_MODE 0x33333333
66#define DMA_MASK_CTL2_MODE 0x00003333
67
65static unsigned int init_nr_desc_per_channel = 64; 68static unsigned int init_nr_desc_per_channel = 64;
66module_param(init_nr_desc_per_channel, uint, 0644); 69module_param(init_nr_desc_per_channel, uint, 0644);
67MODULE_PARM_DESC(init_nr_desc_per_channel, 70MODULE_PARM_DESC(init_nr_desc_per_channel,
@@ -210,10 +213,17 @@ static void pdc_set_dir(struct dma_chan *chan)
210 struct pch_dma_chan *pd_chan = to_pd_chan(chan); 213 struct pch_dma_chan *pd_chan = to_pd_chan(chan);
211 struct pch_dma *pd = to_pd(chan->device); 214 struct pch_dma *pd = to_pd(chan->device);
212 u32 val; 215 u32 val;
216 u32 mask_mode;
217 u32 mask_ctl;
213 218
214 if (chan->chan_id < 8) { 219 if (chan->chan_id < 8) {
215 val = dma_readl(pd, CTL0); 220 val = dma_readl(pd, CTL0);
216 221
222 mask_mode = DMA_CTL0_MODE_MASK_BITS <<
223 (DMA_CTL0_BITS_PER_CH * chan->chan_id);
224 mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
225 (DMA_CTL0_BITS_PER_CH * chan->chan_id));
226 val &= mask_mode;
217 if (pd_chan->dir == DMA_TO_DEVICE) 227 if (pd_chan->dir == DMA_TO_DEVICE)
218 val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id + 228 val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
219 DMA_CTL0_DIR_SHIFT_BITS); 229 DMA_CTL0_DIR_SHIFT_BITS);
@@ -221,18 +231,24 @@ static void pdc_set_dir(struct dma_chan *chan)
221 val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id + 231 val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
222 DMA_CTL0_DIR_SHIFT_BITS)); 232 DMA_CTL0_DIR_SHIFT_BITS));
223 233
234 val |= mask_ctl;
224 dma_writel(pd, CTL0, val); 235 dma_writel(pd, CTL0, val);
225 } else { 236 } else {
226 int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */ 237 int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
227 val = dma_readl(pd, CTL3); 238 val = dma_readl(pd, CTL3);
228 239
240 mask_mode = DMA_CTL0_MODE_MASK_BITS <<
241 (DMA_CTL0_BITS_PER_CH * ch);
242 mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
243 (DMA_CTL0_BITS_PER_CH * ch));
244 val &= mask_mode;
229 if (pd_chan->dir == DMA_TO_DEVICE) 245 if (pd_chan->dir == DMA_TO_DEVICE)
230 val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch + 246 val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch +
231 DMA_CTL0_DIR_SHIFT_BITS); 247 DMA_CTL0_DIR_SHIFT_BITS);
232 else 248 else
233 val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * ch + 249 val &= ~(0x1 << (DMA_CTL0_BITS_PER_CH * ch +
234 DMA_CTL0_DIR_SHIFT_BITS)); 250 DMA_CTL0_DIR_SHIFT_BITS));
235 251 val |= mask_ctl;
236 dma_writel(pd, CTL3, val); 252 dma_writel(pd, CTL3, val);
237 } 253 }
238 254
@@ -244,26 +260,30 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
244{ 260{
245 struct pch_dma *pd = to_pd(chan->device); 261 struct pch_dma *pd = to_pd(chan->device);
246 u32 val; 262 u32 val;
263 u32 mask_ctl;
264 u32 mask_dir;
247 265
248 if (chan->chan_id < 8) { 266 if (chan->chan_id < 8) {
267 mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
268 (DMA_CTL0_BITS_PER_CH * chan->chan_id));
269 mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +\
270 DMA_CTL0_DIR_SHIFT_BITS);
249 val = dma_readl(pd, CTL0); 271 val = dma_readl(pd, CTL0);
250 272 val &= mask_dir;
251 val &= ~(DMA_CTL0_MODE_MASK_BITS <<
252 (DMA_CTL0_BITS_PER_CH * chan->chan_id));
253 val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id); 273 val |= mode << (DMA_CTL0_BITS_PER_CH * chan->chan_id);
254 274 val |= mask_ctl;
255 dma_writel(pd, CTL0, val); 275 dma_writel(pd, CTL0, val);
256 } else { 276 } else {
257 int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */ 277 int ch = chan->chan_id - 8; /* ch8-->0 ch9-->1 ... ch11->3 */
258 278 mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
279 (DMA_CTL0_BITS_PER_CH * ch));
280 mask_dir = 1 << (DMA_CTL0_BITS_PER_CH * ch +\
281 DMA_CTL0_DIR_SHIFT_BITS);
259 val = dma_readl(pd, CTL3); 282 val = dma_readl(pd, CTL3);
260 283 val &= mask_dir;
261 val &= ~(DMA_CTL0_MODE_MASK_BITS <<
262 (DMA_CTL0_BITS_PER_CH * ch));
263 val |= mode << (DMA_CTL0_BITS_PER_CH * ch); 284 val |= mode << (DMA_CTL0_BITS_PER_CH * ch);
264 285 val |= mask_ctl;
265 dma_writel(pd, CTL3, val); 286 dma_writel(pd, CTL3, val);
266
267 } 287 }
268 288
269 dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n", 289 dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n",