📄 dma.c
字号:
/* * linux/arch/arm/plat-omap/dma.c * * Copyright (C) 2003 Nokia Corporation * Author: Juha Yrjölä <juha.yrjola@nokia.com> * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> * Graphics DMA and LCD DMA graphics tranformations * by Imre Deak <imre.deak@nokia.com> * OMAP2 support Copyright (C) 2004-2005 Texas Instruments, Inc. * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com> * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. * * Support functions for the OMAP internal DMA channels. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <asm/system.h>#include <asm/hardware.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/arch/tc.h>#define DEBUG_PRINTS#undef DEBUG_PRINTS#ifdef DEBUG_PRINTS#define debug_printk(x) printk x#else#define debug_printk(x)#endif#define OMAP_DMA_ACTIVE 0x01#define OMAP_DMA_CCR_EN (1 << 7)#define OMAP2_DMA_CSR_CLEAR_MASK 0xffe#define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec)static int enable_1510_mode = 0;struct omap_dma_lch { int next_lch; int dev_id; u16 saved_csr; u16 enabled_irqs; const char *dev_name; void (* callback)(int lch, u16 ch_status, void *data); void *data; long flags;};static int dma_chan_count;static spinlock_t dma_chan_lock;static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT];static const u8 omap1_dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = { INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3, INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7, INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10, INT_1610_DMA_CH11, INT_1610_DMA_CH12, INT_1610_DMA_CH13, INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD};#define REVISIT_24XX() printk(KERN_ERR "FIXME: no %s on 24xx\n", \ __FUNCTION__);#ifdef CONFIG_ARCH_OMAP15XX/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */int omap_dma_in_1510_mode(void){ return enable_1510_mode;}#else#define omap_dma_in_1510_mode() 0#endif#ifdef CONFIG_ARCH_OMAP1static inline int get_gdma_dev(int req){ u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; int shift = ((req - 1) % 5) * 6; return ((omap_readl(reg) >> shift) & 0x3f) + 1;}static inline void set_gdma_dev(int req, int dev){ u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; int shift = ((req - 1) % 5) * 6; u32 l; l = omap_readl(reg); l &= ~(0x3f << shift); l |= (dev - 1) << shift; omap_writel(l, reg);}#else#define set_gdma_dev(req, dev) do {} while (0)#endifstatic void clear_lch_regs(int lch){ int i; u32 lch_base = OMAP_DMA_BASE + lch * 0x40; for (i = 0; i < 0x2c; i += 2) omap_writew(0, lch_base + i);}void omap_set_dma_priority(int lch, int dst_port, int priority){ unsigned long reg; u32 l; if (cpu_class_is_omap1()) { switch (dst_port) { case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */ reg = OMAP_TC_OCPT1_PRIOR; break; case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */ reg = OMAP_TC_OCPT2_PRIOR; break; case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */ reg = OMAP_TC_EMIFF_PRIOR; break; case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */ reg = OMAP_TC_EMIFS_PRIOR; break; default: BUG(); return; } l = omap_readl(reg); l &= ~(0xf << 8); l |= (priority & 0xf) << 8; omap_writel(l, reg); } if (cpu_is_omap24xx()) { if (priority) OMAP_DMA_CCR_REG(lch) |= (1 << 6); else OMAP_DMA_CCR_REG(lch) &= ~(1 << 6); }}void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, int frame_count, int sync_mode, int dma_trigger, int src_or_dst_synch){ OMAP_DMA_CSDP_REG(lch) &= ~0x03; OMAP_DMA_CSDP_REG(lch) |= data_type; if (cpu_class_is_omap1()) { OMAP_DMA_CCR_REG(lch) &= ~(1 << 5); if (sync_mode == OMAP_DMA_SYNC_FRAME) OMAP_DMA_CCR_REG(lch) |= 1 << 5; OMAP1_DMA_CCR2_REG(lch) &= ~(1 << 2); if (sync_mode == OMAP_DMA_SYNC_BLOCK) OMAP1_DMA_CCR2_REG(lch) |= 1 << 2; } if (cpu_is_omap24xx() && dma_trigger) { u32 val = OMAP_DMA_CCR_REG(lch); val &= ~(3 << 19); if (dma_trigger > 63) val |= 1 << 20; if (dma_trigger > 31) val |= 1 << 19; val &= ~(0x1f); val |= (dma_trigger & 0x1f); if (sync_mode & OMAP_DMA_SYNC_FRAME) val |= 1 << 5; else val &= ~(1 << 5); if (sync_mode & OMAP_DMA_SYNC_BLOCK) val |= 1 << 18; else val &= ~(1 << 18); if (src_or_dst_synch) val |= 1 << 24; /* source synch */ else val &= ~(1 << 24); /* dest synch */ OMAP_DMA_CCR_REG(lch) = val; } OMAP_DMA_CEN_REG(lch) = elem_count; OMAP_DMA_CFN_REG(lch) = frame_count;}void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color){ u16 w; BUG_ON(omap_dma_in_1510_mode()); if (cpu_is_omap24xx()) { REVISIT_24XX(); return; } w = OMAP1_DMA_CCR2_REG(lch) & ~0x03; switch (mode) { case OMAP_DMA_CONSTANT_FILL: w |= 0x01; break; case OMAP_DMA_TRANSPARENT_COPY: w |= 0x02; break; case OMAP_DMA_COLOR_DIS: break; default: BUG(); } OMAP1_DMA_CCR2_REG(lch) = w; w = OMAP1_DMA_LCH_CTRL_REG(lch) & ~0x0f; /* Default is channel type 2D */ if (mode) { OMAP1_DMA_COLOR_L_REG(lch) = (u16)color; OMAP1_DMA_COLOR_U_REG(lch) = (u16)(color >> 16); w |= 1; /* Channel type G */ } OMAP1_DMA_LCH_CTRL_REG(lch) = w;}void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode){ if (cpu_is_omap24xx()) { OMAP_DMA_CSDP_REG(lch) &= ~(0x3 << 16); OMAP_DMA_CSDP_REG(lch) |= (mode << 16); }}/* Note that src_port is only for omap1 */void omap_set_dma_src_params(int lch, int src_port, int src_amode, unsigned long src_start, int src_ei, int src_fi){ if (cpu_class_is_omap1()) { OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 2); OMAP_DMA_CSDP_REG(lch) |= src_port << 2; } OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 12); OMAP_DMA_CCR_REG(lch) |= src_amode << 12; if (cpu_class_is_omap1()) { OMAP1_DMA_CSSA_U_REG(lch) = src_start >> 16; OMAP1_DMA_CSSA_L_REG(lch) = src_start; } if (cpu_is_omap24xx()) OMAP2_DMA_CSSA_REG(lch) = src_start; OMAP_DMA_CSEI_REG(lch) = src_ei; OMAP_DMA_CSFI_REG(lch) = src_fi;}void omap_set_dma_params(int lch, struct omap_dma_channel_params * params){ omap_set_dma_transfer_params(lch, params->data_type, params->elem_count, params->frame_count, params->sync_mode, params->trigger, params->src_or_dst_synch); omap_set_dma_src_params(lch, params->src_port, params->src_amode, params->src_start, params->src_ei, params->src_fi); omap_set_dma_dest_params(lch, params->dst_port, params->dst_amode, params->dst_start, params->dst_ei, params->dst_fi);}void omap_set_dma_src_index(int lch, int eidx, int fidx){ if (cpu_is_omap24xx()) { REVISIT_24XX(); return; } OMAP_DMA_CSEI_REG(lch) = eidx; OMAP_DMA_CSFI_REG(lch) = fidx;}void omap_set_dma_src_data_pack(int lch, int enable){ OMAP_DMA_CSDP_REG(lch) &= ~(1 << 6); if (enable) OMAP_DMA_CSDP_REG(lch) |= (1 << 6);}void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode){ unsigned int burst = 0; OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 7); switch (burst_mode) { case OMAP_DMA_DATA_BURST_DIS: break; case OMAP_DMA_DATA_BURST_4: if (cpu_is_omap24xx()) burst = 0x1; else burst = 0x2; break; case OMAP_DMA_DATA_BURST_8: if (cpu_is_omap24xx()) { burst = 0x2; break; } /* not supported by current hardware on OMAP1 * w |= (0x03 << 7); * fall through */ case OMAP_DMA_DATA_BURST_16: if (cpu_is_omap24xx()) { burst = 0x3; break; } /* OMAP1 don't support burst 16 * fall through */ default: BUG(); } OMAP_DMA_CSDP_REG(lch) |= (burst << 7);}/* Note that dest_port is only for OMAP1 */void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, unsigned long dest_start, int dst_ei, int dst_fi){ if (cpu_class_is_omap1()) { OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 9); OMAP_DMA_CSDP_REG(lch) |= dest_port << 9; } OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 14); OMAP_DMA_CCR_REG(lch) |= dest_amode << 14; if (cpu_class_is_omap1()) { OMAP1_DMA_CDSA_U_REG(lch) = dest_start >> 16; OMAP1_DMA_CDSA_L_REG(lch) = dest_start; } if (cpu_is_omap24xx()) OMAP2_DMA_CDSA_REG(lch) = dest_start; OMAP_DMA_CDEI_REG(lch) = dst_ei; OMAP_DMA_CDFI_REG(lch) = dst_fi;}void omap_set_dma_dest_index(int lch, int eidx, int fidx){ if (cpu_is_omap24xx()) { REVISIT_24XX(); return; } OMAP_DMA_CDEI_REG(lch) = eidx; OMAP_DMA_CDFI_REG(lch) = fidx;}void omap_set_dma_dest_data_pack(int lch, int enable){ OMAP_DMA_CSDP_REG(lch) &= ~(1 << 13); if (enable) OMAP_DMA_CSDP_REG(lch) |= 1 << 13;}void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode){ unsigned int burst = 0; OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 14); switch (burst_mode) { case OMAP_DMA_DATA_BURST_DIS: break; case OMAP_DMA_DATA_BURST_4: if (cpu_is_omap24xx()) burst = 0x1; else burst = 0x2; break; case OMAP_DMA_DATA_BURST_8: if (cpu_is_omap24xx()) burst = 0x2; else burst = 0x3; break; case OMAP_DMA_DATA_BURST_16: if (cpu_is_omap24xx()) { burst = 0x3; break; } /* OMAP1 don't support burst 16 * fall through */ default: printk(KERN_ERR "Invalid DMA burst mode\n"); BUG(); return; } OMAP_DMA_CSDP_REG(lch) |= (burst << 14);}static inline void omap_enable_channel_irq(int lch){ u32 status; /* Clear CSR */ if (cpu_class_is_omap1()) status = OMAP_DMA_CSR_REG(lch); else if (cpu_is_omap24xx()) OMAP_DMA_CSR_REG(lch) = OMAP2_DMA_CSR_CLEAR_MASK; /* Enable some nice interrupts. */ OMAP_DMA_CICR_REG(lch) = dma_chan[lch].enabled_irqs; dma_chan[lch].flags |= OMAP_DMA_ACTIVE;}static void omap_disable_channel_irq(int lch){ if (cpu_is_omap24xx()) OMAP_DMA_CICR_REG(lch) = 0;}void omap_enable_dma_irq(int lch, u16 bits){ dma_chan[lch].enabled_irqs |= bits;}void omap_disable_dma_irq(int lch, u16 bits){ dma_chan[lch].enabled_irqs &= ~bits;}static inline void enable_lnk(int lch){ if (cpu_class_is_omap1()) OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 14); /* Set the ENABLE_LNK bits */ if (dma_chan[lch].next_lch != -1) OMAP_DMA_CLNK_CTRL_REG(lch) = dma_chan[lch].next_lch | (1 << 15);}static inline void disable_lnk(int lch){ /* Disable interrupts */ if (cpu_class_is_omap1()) { OMAP_DMA_CICR_REG(lch) = 0; /* Set the STOP_LNK bit */ OMAP_DMA_CLNK_CTRL_REG(lch) |= 1 << 14; } if (cpu_is_omap24xx()) { omap_disable_channel_irq(lch); /* Clear the ENABLE_LNK bit */ OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 15); } dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;}static inline void omap2_enable_irq_lch(int lch){ u32 val; if (!cpu_is_omap24xx()) return; val = omap_readl(OMAP_DMA4_IRQENABLE_L0); val |= 1 << lch; omap_writel(val, OMAP_DMA4_IRQENABLE_L0);}int omap_request_dma(int dev_id, const char *dev_name, void (* callback)(int lch, u16 ch_status, void *data),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -