X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-omap%2Fdma.c;h=cfb23d894a958af55e8fb40214f9aaf319d6ba7c;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=385b4d1cc055c90617fbabe0cf422d28b0a12a32;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c index 385b4d1cc..cfb23d894 100644 --- a/arch/arm/mach-omap/dma.c +++ b/arch/arm/mach-omap/dma.c @@ -118,7 +118,7 @@ void omap_set_dma_constant_fill(int lch, u32 color) 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; @@ -141,7 +141,7 @@ void omap_set_dma_transparent_copy(int lch, u32 color) 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(); } @@ -266,46 +266,78 @@ void omap_set_dma_dest_burst_mode(int lch, int burst_mode) 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; @@ -316,37 +348,34 @@ void omap_start_dma(int lch) 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) @@ -445,7 +474,7 @@ int omap_request_dma(int dev_id, const char *dev_name, 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); @@ -533,7 +562,6 @@ void omap_dma_unlink_lch (int lch_head, int lch_queue) } dma_chan[lch_head].next_lch = -1; - dma_chan[lch_queue].next_lch = -1; } @@ -713,7 +741,7 @@ static int __init omap_init_dma(void) 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", @@ -771,6 +799,8 @@ EXPORT_SYMBOL(omap_request_dma); 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);