⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -