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

📄 dma-omap24xx.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * linux/arch/arm/mach-omap2/dma-omap24xx.c *  * Support functions for the OMAP2 internal DMA channels. * * Copyright (C) 2004 Texas Instruments, Inc.  * * Copied from: * linux/arch/arm/omap/dma.c * Copyright (C) 2003 Nokia Corporation *  * This package 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.  *  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.  */#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 <asm/system.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/dma.h>#include <asm/io.h>/* enable this option to run the dma tests *///#define DMA_TEST#undef DMA_TEST#define OMAP_DMA4_CCR_EN         (1 << 7)//#define DEBUG_PRINTS#undef DEBUG_PRINTS#ifdef DEBUG_PRINTS#define debug_printk(x) printk x#else#define	debug_printk(x)#endifenum { READY, QUEUED, RUNNING };enum { DMA_CH_ALLOC_DONE, DMA_CH_PARAMS_SET_DONE, DMA_CH_STARTED, DMA_CH_QUEUED,	DMA_CH_DONE, DMA_CH_PAUSED, DMA_CH_LINK_ENABLED};typedef struct omap_dma_lch_t {	int dev_id;	int reserved;	const char *dev_name;	void (*callback) (int lch, u16 ch_status, void *data);	void *data;	int next_channel;	int status;	int params_set;	lch_chain *mychain;	int enabled_irqs;} omap_dma_lch;static int dma_chan_count;static spinlock_t dma_chan_lock;static omap_dma_lch dma_chan[OMAP24XX_LOGICAL_DMA_CH_COUNT];static void clear_lch_regs(int lch){	int i;	u32 lch_base = OMAP_DMA4_BASE + lch * 0x60 + 0x80;	//printk(KERN_INFO "\n lch_base = %x", lch_base);	for (i = 0; i < 0x44; i += 4)		writel(0, lch_base + i);}/*dma_trigger - hardware trigger number for hardware sychronized channel */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){	u32 w;	int ch = lch;	w = readl(OMAP_DMA4_CSDP_REG(ch));	w &= ~0x03;	w |= data_type;	writel(w, OMAP_DMA4_CSDP_REG(ch));	if (dma_trigger) {		w = readl(OMAP_DMA4_CCR_REG(ch));		if (dma_trigger > 63)			w |= 1 << 20;		if (dma_trigger > 31)			w |= 1 << 19;		w |= (dma_trigger & 0x1f);		if (sync_mode & 0x1)			w |= 1 << 18;		if (sync_mode & 0x2)			w |= 1 << 5;		if (src_or_dst_synch)			w |= 1 << 24;	/* source synch */		else			w &= ~(1 << 24);	/* dest synch */		writel(w, OMAP_DMA4_CCR_REG(ch));	}	writel(elem_count, OMAP_DMA4_CEN_REG(ch));	writel(frame_count, OMAP_DMA4_CFN_REG(ch));}void omap_set_dma_src_params(int lch, int src_amode,			     int src_start, int src_ei, int src_fi){	u32 w;	w = readl(OMAP_DMA4_CCR_REG(lch));	w &= ~(0x03 << 12);	w |= src_amode << 12;	writel(w, OMAP_DMA4_CCR_REG(lch));	writel(src_start, OMAP_DMA4_CSSA_REG(lch));	writel(src_ei, OMAP_DMA4_CSEI_REG(lch));	writel(src_fi, OMAP_DMA4_CSFI_REG(lch));}void omap_set_dma_dest_params(int lch, int dest_amode,			      int dest_start, int dst_ei, int dst_fi){	u32 w;	w = readl(OMAP_DMA4_CCR_REG(lch));	w &= ~(0x03 << 14);	w |= dest_amode << 14;	writel(w, OMAP_DMA4_CCR_REG(lch));	writel(dest_start, OMAP_DMA4_CDSA_REG(lch));	writel(dst_ei, OMAP_DMA4_CDEI_REG(lch));	writel(dst_fi, OMAP_DMA4_CDFI_REG(lch));}void omap_set_dma_params(int lch, 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_amode, params.src_start,				params.src_ei, params.src_fi);	omap_set_dma_dest_params(lch, params.dst_amode, params.dst_start,				 params.dst_ei, params.dst_fi);	dma_chan[lch].params_set = 1;}int omap_set_dma_params_chain(lch_chain * chain, dma_channel_params params){	int lch;	unsigned long flags;	spin_lock_irqsave(&dma_chan_lock, flags);	//debug	debug_printk((KERN_INFO "\n omap_set_dma_params_chain : "));	/* queue full */	if (dma_chan[chain->queue_tail].next_channel == chain->queue_head) {		debug_printk("\n error : queue full");		return -EAGAIN;	}	if (!chain->started)		lch = chain->queue_head;	else		lch = dma_chan[chain->queue_tail].next_channel;	//debug	debug_printk((KERN_INFO		      "\n chain = %x , dma_chan[lch].params_started = %d  channel = %d ",		      chain, dma_chan[lch].params_set, lch));	/* omap_set_dma_params_chain and omap_start_dma_chain should be called in lock steps */	if (dma_chan[lch].params_set == 1) {		printk(KERN_INFO		       "\n omap_set_dma_params_chain and omap_start_dma_chain should be called in lock steps  ch = %d ",		       lch);		return -EAGAIN;	}	omap_set_dma_params(lch, params);	spin_unlock_irqrestore(&dma_chan_lock, flags);	return 0;}int omap_start_dma(int lch){	u32 w;	/* start the dma enable the lch */	/* and return success */	w = readl(OMAP_DMA4_CCR_REG(lch));	w |= OMAP_DMA4_CCR_EN;	writel(w, OMAP_DMA4_CCR_REG(lch));	return 0;}int omap_get_dma_pos_dst(int lch){	return (readl(OMAP_DMA4_CDAC_REG(lch)));}int omap_get_dma_pos_src(int lch){	return (readl(OMAP_DMA4_CSAC_REG(lch)));}int omap_start_dma_chain(lch_chain * chain){	int lch;	unsigned long flags;	spin_lock_irqsave(&dma_chan_lock, flags);	//debug	debug_printk((KERN_INFO "\n omap_start_dma_chain"));	if (!chain->started) {	/* dma chain not started */		//debug		debug_printk((KERN_INFO "\n chain started "));		lch = chain->queue_head;		if (!dma_chan[lch].params_set) {			printk(KERN_INFO			       "\n error : trying to start/queue channel %d without setting tha parameters",			       lch);			return -1;	//error condition		}		/* start the dma enable the lch */		/* and return success */		omap_start_dma(lch);		chain->started = 1;	} else {		/* enable the chain for the channel in queue */		//debug		debug_printk(("\n channel chain queued"));		lch = dma_chan[chain->queue_tail].next_channel;;		if (!dma_chan[lch].params_set) {			printk(KERN_INFO			       "\n error : trying to start/queue channel %d without setting tha parameters",			       lch);			return -1;	//error condition		}		enable_chain(chain->queue_tail, lch);	/* next dma transfer queued */		chain->queue_tail = lch;	}	chain->queued = chain->queued + 1;	debug_printk(("\n startdma : chain->head = %d , chain -> queue->tail = %d queued = %d", chain->queue_head, chain->queue_tail, chain->queued));	spin_unlock_irqrestore(&dma_chan_lock, flags);	return 0;}/* Chain functions *//* START */void setup_chain(int lch1, int lch2){	writel(lch2, OMAP_DMA4_CLNK_CTRL_REG(lch1));}void remove_chain(int lch){	writel(0x0, OMAP_DMA4_CLNK_CTRL_REG(lch));}void enable_chain(int lch1, int lch2){				/* next dma transfer queued */	int w;	w = readl(OMAP_DMA4_CLNK_CTRL_REG(lch1));	if ((w & 0x1f) != lch2)		printk(KERN_INFO		       "\n error in linking channel, channels should be linked upfront, it is only enabled here");	w |= (1 << 15);	writel(w, OMAP_DMA4_CLNK_CTRL_REG(lch1));}void disable_chain(int lch){	int w;	w = readl(OMAP_DMA4_CLNK_CTRL_REG(lch));	w &= ~(1 << 15);	writel(w, OMAP_DMA4_CLNK_CTRL_REG(lch));}/* Chain functions *//* END */void omap_stop_dma(int lch){	u32 w;	w = readl(OMAP_DMA4_CCR_REG(lch));	w &= ~OMAP_DMA4_CCR_EN;	writel(w, OMAP_DMA4_CCR_REG(lch));}void omap_stop_dma_chain(lch_chain * chain){	int lch;	int i;	lch = chain->queue_head;	omap_stop_dma(lch);	chain->started = 0;	/* chain stopped */	/* traverse through all the chained logical channels and disable them */	for (i = 0; i < chain->num_channels; i++) {		omap_stop_dma(lch);		disable_chain(lch);		lch = dma_chan[lch].next_channel;	}}void omap_enable_dma_irq(int lch){	u32 w;	w = readl(OMAP_DMA4_CICR_REG(lch));	w |= dma_chan[lch].enabled_irqs;	writel(w, OMAP_DMA4_CICR_REG(lch));}void omap_disable_dma_irq(int lch){	u32 w;	w = readl(OMAP_DMA4_CICR_REG(lch));	w &= dma_chan[lch].enabled_irqs;	writel(w, OMAP_DMA4_CICR_REG(lch));}static int dma_handle_ch(int ch){	u32 w;	u32 csr_reg;	w = readl(OMAP_DMA4_CSR_REG(ch));	csr_reg = w;	debug_printk((KERN_INFO "\n interrupt recieved = %x", w));	if (!w)		return 0;	if (unlikely(dma_chan[ch].dev_id == -1))		return 0;	if (unlikely(w & OMAP_DMA_TOUT_IRQ))		printk(KERN_INFO "DMA timeout with device %d\n",		       dma_chan[ch].dev_id);	if (unlikely(w & OMAP_DMA_DROP_IRQ))		printk(KERN_INFO		       "DMA synchronization event drop occurred with device %d\n",		       dma_chan[ch].dev_id);	/* if transfer completed for a channel , update the data structures */	/* this interrupt is required by the framework */	if (w & OMAP_DMA_BLOCK_IRQ) {		lch_chain *chain = dma_chan[ch].mychain;		debug_printk((KERN_INFO			      "\n got end of block interrupt for ch = %d ",			      ch));		if (chain) {			if (chain->queue_head != ch)				printk(KERN_INFO "\n error in queueing logic QH=%d CH=%d",chain->queue_head,ch);	// should never be true			chain->queued = chain->queued - 1;			if (chain->queued <= 0) {				debug_printk				    ("\n queueing underrun : restarting the chain");				chain->queue_head = ch;				chain->queue_tail = ch;				chain->started = 0;				omap_stop_dma(ch);				//clear_lch_regs(ch);			} else {				chain->queue_head = dma_chan[ch].next_channel;			}			dma_chan[ch].params_set = 0;			debug_printk(("\n end_dma : chain = %x chain->head = %d , chain -> queue->tail = %d queued = %d", chain, chain->queue_head, chain->queue_tail, chain->queued));			//chain->queued = chain->queued - 1;		}	}	w = writel(0x20, OMAP_DMA4_CSR_REG(ch));	w = readl(OMAP_DMA4_IRQSTATUS_L0);	w = 1 << (ch);		/* ch in this function is from 0-31 while in register it is 1-32 */	writel(w, OMAP_DMA4_IRQSTATUS_L0);#ifdef DMA_TEST	/* debug */	w = readl(OMAP_DMA4_IRQSTATUS_L0);	debug_printk((KERN_INFO "IRQSTATUS_L0 = %x", w));	w = readl(OMAP_DMA4_CSR_REG(ch));	debug_printk((KERN_INFO "CSR_REG = %x", w));	w = readl(OMAP_DMA4_CICR_REG(ch));	debug_printk((KERN_INFO "CICR_REG = %x", w));#endif	if (likely(dma_chan[ch].callback != NULL))		dma_chan[ch].callback(ch, w, dma_chan[ch].data);	return 0;}static irqreturn_t omap24xx_dma4_irq_demux(int irq, void *dev_id,					   struct pt_regs *regs){	u32 w;	int i;	w = readl(OMAP_DMA4_IRQSTATUS_L0);	debug_printk((KERN_INFO "\n demux IRQSTATUS_L0 = %x", w));	for (i = 1; i <= OMAP24XX_LOGICAL_DMA_CH_COUNT; i++) {		int val = w & (1 << (i - 1));		if (val)			dma_handle_ch(i - 1);	/* STATUS register count is from 1-32 while our is 0-31 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -