aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>2011-05-30 21:34:45 -0400
committerVinod Koul <vinod.koul@intel.com>2011-06-01 03:57:40 -0400
commitc3d4913cd4cd469cbf29d411293e937729e83f3a (patch)
tree6bb7e2da26f45b379243793f21d9858ec74515f6
parent55922c9d1b84b89cb946c777fddccb3247e7df2c (diff)
pch_dma: fix DMA issue(ch8-ch11)
ISSUE: In case PCH_DMA with I2S communications with ch8~ch11, sometimes I2S data is not send correctly. CAUSE: The following patch I submitted before was not enough modification for supporting DMA ch8~ch11. The modification for status register of ch8~11 was not enough. pch_dma: Support I2S for ML7213 IOH author Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> Mon, 9 May 2011 07:09:38 +0000 (16:09 +0900) committer Vinod Koul <vinod.koul@intel.com> Mon, 9 May 2011 11:42:23 +0000 (16:42 +0530) commit 194f5f2706c7472f9c6bb2d17fa788993606581f tree c9d4903ea02b18939a4f390956a48be1a3734517 parent 60092d0bde4c8741198da4a69b693d3709385bf1 This patch fixes the issue. We can confirm PCH_DMA with I2S communications with ch8~ch11 works well. Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/pch_dma.c69
1 files changed, 55 insertions, 14 deletions
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index ff5b38f9d45b..65c32f893a57 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -45,7 +45,8 @@
45#define DMA_STATUS_MASK_BITS 0x3 45#define DMA_STATUS_MASK_BITS 0x3
46#define DMA_STATUS_SHIFT_BITS 16 46#define DMA_STATUS_SHIFT_BITS 16
47#define DMA_STATUS_IRQ(x) (0x1 << (x)) 47#define DMA_STATUS_IRQ(x) (0x1 << (x))
48#define DMA_STATUS_ERR(x) (0x1 << ((x) + 8)) 48#define DMA_STATUS0_ERR(x) (0x1 << ((x) + 8))
49#define DMA_STATUS2_ERR(x) (0x1 << (x))
49 50
50#define DMA_DESC_WIDTH_SHIFT_BITS 12 51#define DMA_DESC_WIDTH_SHIFT_BITS 12
51#define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS) 52#define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS)
@@ -133,6 +134,7 @@ struct pch_dma {
133#define PCH_DMA_CTL3 0x0C 134#define PCH_DMA_CTL3 0x0C
134#define PCH_DMA_STS0 0x10 135#define PCH_DMA_STS0 0x10
135#define PCH_DMA_STS1 0x14 136#define PCH_DMA_STS1 0x14
137#define PCH_DMA_STS2 0x18
136 138
137#define dma_readl(pd, name) \ 139#define dma_readl(pd, name) \
138 readl((pd)->membase + PCH_DMA_##name) 140 readl((pd)->membase + PCH_DMA_##name)
@@ -183,13 +185,19 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable)
183{ 185{
184 struct pch_dma *pd = to_pd(chan->device); 186 struct pch_dma *pd = to_pd(chan->device);
185 u32 val; 187 u32 val;
188 int pos;
189
190 if (chan->chan_id < 8)
191 pos = chan->chan_id;
192 else
193 pos = chan->chan_id + 8;
186 194
187 val = dma_readl(pd, CTL2); 195 val = dma_readl(pd, CTL2);
188 196
189 if (enable) 197 if (enable)
190 val |= 0x1 << chan->chan_id; 198 val |= 0x1 << pos;
191 else 199 else
192 val &= ~(0x1 << chan->chan_id); 200 val &= ~(0x1 << pos);
193 201
194 dma_writel(pd, CTL2, val); 202 dma_writel(pd, CTL2, val);
195 203
@@ -262,7 +270,7 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
262 chan->chan_id, val); 270 chan->chan_id, val);
263} 271}
264 272
265static u32 pdc_get_status(struct pch_dma_chan *pd_chan) 273static u32 pdc_get_status0(struct pch_dma_chan *pd_chan)
266{ 274{
267 struct pch_dma *pd = to_pd(pd_chan->chan.device); 275 struct pch_dma *pd = to_pd(pd_chan->chan.device);
268 u32 val; 276 u32 val;
@@ -272,9 +280,27 @@ static u32 pdc_get_status(struct pch_dma_chan *pd_chan)
272 DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id)); 280 DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id));
273} 281}
274 282
283static u32 pdc_get_status2(struct pch_dma_chan *pd_chan)
284{
285 struct pch_dma *pd = to_pd(pd_chan->chan.device);
286 u32 val;
287
288 val = dma_readl(pd, STS2);
289 return DMA_STATUS_MASK_BITS & (val >> (DMA_STATUS_SHIFT_BITS +
290 DMA_STATUS_BITS_PER_CH * (pd_chan->chan.chan_id - 8)));
291}
292
275static bool pdc_is_idle(struct pch_dma_chan *pd_chan) 293static bool pdc_is_idle(struct pch_dma_chan *pd_chan)
276{ 294{
277 if (pdc_get_status(pd_chan) == DMA_STATUS_IDLE) 295 u32 sts;
296
297 if (pd_chan->chan.chan_id < 8)
298 sts = pdc_get_status0(pd_chan);
299 else
300 sts = pdc_get_status2(pd_chan);
301
302
303 if (sts == DMA_STATUS_IDLE)
278 return true; 304 return true;
279 else 305 else
280 return false; 306 return false;
@@ -693,30 +719,45 @@ static irqreturn_t pd_irq(int irq, void *devid)
693 struct pch_dma *pd = (struct pch_dma *)devid; 719 struct pch_dma *pd = (struct pch_dma *)devid;
694 struct pch_dma_chan *pd_chan; 720 struct pch_dma_chan *pd_chan;
695 u32 sts0; 721 u32 sts0;
722 u32 sts2;
696 int i; 723 int i;
697 int ret = IRQ_NONE; 724 int ret0 = IRQ_NONE;
725 int ret2 = IRQ_NONE;
698 726
699 sts0 = dma_readl(pd, STS0); 727 sts0 = dma_readl(pd, STS0);
728 sts2 = dma_readl(pd, STS2);
700 729
701 dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0); 730 dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0);
702 731
703 for (i = 0; i < pd->dma.chancnt; i++) { 732 for (i = 0; i < pd->dma.chancnt; i++) {
704 pd_chan = &pd->channels[i]; 733 pd_chan = &pd->channels[i];
705 734
706 if (sts0 & DMA_STATUS_IRQ(i)) { 735 if (i < 8) {
707 if (sts0 & DMA_STATUS_ERR(i)) 736 if (sts0 & DMA_STATUS_IRQ(i)) {
708 set_bit(0, &pd_chan->err_status); 737 if (sts0 & DMA_STATUS0_ERR(i))
738 set_bit(0, &pd_chan->err_status);
709 739
710 tasklet_schedule(&pd_chan->tasklet); 740 tasklet_schedule(&pd_chan->tasklet);
711 ret = IRQ_HANDLED; 741 ret0 = IRQ_HANDLED;
712 } 742 }
743 } else {
744 if (sts2 & DMA_STATUS_IRQ(i - 8)) {
745 if (sts2 & DMA_STATUS2_ERR(i))
746 set_bit(0, &pd_chan->err_status);
713 747
748 tasklet_schedule(&pd_chan->tasklet);
749 ret2 = IRQ_HANDLED;
750 }
751 }
714 } 752 }
715 753
716 /* clear interrupt bits in status register */ 754 /* clear interrupt bits in status register */
717 dma_writel(pd, STS0, sts0); 755 if (ret0)
756 dma_writel(pd, STS0, sts0);
757 if (ret2)
758 dma_writel(pd, STS2, sts2);
718 759
719 return ret; 760 return ret0 | ret2;
720} 761}
721 762
722#ifdef CONFIG_PM 763#ifdef CONFIG_PM