diff options
Diffstat (limited to 'arch/arm/plat-omap/dma.c')
-rw-r--r-- | arch/arm/plat-omap/dma.c | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 68eaae3..be4ce07 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -32,9 +32,9 @@ #include <asm/system.h> #include <mach/hardware.h> -#include <mach/dma.h> +#include <plat/dma.h> -#include <mach/tc.h> +#include <plat/tc.h> #undef DEBUG @@ -54,6 +54,12 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED }; static int enable_1510_mode; +static struct omap_dma_global_context_registers { + u32 dma_irqenable_l0; + u32 dma_ocp_sysconfig; + u32 dma_gcr; +} omap_dma_global_context; + struct omap_dma_lch { int next_lch; int dev_id; @@ -2355,44 +2361,83 @@ void omap_stop_lcd_dma(void) } EXPORT_SYMBOL(omap_stop_lcd_dma); +void omap_dma_global_context_save(void) +{ + omap_dma_global_context.dma_irqenable_l0 = + dma_read(IRQENABLE_L0); + omap_dma_global_context.dma_ocp_sysconfig = + dma_read(OCP_SYSCONFIG); + omap_dma_global_context.dma_gcr = dma_read(GCR); +} + +void omap_dma_global_context_restore(void) +{ + int ch; + + dma_write(omap_dma_global_context.dma_gcr, GCR); + dma_write(omap_dma_global_context.dma_ocp_sysconfig, + OCP_SYSCONFIG); + dma_write(omap_dma_global_context.dma_irqenable_l0, + IRQENABLE_L0); + + /* + * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared + * after secure sram context save and restore. Hence we need to + * manually clear those IRQs to avoid spurious interrupts. This + * affects only secure devices. + */ + if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) + dma_write(0x3 , IRQSTATUS_L0); + + for (ch = 0; ch < dma_chan_count; ch++) + if (dma_chan[ch].dev_id != -1) + omap_clear_dma(ch); +} + /*----------------------------------------------------------------------------*/ static int __init omap_init_dma(void) { + unsigned long base; int ch, r; if (cpu_class_is_omap1()) { - omap_dma_base = OMAP1_IO_ADDRESS(OMAP1_DMA_BASE); + base = OMAP1_DMA_BASE; dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT; } else if (cpu_is_omap24xx()) { - omap_dma_base = OMAP2_IO_ADDRESS(OMAP24XX_DMA4_BASE); + base = OMAP24XX_DMA4_BASE; dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT; } else if (cpu_is_omap34xx()) { - omap_dma_base = OMAP2_IO_ADDRESS(OMAP34XX_DMA4_BASE); + base = OMAP34XX_DMA4_BASE; dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT; } else if (cpu_is_omap44xx()) { - omap_dma_base = OMAP2_IO_ADDRESS(OMAP44XX_DMA4_BASE); + base = OMAP44XX_DMA4_BASE; dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT; } else { pr_err("DMA init failed for unsupported omap\n"); return -ENODEV; } + omap_dma_base = ioremap(base, SZ_4K); + BUG_ON(!omap_dma_base); + 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) - return -ENOMEM; + if (!dma_chan) { + r = -ENOMEM; + goto out_unmap; + } if (cpu_class_is_omap2()) { dma_linked_lch = kzalloc(sizeof(struct dma_link_info) * dma_lch_count, GFP_KERNEL); if (!dma_linked_lch) { - kfree(dma_chan); - return -ENOMEM; + r = -ENOMEM; + goto out_free; } } @@ -2466,7 +2511,7 @@ static int __init omap_init_dma(void) for (i = 0; i < ch; i++) free_irq(omap1_dma_irq[i], (void *) (i + 1)); - return r; + goto out_free; } } } @@ -2484,8 +2529,8 @@ static int __init omap_init_dma(void) setup_irq(irq, &omap24xx_dma_irq); } - /* Enable smartidle idlemodes and autoidle */ if (cpu_is_omap34xx()) { + /* Enable smartidle idlemodes and autoidle */ u32 v = dma_read(OCP_SYSCONFIG); v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK | DMA_SYSCONFIG_SIDLEMODE_MASK | @@ -2494,6 +2539,13 @@ static int __init omap_init_dma(void) DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) | DMA_SYSCONFIG_AUTOIDLE); dma_write(v , OCP_SYSCONFIG); + /* reserve dma channels 0 and 1 in high security devices */ + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + printk(KERN_INFO "Reserving DMA channels 0 and 1 for " + "HS ROM code\n"); + dma_chan[0].dev_id = 0; + dma_chan[1].dev_id = 1; + } } @@ -2508,11 +2560,19 @@ static int __init omap_init_dma(void) "(error %d)\n", r); for (i = 0; i < dma_chan_count; i++) free_irq(omap1_dma_irq[i], (void *) (i + 1)); - return r; + goto out_free; } } return 0; + +out_free: + kfree(dma_chan); + +out_unmap: + iounmap(omap_dma_base); + + return r; } arch_initcall(omap_init_dma); |