📄 dma_ep93xx.c
字号:
* interrupt on the channel. */ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); uiCONTROL &= ~CONTROL_M2M_NFBINTEN; outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); /* * enable the done interrupt. */ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2M_DONEINTEN; outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); /* * Update the dma channel instance transfer state. */ dma->xfer_enable = TRUE; dma->pause = FALSE; /* * Program up the first buffer descriptor with a source and destination * and a byte count. */ outl( dma->buffer_queue[dma->current_buffer].source, M2M_reg_base+M2M_OFFSET_SAR_BASE0 ); outl( dma->buffer_queue[dma->current_buffer].dest, M2M_reg_base+M2M_OFFSET_DAR_BASE0 ); outl( dma->buffer_queue[dma->current_buffer].size, M2M_reg_base+M2M_OFFSET_BCR0 ); /* * Decrement the new buffers counter. */ dma->new_buffers--; /* * Set up the second buffer descriptor with a second buffer if we have * a second buffer. */ if (dma->new_buffers) { outl( dma->buffer_queue[(dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, M2M_reg_base+M2M_OFFSET_SAR_BASE1 ); outl( dma->buffer_queue[(dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].dest, M2M_reg_base+M2M_OFFSET_DAR_BASE1 ); outl( dma->buffer_queue[(dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, M2M_reg_base+M2M_OFFSET_BCR1 ); uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2M_NFBINTEN; outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); dma->new_buffers--; } /* * Now we enable the channel. This initiates the transfer. */ uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2M_ENABLE; outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); inl(M2M_reg_base + M2M_OFFSET_CONTROL); /* * If this is a memory to memory transfer, we need to s/w trigger the * transfer by setting the start bit within the control register. */ if (dma->device == DMA_MEMORY) { uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2M_START; outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL ); } DPRINTK("DMA - It's been started!!"); DPRINTK("CONTROL - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_CONTROL) ); DPRINTK("STATUS - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_STATUS) ); DPRINTK("BCR0 - 0x%x \n", dma->buffer_queue[dma->current_buffer].size); DPRINTK("SAR_BASE0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) ); DPRINTK("SAR_CUR0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) ); DPRINTK("DAR_BASE0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) ); DPRINTK("DAR_CUR0 - 0x%x \n", inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) ); /* * Unmask irqs */ local_irq_restore(flags); /* * Success. */ return(0);}/***************************************************************************** * * DMA interface functions * ****************************************************************************//***************************************************************************** * * int dma_init(int handle, unsigned int flags_m2p, unsigned int flags_m2m, * dma_callback callback, unsigned int user_data) * * Description: Configure the DMA channel and install a callback function. * * handle: Handle unique the each instance of the dma interface, used * to verify this call. * flags_m2p Flags used to configure an M2P/P2M dma channel and determine * if a callback function and user_data information are included * in this call. This field should be NULL if handle represents * an M2M channel. * 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. This field should be NULL if handle represents * an M2P/P2M channel. * callback function pointer which is called near the end of the * dma channel's irq handler. * user_data defined by the calling driver. * ****************************************************************************/intep93xx_dma_config(int handle, unsigned int flags_m2p, unsigned int flags_m2m, dma_callback callback, unsigned int user_data){ int channel; ep93xx_dma_t * dma; int flags; unsigned int M2P_reg_base, uiCONTROL; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Config: Invalid dma handle.\n"); return(-EINVAL); } DPRINTK("DMA Config \n"); dma = &dma_chan[channel]; local_irq_save(flags); /* * Check if the channel is currently transferring. */ if (dma->xfer_enable) { local_irq_restore(flags); return(-EINVAL); } /* * Check if this is an m2m function. */ if (channel >= 10) { local_irq_restore(flags); /* * Call another function to handle m2m config. */ return(dma_config_m2m(dma, flags_m2m, callback, user_data)); } /* * Setup a pointer into the dma channel's register set. */ M2P_reg_base = dma->reg_base; /* * By default we enable the stall interrupt. */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2P_STALLINTEN; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); /* * Configure the channel for an error from the peripheral. */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); if ( flags_m2p && CHANNEL_ERROR_INT_ENABLE ) uiCONTROL |= CONTROL_M2P_CHERRORINTEN; else uiCONTROL &= ~CONTROL_M2P_CHERRORINTEN; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); if ( flags_m2p && CHANNEL_ABORT ) uiCONTROL |= CONTROL_M2P_ABRT; else uiCONTROL &= ~CONTROL_M2P_ABRT; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); if ( flags_m2p && IGNORE_CHANNEL_ERROR ) uiCONTROL |= CONTROL_M2P_ICE; else uiCONTROL &= ~CONTROL_M2P_ICE; outl( uiCONTROL, M2P_reg_base+M2P_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. * ****************************************************************************/intep93xx_dma_start(int handle, unsigned int channels, unsigned int * handles){ ep93xx_dma_t * dma_pointers[3]; unsigned int M2P_reg_bases[3]; unsigned int loop, flags, uiCONTROL; int channel; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Start: Invalid dma handle.\n"); return(-EINVAL); } if (channels < 1) { printk(KERN_ERR "DMA Start: Invalid parameter.\n"); return(-EINVAL); } DPRINTK("DMA Start \n"); /* * Mask off registers. */ local_irq_save(flags); /* * Check if this is a start multiple. */ if (channels > 1) { DPRINTK("DMA ERROR: Start, multiple start not supported yet \n"); return(-1); } else { /* * Check if this channel is already transferring. */ if (dma_chan[channel].xfer_enable && !dma_chan[channel].pause) { printk(KERN_ERR "DMA Start: Invalid command for channel %d.\n", channel); /* * Unmask irqs */ local_irq_restore(flags); /* * This channel is already transferring, so return an error. */ return(-EINVAL); } /* * If this is an M2M channel, call a different function. */ if (channel >= 10) { /* * Unmask irqs */ local_irq_restore(flags); /* * Call the m2m start function. Only start one channel. */ return(dma_start_m2m(channel, &dma_chan[channel])); } /* * Make sure the channel has at least one buffer in the queue. */ if (dma_chan[channel].new_buffers < 1) { DPRINTK("DMA Start: Channel starved.\n"); /* * This channel does not have enough buffers queued up, * so enter the pause by starvation state. */ dma_chan[channel].xfer_enable = TRUE; dma_chan[channel].pause = TRUE; /* * Unmask irqs */ local_irq_restore(flags); /* * Success. */ return(0); } /* * Set up a dma instance pointer for this dma channel. */ dma_pointers[0] = &dma_chan[channel]; /* * Set up a pointer to the register set for this channel. */ M2P_reg_bases[0] = dma_pointers[0]->reg_base; } /* * Setup both MAXCNT registers with values from the next two buffers * in the queue, and enable the next frame buffer interrupt on the channel. */ for (loop = 0; loop < channels; loop++) { /* * By default we enable the next frame buffer interrupt. */ uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2P_NFBINTEN; outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL ); /* * Check if we need to restore a paused transfer. */ if (dma_pointers[loop]->pause_buf.buf_id != -1) outl( dma_pointers[loop]->pause_buf.size, M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 ); else outl( dma_pointers[loop]->buffer_queue[dma_pointers[loop]->current_buffer].size, M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 ); } for (loop = 0; loop < channels; loop++) { /* * Enable the specified dma channels. */ uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2P_ENABLE; outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL ); /* * Update the dma channel instance transfer state. */ dma_pointers[loop]->xfer_enable = TRUE; dma_pointers[loop]->pause = FALSE; if (dma_pointers[loop]->pause_buf.buf_id == -1) dma_pointers[loop]->new_buffers--; } /* * Program up the BASE0 registers for all specified channels, this * will initiate transfers on all specified channels. */ for (loop = 0; loop < channels; loop++) /* * Check if we need to restore a paused transfer. */ if (dma_pointers[loop]->pause_buf.buf_id != -1) { outl( dma_pointers[loop]->pause_buf.source, M2P_reg_bases[loop]+M2P_OFFSET_BASE0 ); /* * Set the pause buffer to NULL */ dma_pointers[loop]->pause_buf.buf_id = -1; dma_pointers[loop]->pause_buf.size = 0; } else outl( dma_pointers[loop]->buffer_queue[ dma_pointers[loop]->current_buffer].source, M2P_reg_bases[loop]+M2P_OFFSET_BASE0 ); /* * Before restoring irqs setup the second MAXCNT/BASE * register with a second buffer. */ for (loop = 0; loop < channels; loop++) if (dma_pointers[loop]->new_buffers) { outl( dma_pointers[loop]->buffer_queue[ (dma_pointers[loop]->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT1 ); outl( dma_pointers[loop]->buffer_queue[ (dma_pointers[loop]->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, M2P_reg_bases[loop]+M2P_OFFSET_BASE1 ); } /* DPRINTK("DMA - It's been started!!"); DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); DPRINTK("Pause - %d \n", dma_pointers[0]->pause); DPRINTK("xfer_enable - %d \n", dma_pointers[0]->xfer_enable); DPRINTK("total bytes - 0x%x \n", dma_pointers[0]->total_bytes); DPRINTK("total buffer - %d \n", dma_pointers[0]->total_buffers); DPRINTK("new buffers - %d \n", dma_pointers[0]->new_buffers); DPRINTK("current buffer - %d \n", dma_pointers[0]->current_buffer); DPRINTK("last buffer - %d \n", dma_pointers[0]->last_buffer); DPRINTK("used buffers - %d \n", dma_pointers[0]->used_buffers); */ /* * Unmask irqs */ local_irq_restore(flags); /* * Success. */ return(0);}/***************************************************************************** * * int ep93xx_dma_add_buffer(int handle, unsigned int * address, * unsigned int size, unsigned int last) * * Description: Add a buffer entry to the DMA buffer queue. * * handle: handle for the channel to add this buffer to. * address: Pointer to an integer which is the start address of the * buffer which is to be added to the queue. * size: size of the buffer in bytes.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -