Commit e65f3a58 authored by Tomoya MORINAGA's avatar Tomoya MORINAGA Committed by Greg Kroah-Hartman

pch_dma: fix DMA issue(ch8-ch11)

commit c3d4913c upstream.

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	194f5f27
tree	c9d4903ea02b18939a4f390956a48be1a3734517
parent	60092d0b

This patch fixes the issue.
We can confirm PCH_DMA with I2S communications with ch8~ch11 works well.
Signed-off-by: default avatarTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
Signed-off-by: default avatarTomoya MORINAGA <tomoya.rohm@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent da980f0d
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
#define DMA_STATUS_MASK_BITS 0x3 #define DMA_STATUS_MASK_BITS 0x3
#define DMA_STATUS_SHIFT_BITS 16 #define DMA_STATUS_SHIFT_BITS 16
#define DMA_STATUS_IRQ(x) (0x1 << (x)) #define DMA_STATUS_IRQ(x) (0x1 << (x))
#define DMA_STATUS_ERR(x) (0x1 << ((x) + 8)) #define DMA_STATUS0_ERR(x) (0x1 << ((x) + 8))
#define DMA_STATUS2_ERR(x) (0x1 << (x))
#define DMA_DESC_WIDTH_SHIFT_BITS 12 #define DMA_DESC_WIDTH_SHIFT_BITS 12
#define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS) #define DMA_DESC_WIDTH_1_BYTE (0x3 << DMA_DESC_WIDTH_SHIFT_BITS)
...@@ -133,6 +134,7 @@ struct pch_dma { ...@@ -133,6 +134,7 @@ struct pch_dma {
#define PCH_DMA_CTL3 0x0C #define PCH_DMA_CTL3 0x0C
#define PCH_DMA_STS0 0x10 #define PCH_DMA_STS0 0x10
#define PCH_DMA_STS1 0x14 #define PCH_DMA_STS1 0x14
#define PCH_DMA_STS2 0x18
#define dma_readl(pd, name) \ #define dma_readl(pd, name) \
readl((pd)->membase + PCH_DMA_##name) readl((pd)->membase + PCH_DMA_##name)
...@@ -183,13 +185,19 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable) ...@@ -183,13 +185,19 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable)
{ {
struct pch_dma *pd = to_pd(chan->device); struct pch_dma *pd = to_pd(chan->device);
u32 val; u32 val;
int pos;
if (chan->chan_id < 8)
pos = chan->chan_id;
else
pos = chan->chan_id + 8;
val = dma_readl(pd, CTL2); val = dma_readl(pd, CTL2);
if (enable) if (enable)
val |= 0x1 << chan->chan_id; val |= 0x1 << pos;
else else
val &= ~(0x1 << chan->chan_id); val &= ~(0x1 << pos);
dma_writel(pd, CTL2, val); dma_writel(pd, CTL2, val);
...@@ -262,7 +270,7 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode) ...@@ -262,7 +270,7 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
chan->chan_id, val); chan->chan_id, val);
} }
static u32 pdc_get_status(struct pch_dma_chan *pd_chan) static u32 pdc_get_status0(struct pch_dma_chan *pd_chan)
{ {
struct pch_dma *pd = to_pd(pd_chan->chan.device); struct pch_dma *pd = to_pd(pd_chan->chan.device);
u32 val; u32 val;
...@@ -272,9 +280,27 @@ static u32 pdc_get_status(struct pch_dma_chan *pd_chan) ...@@ -272,9 +280,27 @@ static u32 pdc_get_status(struct pch_dma_chan *pd_chan)
DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id)); DMA_STATUS_BITS_PER_CH * pd_chan->chan.chan_id));
} }
static u32 pdc_get_status2(struct pch_dma_chan *pd_chan)
{
struct pch_dma *pd = to_pd(pd_chan->chan.device);
u32 val;
val = dma_readl(pd, STS2);
return DMA_STATUS_MASK_BITS & (val >> (DMA_STATUS_SHIFT_BITS +
DMA_STATUS_BITS_PER_CH * (pd_chan->chan.chan_id - 8)));
}
static bool pdc_is_idle(struct pch_dma_chan *pd_chan) static bool pdc_is_idle(struct pch_dma_chan *pd_chan)
{ {
if (pdc_get_status(pd_chan) == DMA_STATUS_IDLE) u32 sts;
if (pd_chan->chan.chan_id < 8)
sts = pdc_get_status0(pd_chan);
else
sts = pdc_get_status2(pd_chan);
if (sts == DMA_STATUS_IDLE)
return true; return true;
else else
return false; return false;
...@@ -693,30 +719,45 @@ static irqreturn_t pd_irq(int irq, void *devid) ...@@ -693,30 +719,45 @@ static irqreturn_t pd_irq(int irq, void *devid)
struct pch_dma *pd = (struct pch_dma *)devid; struct pch_dma *pd = (struct pch_dma *)devid;
struct pch_dma_chan *pd_chan; struct pch_dma_chan *pd_chan;
u32 sts0; u32 sts0;
u32 sts2;
int i; int i;
int ret = IRQ_NONE; int ret0 = IRQ_NONE;
int ret2 = IRQ_NONE;
sts0 = dma_readl(pd, STS0); sts0 = dma_readl(pd, STS0);
sts2 = dma_readl(pd, STS2);
dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0); dev_dbg(pd->dma.dev, "pd_irq sts0: %x\n", sts0);
for (i = 0; i < pd->dma.chancnt; i++) { for (i = 0; i < pd->dma.chancnt; i++) {
pd_chan = &pd->channels[i]; pd_chan = &pd->channels[i];
if (sts0 & DMA_STATUS_IRQ(i)) { if (i < 8) {
if (sts0 & DMA_STATUS_ERR(i)) if (sts0 & DMA_STATUS_IRQ(i)) {
set_bit(0, &pd_chan->err_status); if (sts0 & DMA_STATUS0_ERR(i))
set_bit(0, &pd_chan->err_status);
tasklet_schedule(&pd_chan->tasklet); tasklet_schedule(&pd_chan->tasklet);
ret = IRQ_HANDLED; ret0 = IRQ_HANDLED;
} }
} else {
if (sts2 & DMA_STATUS_IRQ(i - 8)) {
if (sts2 & DMA_STATUS2_ERR(i))
set_bit(0, &pd_chan->err_status);
tasklet_schedule(&pd_chan->tasklet);
ret2 = IRQ_HANDLED;
}
}
} }
/* clear interrupt bits in status register */ /* clear interrupt bits in status register */
dma_writel(pd, STS0, sts0); if (ret0)
dma_writel(pd, STS0, sts0);
if (ret2)
dma_writel(pd, STS2, sts2);
return ret; return ret0 | ret2;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment