📄 dma_ep93xx.c
字号:
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 + -