static int dma_lch_count;
static int dma_chan_count;
+static int omap_dma_reserve_channels;
static spinlock_t dma_chan_lock;
static struct omap_dma_lch *dma_chan;
{
unsigned long flags;
- spin_lock_irqsave(&dma_chan_lock, flags);
if (dma_chan[lch].dev_id == -1) {
pr_err("omap_dma: trying to free unallocated DMA channel %d\n",
lch);
- spin_unlock_irqrestore(&dma_chan_lock, flags);
return;
}
- dma_chan[lch].dev_id = -1;
- dma_chan[lch].next_lch = -1;
- dma_chan[lch].callback = NULL;
- spin_unlock_irqrestore(&dma_chan_lock, flags);
-
if (cpu_class_is_omap1()) {
/* Disable all DMA interrupts for the channel. */
dma_write(0, CICR(lch));
dma_write(0, CCR(lch));
omap_clear_dma(lch);
}
+
+ spin_lock_irqsave(&dma_chan_lock, flags);
+ dma_chan[lch].dev_id = -1;
+ dma_chan[lch].next_lch = -1;
+ dma_chan[lch].callback = NULL;
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
}
EXPORT_SYMBOL(omap_free_dma);
/* STATUS register count is from 1-32 while our is 0-31 */
static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
{
- u32 val;
+ u32 val, enable_reg;
int i;
val = dma_read(IRQSTATUS_L0);
printk(KERN_WARNING "Spurious DMA IRQ\n");
return IRQ_HANDLED;
}
+ enable_reg = dma_read(IRQENABLE_L0);
+ val &= enable_reg; /* Dispatch only relevant interrupts */
for (i = 0; i < dma_lch_count && val != 0; i++) {
if (val & 1)
omap2_dma_handle_ch(i);
return -ENODEV;
}
+ if (cpu_class_is_omap2() && omap_dma_reserve_channels
+ && (omap_dma_reserve_channels <= dma_lch_count))
+ dma_lch_count = omap_dma_reserve_channels;
+
dma_chan = kzalloc(sizeof(struct omap_dma_lch) * dma_lch_count,
GFP_KERNEL);
if (!dma_chan)
u8 revision = dma_read(REVISION) & 0xff;
printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
revision >> 4, revision & 0xf);
- dma_chan_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
+ dma_chan_count = dma_lch_count;
} else {
dma_chan_count = 0;
return 0;
if (cpu_class_is_omap2())
setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq);
+ /* Enable smartidle idlemodes and autoidle */
+ if (cpu_is_omap34xx()) {
+ u32 v = dma_read(OCP_SYSCONFIG);
+ v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
+ DMA_SYSCONFIG_SIDLEMODE_MASK |
+ DMA_SYSCONFIG_AUTOIDLE);
+ v |= (DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+ DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+ DMA_SYSCONFIG_AUTOIDLE);
+ dma_write(v , OCP_SYSCONFIG);
+ }
+
+
/* FIXME: Update LCD DMA to work on 24xx */
if (cpu_class_is_omap1()) {
r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
arch_initcall(omap_init_dma);
+/*
+ * Reserve the omap SDMA channels using cmdline bootarg
+ * "omap_dma_reserve_ch=". The valid range is 1 to 32
+ */
+static int __init omap_dma_cmdline_reserve_ch(char *str)
+{
+ if (get_option(&str, &omap_dma_reserve_channels) != 1)
+ omap_dma_reserve_channels = 0;
+ return 1;
+}
+
+__setup("omap_dma_reserve_ch=", omap_dma_cmdline_reserve_ch);
+