u16 w;
#ifdef CONFIG_DEBUG_KERNEL
- if (omap_dma_in_1510_mode) {
+ if (omap_dma_in_1510_mode()) {
printk(KERN_ERR "OMAP DMA constant fill not available in 1510 mode.");
BUG();
return;
u16 w;
#ifdef CONFIG_DEBUG_KERNEL
- if (omap_dma_in_1510_mode) {
+ if (omap_dma_in_1510_mode()) {
printk(KERN_ERR "OMAP DMA transparent copy not available in 1510 mode.");
BUG();
}
omap_writew(w, OMAP_DMA_CSDP(lch));
}
-void omap_start_dma(int lch)
+static inline void init_intr(int lch)
{
u16 w;
- if (!omap_dma_in_1510_mode()) {
- int next_lch;
-
- next_lch = dma_chan[lch].next_lch;
-
- /* Enable the queue, if needed so. */
- if (next_lch != -1) {
- /* Clear the STOP_LNK bits */
- w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
- w &= ~(1 << 14);
- omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
- w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch));
- w &= ~(1 << 14);
- omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch));
-
- /* And set the ENABLE_LNK bits */
- omap_writew(next_lch | (1 << 15),
- OMAP_DMA_CLNK_CTRL(lch));
- /* The loop case */
- if (dma_chan[next_lch].next_lch == lch)
- omap_writew(lch | (1 << 15),
- OMAP_DMA_CLNK_CTRL(next_lch));
-
- /* Read CSR to make sure it's cleared. */
- w = omap_readw(OMAP_DMA_CSR(next_lch));
- /* Enable some nice interrupts. */
- omap_writew(dma_chan[next_lch].enabled_irqs,
- OMAP_DMA_CICR(next_lch));
- dma_chan[next_lch].flags |= OMAP_DMA_ACTIVE;
- }
- }
-
/* Read CSR to make sure it's cleared. */
w = omap_readw(OMAP_DMA_CSR(lch));
/* Enable some nice interrupts. */
omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch));
+ dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+
+static inline void enable_lnk(int lch)
+{
+ u16 w;
+
+ /* Clear the STOP_LNK bits */
+ w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+ w &= ~(1 << 14);
+ omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+ /* And set the ENABLE_LNK bits */
+ if (dma_chan[lch].next_lch != -1)
+ omap_writew(dma_chan[lch].next_lch | (1 << 15),
+ OMAP_DMA_CLNK_CTRL(lch));
+}
+
+static inline void disable_lnk(int lch)
+{
+ u16 w;
+
+ /* Disable interrupts */
+ omap_writew(0, OMAP_DMA_CICR(lch));
+
+ /* Set the STOP_LNK bit */
+ w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+ w |= (1 << 14);
+ w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+ dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
+void omap_start_dma(int lch)
+{
+ u16 w;
+
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch;
+ char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+ dma_chan_link_map[lch] = 1;
+ /* Set the link register of the first channel */
+ enable_lnk(lch);
+
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ cur_lch = dma_chan[lch].next_lch;
+ do {
+ next_lch = dma_chan[cur_lch].next_lch;
+
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
+
+ enable_lnk(cur_lch);
+ init_intr(cur_lch);
+
+ cur_lch = next_lch;
+ } while (next_lch != -1);
+ }
+
+ init_intr(lch);
w = omap_readw(OMAP_DMA_CCR(lch));
w |= OMAP_DMA_CCR_EN;
void omap_stop_dma(int lch)
{
u16 w;
- int next_lch;
- /* Disable all interrupts on the channel */
- omap_writew(0, OMAP_DMA_CICR(lch));
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch = lch;
+ char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
- if (omap_dma_in_1510_mode()) {
- w = omap_readw(OMAP_DMA_CCR(lch));
- w &= ~OMAP_DMA_CCR_EN;
- omap_writew(w, OMAP_DMA_CCR(lch));
- dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
- return;
- }
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ do {
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
- next_lch = dma_chan[lch].next_lch;
+ disable_lnk(cur_lch);
- /*
- * According to thw HW spec, enabling the STOP_LNK bit
- * resets the CCR_EN bit at the same time.
- */
- w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
- w |= (1 << 14);
- w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
- dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+ next_lch = dma_chan[cur_lch].next_lch;
+ cur_lch = next_lch;
+ } while (next_lch != -1);
- if (next_lch != -1) {
- omap_writew(0, OMAP_DMA_CICR(next_lch));
- w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch));
- w |= (1 << 14);
- w = omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch));
- dma_chan[next_lch].flags &= ~OMAP_DMA_ACTIVE;
+ return;
}
+ /* Disable all interrupts on the channel */
+ omap_writew(0, OMAP_DMA_CICR(lch));
+
+ w = omap_readw(OMAP_DMA_CCR(lch));
+ w &= ~OMAP_DMA_CCR_EN;
+ omap_writew(w, OMAP_DMA_CCR(lch));
+ dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
}
void omap_enable_dma_irq(int lch, u16 bits)
chan->data = data;
chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
- if (cpu_is_omap1610() || cpu_is_omap5912()) {
+ if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) {
/* If the sync device is set, configure it dynamically. */
if (dev_id != 0) {
set_gdma_dev(free_ch + 1, dev_id);
}
dma_chan[lch_head].next_lch = -1;
- dma_chan[lch_queue].next_lch = -1;
}
printk(KERN_INFO "DMA support for OMAP1510 initialized\n");
dma_chan_count = 9;
enable_1510_mode = 1;
- } else if (cpu_is_omap1610() || cpu_is_omap5912()) {
+ } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) {
printk(KERN_INFO "OMAP DMA hardware version %d\n",
omap_readw(OMAP_DMA_HW_ID));
printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
EXPORT_SYMBOL(omap_free_dma);
EXPORT_SYMBOL(omap_start_dma);
EXPORT_SYMBOL(omap_stop_dma);
+EXPORT_SYMBOL(omap_enable_dma_irq);
+EXPORT_SYMBOL(omap_disable_dma_irq);
EXPORT_SYMBOL(omap_set_dma_transfer_params);
EXPORT_SYMBOL(omap_set_dma_constant_fill);