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

📄 dma.c

📁 自己正在开发的一个ARM9的操作系统。详细信息请访问www.another-prj.com
💻 C
字号:
/* *	ApOS (Another Project software for s3c2410) *	 *	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. *			 *						Copyright caiyuqing * *	this file define the functions of the DMA block *  	本文件实现了对DMA模块进行操作的函数 */#include "../include/s3c2410/s3c2410.h"#include "../include/s3c2410/dma.h"#include "../include/kernel/irq.h"extern irq_ptr irq_rotunie[32];/* *	DMA global object,any functions of the dma control is base it.  *	DMA全局对象,整个系统的DMA操作(初始化,设置等等)都是基于这个对象的 */struct dma_ctrl_object dma_ctrl_object;/* *	system can get the status of a dma opteration througth *	thease four global variable *	四个全局变量,通过他们系统可以知道dma操作是否已经完成 */char sys_dma0_done;char sys_dma1_done;char sys_dma2_done;char sys_dma3_done;/* *	irq for chanel0	 *	0号通道dma中断服务例程 */void dma0_irq(struct cpu_registers *regs);/* *	initialize the DMA object *	初始化 dma_ctrl_object 对象 */void dma_ctrl_obj_init(struct dma_ctrl_object *dco){	//0通道对象初始化	dco->chanel0.disrc	=&rDISRC0;	dco->chanel0.disrcc	=&rDISRCC0;	dco->chanel0.didst	=&rDIDST0;	dco->chanel0.didstc	=&rDIDSTC0;	dco->chanel0.dcon	=&rDCON0;	dco->chanel0.dstat	=&rDSTAT0;	dco->chanel0.dcsrc	=&rDCSRC0;	dco->chanel0.dcdst	=&rDCDST0;	dco->chanel0.dmasktrig	=&rDMASKTRIG0;	dco->chanel0.tc_opt	=1;	//1通道对象初始化	dco->chanel1.disrc	=&rDISRC1;	dco->chanel1.disrcc	=&rDISRCC1;	dco->chanel1.didst	=&rDIDST1;	dco->chanel1.didstc	=&rDIDSTC1;	dco->chanel1.dcon	=&rDCON1;	dco->chanel1.dstat	=&rDSTAT1;	dco->chanel1.dcsrc	=&rDCSRC1;	dco->chanel1.dcdst	=&rDCDST1;	dco->chanel1.dmasktrig	=&rDMASKTRIG1;	dco->chanel1.tc_opt	=1;		//2通道对象初始化	dco->chanel2.disrc	=&rDISRC2;	dco->chanel2.disrcc	=&rDISRCC2;	dco->chanel2.didst	=&rDIDST2;	dco->chanel2.didstc	=&rDIDSTC2;	dco->chanel2.dcon	=&rDCON2;	dco->chanel2.dstat	=&rDSTAT2;	dco->chanel2.dcsrc	=&rDCSRC2;	dco->chanel2.dcdst	=&rDCDST2;	dco->chanel2.dmasktrig	=&rDMASKTRIG2;	dco->chanel2.tc_opt	=1;		//3通道对象初始化	dco->chanel3.disrc	=&rDISRC3;	dco->chanel3.disrcc	=&rDISRCC3;	dco->chanel3.didst	=&rDIDST3;	dco->chanel3.didstc	=&rDIDSTC3;	dco->chanel3.dcon	=&rDCON3;	dco->chanel3.dstat	=&rDSTAT3;	dco->chanel3.dcsrc	=&rDCSRC3;	dco->chanel3.dcdst	=&rDCDST3;	dco->chanel3.dmasktrig	=&rDMASKTRIG3;	dco->chanel3.tc_opt	=1;	irq_rotunie[INT_DMA0]	=&dma0_irq;}/* *	Select one between Demand mode and Handshake mode. * */static void set_ack_mode(struct dma_chanel *dma_chanel,			char hs_mode){	*dma_chanel->dcon&=~(1<<DMD_HS_OFFSET);	*dma_chanel->dcon|=(hs_mode<<DMD_HS_OFFSET);}/* *	Select DREQ/DACK synchronization. * */static void set_sync_mode(struct dma_chanel *dma_chanel,				char sync_mode){	*dma_chanel->dcon&=~(1<<SYNC_OFFSET);	*dma_chanel->dcon|=(sync_mode<<SYNC_OFFSET);}/* *	Enable/Disable the interrupt setting for CURR_TC * */static void enable_int(struct dma_chanel *dma_chanel,			char int_enable){	*dma_chanel->dcon&=~(1<<INT_OFFSET);	*dma_chanel->dcon|=(int_enable<<INT_OFFSET);}/* *	Select the transfer size of an atomic transfer * */static void set_transfer_size(struct dma_chanel *dma_chanel,				char transfer_size){	(*dma_chanel->dcon)&=~(1<<TSZ_OFFSET);	(*dma_chanel->dcon)|=(transfer_size<<TSZ_OFFSET);}/* *	Select the service mode between Single service mode and Whole *	service mode. * */static void set_service_size(struct dma_chanel *dma_chanel,				char serve_mode){	*dma_chanel->dcon&=~(1<<SERVMODE_OFFSET);	*dma_chanel->dcon|=(serve_mode<<SERVMODE_OFFSET);}/* *	Select DMA request source for each DMA. * */static void set_hardware_src(struct dma_chanel *dma_chanel,				char hw_src_sel){	*dma_chanel->dcon&=~(0x7<<HWSRCSEL_OFFSET);	*dma_chanel->dcon|=(hw_src_sel<<HWSRCSEL_OFFSET);}/* *	Select the DMA source between software (S/W request mode) and *	hardware (H/W request mode). * */static void set_triger_src(struct dma_chanel *dma_chanel,				char sw_or_hw){	*dma_chanel->dcon&=~(1<<SWHW_SEL_OFFSET);	*dma_chanel->dcon|=(sw_or_hw<<SWHW_SEL_OFFSET);}/* *	Set the reload on/off option * */static void reload_enable(struct dma_chanel *dma_chanel,				char reload){	*dma_chanel->dcon&=~(1<<RELOAD_OFFSET);	*dma_chanel->dcon|=(reload<<RELOAD_OFFSET);}/* *	Data size to be transferred * */static void set_data_size(struct dma_chanel *dma_chanel,				char data_size){	*dma_chanel->dcon&=~(0x3<<DSZ_OFFSET);	*dma_chanel->dcon|=(data_size<<DSZ_OFFSET);}/* *	setup the DMA chanel. *	对dma通道的属性进行设置,比如设置触发模式,触发源 */int setup_dma_chanel(struct dma_option* opt){	char chanel=opt->ch;	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+chanel;			/*	 *	0号通道用于内存之间的数据传递	 *	2号通道用于sdi的数据传递	 */	if(chanel==0||chanel==2)		return -1;		*dma_chanel->disrcc=((opt->src_loc)<<LOC_OFFSET)|((opt->src_inc)<<INC_OFFSET);	*dma_chanel->didstc=((opt->dest_loc)<<LOC_OFFSET)|((opt->dest_inc)<<INC_OFFSET);	set_ack_mode(dma_chanel,opt->hs_mode);	set_sync_mode(dma_chanel,opt->sync_mode);	enable_int(dma_chanel,opt->int_enable);	set_transfer_size(dma_chanel,opt->transfer_size);	set_service_size(dma_chanel,opt->serve_mode);	set_hardware_src(dma_chanel,opt->hw_src_sel);	set_triger_src(dma_chanel,opt->sw_or_hw);	reload_enable(dma_chanel,opt->reload);	set_data_size(dma_chanel,opt->data_size);	irq_rotunie[INT_DMA0+chanel]=opt->interrupt_routine;	switch(opt->transfer_size)	{		case 0:			dma_chanel->tc_opt*=1;			break;		case 1:			dma_chanel->tc_opt*=4;			break;	}	switch(opt->data_size)	{		case 0:			dma_chanel->tc_opt*=1;			break;		case 1:			dma_chanel->tc_opt*=2;			break;		case 2:			dma_chanel->tc_opt*=4;			break;	}	return chanel;}/* *	get options of the DMA chanel ask . *	获得指定的DMA通道的属性 */void get_dma_option(int chanel,struct dma_option* opt){	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+chanel;	opt->src_loc		=((*dma_chanel->disrcc)>>LOC_OFFSET)&0x01;	opt->src_inc		=(*dma_chanel->disrcc)&0x01;	opt->dest_loc		=((*dma_chanel->didstc)>>LOC_OFFSET)&0x01;	opt->dest_inc		=(*dma_chanel->didstc)&0x01;	opt->hs_mode		=((*dma_chanel->dcon)>>DMD_HS_OFFSET)&0x01;	opt->sync_mode		=((*dma_chanel->dcon)>>SYNC_OFFSET)&0x01;	opt->int_enable		=((*dma_chanel->dcon)>>INT_OFFSET)&0x01;	opt->transfer_size	=((*dma_chanel->dcon)>>TSZ_OFFSET)&0x01;	opt->serve_mode		=((*dma_chanel->dcon)>>SERVMODE_OFFSET)&0x01;	opt->hw_src_sel		=((*dma_chanel->dcon)>>HWSRCSEL_OFFSET)&0x07;	opt->sw_or_hw		=((*dma_chanel->dcon)>>SWHW_SEL_OFFSET)&0x01;	opt->reload		=((*dma_chanel->dcon)>>RELOAD_OFFSET)&0x01;	opt->data_size		=((*dma_chanel->dcon)>>DSZ_OFFSET)&0x03;}/* *	very important,if an dma operation is trigger(except chanel 0), *	this function should be called.It deal the DMA operation. *	很重要的一个函数,这个函数是每个DMA通道(除0号通道)被触发后进行DMA操作的函数 * *	chanel:		chanel ID 		通道号 *	src_addr:	source address 		源地址 *	dest_addr:	destination address	目标地址 *	len:		data length(byts)	数据长度(字节) */int do_dma(int chanel,unsigned int* src_addr,unsigned int* dest_addr,int len){	/*	 *	get the DMA global object	 *	获得系统DMA对象	 */	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	/*	 *	get the DMA chanel object	 *	获得DMA通道对象	 */		struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+chanel;		/*	 *	get the transfer count	 *	获取DMA操作的传送次数	 */		unsigned int tc	=(len+dma_chanel->tc_opt-1)/(dma_chanel->tc_opt);	switch(chanel)	{		case DMA_CHANEL_0:			return -1;					case DMA_CHANEL_1:			/*			 *	unmask DMA1 int,set the sys_dma1_done to 0 indicate			 *	that DMA operation will be deal.			 *	开启DMA1中断,将sys_dmaX_done设置为0表示一个DMA操作将开始			 */			irq_mask(INT_DMA1,IRQ_UNMASK);			sys_dma1_done=0;			break;					case DMA_CHANEL_2://same as above			irq_mask(INT_DMA2,IRQ_UNMASK);			sys_dma2_done=0;			break;					case DMA_CHANEL_3://same as above			irq_mask(INT_DMA3,IRQ_UNMASK);			sys_dma3_done=0;			break;	}	/*	 *	set the DMA operation's source address,destination address and	 *	the transfer count(tc)	 *	设置DMA操作的源地址src_addr,目标地址dest_addr,传送次数tc	 */	*dma_chanel->disrc=src_addr;	*dma_chanel->didst=dest_addr;	*dma_chanel->dcon|=tc;	//ready?	while((*dma_chanel->dstat)&0xfffff!=0);		//DMA on, SW_TRIG 	if((*dma_chanel->dcon&(1<<SWHW_SEL_OFFSET))==0)	{		//该通道为软触发		*dma_chanel->dmasktrig=(1<<ON_OFF_OFFSET)|(1<<SW_TRIG_OFFSET); 		printk("dma soft trig turn on\n");	}	else	{		//该通道为硬触发		*dma_chanel->dmasktrig=(0<<STOP_OFFSET)|(1<<ON_OFF_OFFSET)|0;		printk("dma hard trig turn on\n");	}	return chanel;}/* *	we use chanel0 to perform the data transfer between memory and memory *	本函数使用DMA的0号通道对内存间的数据传送 *	src_addr:	source address 		源地址 *	dest_addr:	destination address	目标地址 *	len:		data length(byts)	数据长度(字节) */int dma_mem_transfer(unsigned int* src_addr,unsigned int* dest_addr,int len){	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+0;		unsigned int tc=(len);		irq_mask(INT_DMA0,IRQ_UNMASK);	sys_dma0_done=0;	/*	 *	LOC: 0	address increment	 *	INC: 0	AHB	 */	*dma_chanel->disrc=src_addr;	*dma_chanel->disrcc=(0<<LOC_OFFSET)|(0<<INC_OFFSET);	*dma_chanel->didst=dest_addr;	*dma_chanel->didstc=(0<<LOC_OFFSET)|(0<<INC_OFFSET);		/*	 *	DMD_HS:	 1	Handshake mode.	 *	 *	SYNC:	 1	DREQ and DACK are synchronized to HCLK.	 *			由于是内存间的数据传递,数据源设备是内存,应该同步于HCLK	 *			所以将SYNC位设置为1	 *			若数据源设备是属于外部总线的,则必须同步于PCLK,必须将该	 *			位设置为0	 *				 *	INT:	 1	interrupt request is generated when all the transfer is done.	 *			当该位为1时,则DMA完成(既CURR_TC变为0)之后相应的DMA中断将被触发	 *		 *	TSZ:	 0	an union transfer is performed.	 *			DMA设备每次占用总线时传递数据的次数,0是传递1次后释放总线,	 *			1是传递4次后再释放总线	 *				 *	SERVMODE:1	Whole service mode.	 *	 *	SWHW_SEL:0	S/W request mode.	 *			DMA触发方式的选择,0软件触发,1为硬件触发。	 *			当设置为硬件触发之后我们必须设置HWSRCSEL位	 *			为4个通道配置触发源	 *				 *	RELOAD:	 1	DMA channel (DMA REQ) is turned off when a current value of 	 *			transfer count becomes 0.	 *			当设置为1时,则一旦某通道完成了DMA操作(既CURR_TC变为0),该通道	 *			将被马上关闭。(既DMASKTRIG寄存器的ON_OFF位被置0)	 *			若设置为0时,则完成DMA操作之后的通道并不关闭(既DMASKTRIG寄存器	 *			的ON_OFF位还是1),它会紧接着处理新的请求(如果有的话)	 *	 *	DSZ:	 00	BYTE.	 *			DMA每次传送数据的字节数	 *				 *	TC:	 tc 当前DMA请求总共需要传递多少次数据(必须占用多少次总线)	 *		 一个DMA操作传递的数据字节数实际上是 DSZ*TSZ*TC	 *				 */	*dma_chanel->dcon=(1<<DMD_HS_OFFSET)|(1<<SYNC_OFFSET)|			(1<<INT_OFFSET)|(0<<TSZ_OFFSET)|(1<<SERVMODE_OFFSET)|			(0<<SWHW_SEL_OFFSET)|(1<<RELOAD_OFFSET)|(BYTE<<DSZ_OFFSET)|			(tc);	//ready?	while((*dma_chanel->dstat)&0xfffff!=0);	/*	 *	DMA on, SW_TRIG 	 *	开启DMA通道,触发一个DMA信号	 */	*dma_chanel->dmasktrig=(1<<ON_OFF_OFFSET)|(1<<SW_TRIG_OFFSET);		return tc;}dma_stop(int chanel){	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+chanel;		*dma_chanel->dmasktrig=(1<<STOP_OFFSET);}/* *	irq for dam chanel0 *	dma chanel0 中断服务例程 */void dma0_irq(struct cpu_registers *regs){	/*	 *	clean the interrupt pin and mask the interrupt,set	 *	the sys_dmaX_done to 1,indecate that the DMA opteration 	 *	is complete.	 *		 *	清除中断信号并屏蔽该中断,将sys_dmaX_done	 *	设置为0表示一个DMA操作已经完成	 */	clean_src_pnd(INT_DMA0);	clean_int_pnd(INT_DMA0);	irq_mask(INT_DMA0,IRQ_MASK);	sys_dma0_done=1;}int dma_tranfer_done(){	return sys_dma0_done;}

⌨️ 快捷键说明

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