diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/pch_dma.c | 69 |
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 | ||
265 | static u32 pdc_get_status(struct pch_dma_chan *pd_chan) | 273 | static 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 | ||
283 | static 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 | |||
275 | static bool pdc_is_idle(struct pch_dma_chan *pd_chan) | 293 | static 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 |