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) commit194f5f2706
treec9d4903ea0
parent60092d0bde
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>
This commit is contained in:
parent
55922c9d1b
commit
c3d4913cd4
1 changed files with 55 additions and 14 deletions
|
@ -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 {
|
||||||
#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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue