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

📄 dma_ep93xx.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	for (; loop < 10; loop = loop + 2)		if (!dma_chan[loop].ref_count) {			/*			 *  Capture the channel and increment the reference count.			 */			channel = loop;			dma_chan[channel].ref_count++;			break;		}	/*	 *  Unlock the dma channel list.	 */	spin_unlock_irqrestore(&dma_list_lock, flags);	/*	 *  See if we got a valid channel.	 */	if (channel < 0)		return(-1);	/*	 *  Point regs to the correct dma channel register base.	 */	M2P_reg_base = dma_chan[channel].reg_base;	/*	 *  Turn on the clock for the specified DMA channel	 *  TODO: need to use the correct register name for the	 *  power control register.	 */	uiPWRCNT = inl(SYSCON_PWRCNT);	switch (channel) {	case 0:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH0;		break;	case 1:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH1;		break;	case 2:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH2;		break;	case 3:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH3;		break;	case 4:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH4;		break;	case 5:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH5;		break;	case 6:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH6;		break;	case 7:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH7;		break;	case 8:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH8;		break;	case 9:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH9;		break;	default:		return(-1);	}	outl( uiPWRCNT, SYSCON_PWRCNT );	/*	 *  Clear out the control register before any further setup.	 */	outl( 0, M2P_reg_base+M2P_OFFSET_CONTROL );	/*	 *  Setup the peripheral port value in the DMA channel registers.	 */	if (device < 10)		outl( (unsigned int)device, M2P_reg_base+M2P_OFFSET_PPALLOC );	else		outl( (unsigned int)(device - 10), M2P_reg_base+M2P_OFFSET_PPALLOC );	/*	 *  Let's hold on to the value of the Hw device for comparison later.	 */	dma_chan[channel].device = device;	/*	 *  Success.	 */	return(channel);}/***************************************************************************** * * dma_open_m2m(int device) * * Description: This function will attempt to open a M2M DMA channel. *			  If the open is successful, the channel number is returned, *			  otherwise a negative number is returned. * * Parameters: *  device:	 device for which the dma channel is requested. * ****************************************************************************/static intdma_open_m2m(int device){	int channel = -1;	unsigned int loop;	unsigned int M2M_reg_base;	unsigned int uiPWRCNT, uiCONTROL;	unsigned long flags;	DPRINTK("DMA Open M2M with hw dev %d\n", device);	/*	 *  Lock the dma channel list.	 */	spin_lock_irqsave(&dma_list_lock, flags);	DPRINTK("1\n");	/*	 *  Check if this device is already allocated a channel.	 *  TODO: can one M2M device be allocated multiple channels?	 */	for (loop = DMA_MEMORY; loop < UNDEF; loop++)		/*		 *  Before checking for a matching device, check that the		 *  channel is in use, otherwise the device field is		 *  invalid.		 */		if (dma_chan[loop].ref_count)			if (device == dma_chan[loop].device) {				DPRINTK("Error - dma_open_m2m - already allocated channel\n");				/*				 *  Unlock the dma channel list.				 */				spin_unlock_irqrestore(&dma_list_lock, flags);				/*				 *  Fail.				 */				return(-1);			}	/*	 *  Get a DMA channel instance for the given hardware device.	 */	for (loop = 10; loop < 12; loop++)		if (!dma_chan[loop].ref_count) {			/*			 *  Capture the channel and increment the reference count.			 */			channel = loop;			dma_chan[channel].ref_count++;			break;		}	/*	 *  Unlock the dma channel list.	 */	spin_unlock(dma_list_lock);	/*	 *  See if we got a valid channel.	 */	if (channel < 0)		return(-1);	/*	 *  Point regs to the correct dma channel register base.	 */	M2M_reg_base = dma_chan[channel].reg_base;	/*	 *  Turn on the clock for the specified DMA channel	 *  TODO: need to use the correct register name for the	 *  power control register.	 */	uiPWRCNT = inl(SYSCON_PWRCNT);	switch (channel) {	case 10:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH0;		break;	case 11:		uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH1;		break;	default:		return(-1);	}	outl( uiPWRCNT, SYSCON_PWRCNT );	DPRINTK("DMA Open - power control: 0x%x \n", inl(SYSCON_PWRCNT) );	/*	 *  Clear out the control register before any further setup.	 */	outl( 0, M2M_reg_base+M2M_OFFSET_CONTROL );	/*	 *  Setup the transfer mode and the request source selection within	 *  the DMA M2M channel registers.	 */	switch (device) {	case DMA_MEMORY:		/*		 * Clear TM field, set RSS field to 0		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_TM_MASK | CONTROL_M2M_RSS_MASK);		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		break;	case DMA_IDE:		/*		 * Set RSS field to 3, Set NO_HDSK, Set PW field to 1		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_PW_MASK);		uiCONTROL |= (3<<CONTROL_M2M_RSS_SHIFT) |			CONTROL_M2M_NO_HDSK |			(2<<CONTROL_M2M_PW_SHIFT);		uiCONTROL &= ~(CONTROL_M2M_ETDP_MASK);		uiCONTROL &= ~(CONTROL_M2M_DACKP);		uiCONTROL &= ~(CONTROL_M2M_DREQP_MASK);		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		inl(M2M_reg_base+M2M_OFFSET_CONTROL);		break;	case DMARx_SSP:		/*		 * Set RSS field to 1, Set NO_HDSK, Set TM field to 2		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);		uiCONTROL |= (1<<CONTROL_M2M_RSS_SHIFT) |			CONTROL_M2M_NO_HDSK |			(2<<CONTROL_M2M_TM_SHIFT);		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		break;	case DMATx_SSP:		/*		 * Set RSS field to 2, Set NO_HDSK, Set TM field to 1		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);		uiCONTROL |= (2<<CONTROL_M2M_RSS_SHIFT) |			CONTROL_M2M_NO_HDSK |			(1<<CONTROL_M2M_TM_SHIFT);		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		break;	case DMATx_EXT_DREQ:		/*		 * Set TM field to 2, set RSS field to 0		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);		uiCONTROL |= 1<<CONTROL_M2M_TM_SHIFT;		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		break;	case DMARx_EXT_DREQ:		/*		 * Set TM field to 2, set RSS field to 0		 */		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);		uiCONTROL |= 2<<CONTROL_M2M_TM_SHIFT;		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		break;	default:		return -1;	}	/*	 *  Let's hold on to the value of the Hw device for comparison later.	 */	dma_chan[channel].device = device;	/*	 *  Success.	 */	return(channel);}/***************************************************************************** * *  int dma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m, *			   dma_callback callback, unsigned int user_data) * *  Description: Configure the DMA channel and install a callback function. *			   This function will have to be called for every transfer * *  dma:		Pointer to the dma instance data for the M2M channel to *			  configure. *  flags_m2m   Flags used to configure an M2M dma channel and determine *			  if a callback function and user_data information are included *			  in this call. *  callback	function pointer which is called near the end of the *			  dma channel's irq handler. *  user_data   defined by the calling driver. * ****************************************************************************/static intdma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m,			   dma_callback callback, unsigned int user_data){	unsigned int flags;	unsigned int M2M_reg_base, uiCONTROL;	/*	 *  Make sure the channel is disabled before configuring the channel.	 *	 *  TODO: Is this correct??   Making a big change here...	 */	/* if (!dma->pause || (!dma->pause && dma->xfer_enable)) */	if (dma->xfer_enable) {		/*		 *  DMA channel is not paused, so we can't configure it.		 */		DPRINTK("DMA channel not paused, so can't configure! \n");		return(-1);	}	/*	 *  Mask interrupts.	 */	local_irq_save(flags);	/*	 *  Setup a pointer into the dma channel's register set.	 */	M2M_reg_base = dma->reg_base;	uiCONTROL = inl(M2M_reg_base + M2M_OFFSET_CONTROL);	outl(0, M2M_reg_base + M2M_OFFSET_CONTROL);	inl(M2M_reg_base + M2M_OFFSET_CONTROL);	outl(uiCONTROL, M2M_reg_base + M2M_OFFSET_CONTROL);	/*	 *  By default we disable the stall interrupt.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	uiCONTROL &= ~CONTROL_M2M_STALLINTEN;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	/*	 *  By default we disable the done interrupt.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	uiCONTROL &= ~CONTROL_M2M_DONEINTEN;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	/*	 *  Set up the transfer control fields based on values passed in	 *  the flags_m2m field.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	if ( flags_m2m & DESTINATION_HOLD )		uiCONTROL |= CONTROL_M2M_DAH;	else		uiCONTROL &= ~CONTROL_M2M_DAH;	if ( flags_m2m & SOURCE_HOLD )		uiCONTROL |= CONTROL_M2M_SAH;	else		uiCONTROL &= ~CONTROL_M2M_SAH;	uiCONTROL &= ~CONTROL_M2M_TM_MASK;	uiCONTROL |= (((flags_m2m & TRANSFER_MODE_MASK) >> TRANSFER_MODE_SHIFT) <<				  CONTROL_M2M_TM_SHIFT) & CONTROL_M2M_TM_MASK;	uiCONTROL &= ~CONTROL_M2M_PWSC_MASK;	uiCONTROL |= (((flags_m2m & WAIT_STATES_MASK) >> WAIT_STATES_SHIFT) <<				  CONTROL_M2M_PWSC_SHIFT) & CONTROL_M2M_PWSC_MASK;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	inl(M2M_reg_base + M2M_OFFSET_CONTROL);	/*	 *  Save the callback function in the dma instance for this channel.	 */	dma->callback = callback;	/*	 *  Save the user data in the the dma instance for this channel.	 */	dma->user_data = user_data;	/*	 *  Put the dma instance into the pause state by setting the	 *  pause bit to true.	 */	dma->pause = TRUE;	local_irq_restore(flags);	/*	 *  Success.	 */	return(0);}/***************************************************************************** * *  int dma_start(int handle, unsigned int channels, unsigned int * handles) * *  Description: Initiate a transfer on up to 3 channels. * *  handle:	 handle for the channel to initiate transfer on. *  channels:   number of channels to initiate transfers on. *  handles:	pointer to an array of handles, one for each channel which *			   is to be started. * ****************************************************************************/static intdma_start_m2m(int channel, ep93xx_dma_t * dma){	unsigned int flags;	unsigned int M2M_reg_base = dma->reg_base;	unsigned int uiCONTROL;	/*	 *  Mask interrupts while we get this started.	 */	local_irq_save(flags);	/*	 *  Make sure the channel has at least one buffer in the queue.	 */	if (dma->new_buffers < 1) {		/*		 *  Unmask irqs		 */		local_irq_restore(flags);		DPRINTK("DMA Start: Channel starved.\n");		/*		 *  This channel does not have enough buffers queued up,		 *  so enter the pause by starvation state.		 */		dma->xfer_enable = TRUE;		dma->pause = TRUE;		/*		 *  Success.		 */		return(0);	}	/*	 *  Clear any pending interrupts.	 */	outl(0x0, M2M_reg_base+M2M_OFFSET_INTERRUPT);	/*	 *  Set up one or both buffer descriptors with values from the next one or	 *  two buffers in the queue.  By default disable the next frame buffer

⌨️ 快捷键说明

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