diff options
author | Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> | 2011-07-13 20:52:38 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2011-07-25 09:41:12 -0400 |
commit | 0b052f4a088ddc47a5da23dd733522241314cfb4 (patch) | |
tree | 8367cd4cb3dd7fd7e5c01c2b6117755c6e9ea72e /drivers/dma/pch_dma.c | |
parent | 95bfea1675c02d83cf1923272e62f91db11cbb8f (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/pch_dma.c')
-rw-r--r-- | drivers/dma/pch_dma.c | 42 |
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 | |||
65 | static unsigned int init_nr_desc_per_channel = 64; | 68 | static unsigned int init_nr_desc_per_channel = 64; |
66 | module_param(init_nr_desc_per_channel, uint, 0644); | 69 | module_param(init_nr_desc_per_channel, uint, 0644); |
67 | MODULE_PARM_DESC(init_nr_desc_per_channel, | 70 | MODULE_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", |