/////////////////////////////////////////////////////////////////////////////////// // File : dma_driver.c // Date : 23/11/2013 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #if !defined(X_SIZE) # error: You must define X_SIZE in the hard_config.h file #endif #if !defined(Y_SIZE) # error: You must define X_SIZE in the hard_config.h file #endif #if !defined(X_WIDTH) # error: You must define X_WIDTH in the hard_config.h file #endif #if !defined(Y_WIDTH) # error: You must define X_WIDTH in the hard_config.h file #endif #if !defined(NB_DMA_CHANNELS) # error: You must define NB_DMA_CHANNELS in the hard_config.h file #endif #if !defined(SEG_DMA_BASE) # error: You must define SEG_DMA_BASE in the hard_config.h file #endif #if !defined(PERI_CLUSTER_INCREMENT) # error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file #endif extern volatile unsigned int _ptabs_vaddr[]; /////////////////////////////////////////////////////////////////////////////// // This low level function returns the value contained in register "index" // in the DMA component contained in cluster "cluster_xy" /////////////////////////////////////////////////////////////////////////////// #if NB_DMA_CHANNELS > 0 static unsigned int _dma_get_register( unsigned int cluster_xy, // cluster index unsigned int channel_id, // channel index unsigned int index ) // register index { unsigned int vaddr = SEG_DMA_BASE + (cluster_xy * PERI_CLUSTER_INCREMENT) + (channel_id * DMA_SPAN) + (index << 2); return ioread32( (void*)vaddr ); } #endif /////////////////////////////////////////////////////////////////////////////// // This low level function sets a new value in register "index" // in the DMA component contained in cluster "cluster_xy" /////////////////////////////////////////////////////////////////////////////// #if NB_DMA_CHANNELS > 0 static void _dma_set_register( unsigned int cluster_xy, // cluster index unsigned int channel_id, // channel index unsigned int index, // register index unsigned int value ) // value to be written { unsigned int vaddr = SEG_DMA_BASE + (cluster_xy * PERI_CLUSTER_INCREMENT) + (channel_id * DMA_SPAN) + (index << 2); iowrite32( (void*)vaddr, value ); } #endif //////////////////////////////////////////////// void _dma_disable_irq( unsigned int cluster_xy, unsigned int channel_id ) { #if NB_DMA_CHANNELS > 0 // check DMA channel parameters unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) { _puts("\n[DMA ERROR] in _dma_disable_irq() : illegal DMA channel "); _exit(); } // disable interrupt for selected channel _dma_set_register(cluster_xy, channel_id, DMA_IRQ_DISABLE, 1); #endif } ///////////////////////////////////////////////// void _dma_reset_channel( unsigned int cluster_xy, unsigned int channel_id ) { #if NB_DMA_CHANNELS > 0 // check DMA channel parameters unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) { _puts("\n[DMA ERROR] in _dma_reset_channel() : illegal DMA channel "); _exit(); } // reset selected channel _dma_set_register(cluster_xy, channel_id, DMA_RESET, 0); #endif } /////////////////////////////////////////////////////// void _dma_get_status( unsigned int cluster_xy, unsigned int channel_id, unsigned int* status ) { #if NB_DMA_CHANNELS > 0 // check DMA channel parameters unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) { _puts("\n[DMA ERROR] in _dma_get_status() : illegal DMA channel "); _exit(); } // returns selected channel status *status = _dma_get_register(cluster_xy, channel_id, DMA_LEN); #endif } //////////////////////////////////////////////////////// void _dma_start_transfer( unsigned int cluster_xy, // DMA cluster unsigned int channel_id, // DMA channel unsigned long long dst_paddr, // physical address unsigned long long src_paddr, // physical address unsigned int size ) // bytes { #if NB_DMA_CHANNELS > 0 // check DMA channel parameters unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) { _puts("\n[DMA ERROR] in _dma_start_transfer() : illegal DMA channel "); _exit(); } // selected channel configuration and lauching _dma_set_register(cluster_xy, channel_id, DMA_SRC, (unsigned int)(src_paddr)); _dma_set_register(cluster_xy, channel_id, DMA_SRC_EXT, (unsigned int)(src_paddr>>32)); _dma_set_register(cluster_xy, channel_id, DMA_DST, (unsigned int)(dst_paddr)); _dma_set_register(cluster_xy, channel_id, DMA_DST_EXT, (unsigned int)(dst_paddr>>32)); _dma_set_register(cluster_xy, channel_id, DMA_LEN, (unsigned int)size); #endif } /////////////////////////////////////////////////////// void _dma_physical_copy( unsigned int cluster_xy, // DMA cluster unsigned int channel_id, // DMA channel unsigned long long dst_paddr, // dest physical address unsigned long long src_paddr, // src physical address unsigned int size ) // bytes { #if NB_DMA_CHANNELS > 0 // check buffers alignment constraints if ( (dst_paddr & 0x3) || (src_paddr & 0x3) || (size & 0x3) ) { _puts("\n[DMA ERROR] in _dma_physical_copy() : buffer unaligned\n"); _exit(); } #if GIET_DEBUG_DMA_DRIVER unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1< 0 // check buffers alignment constraints if ( (dst_vaddr & 0x3) || (src_vaddr & 0x3) || (size & 0x3) ) { _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n"); _exit(); } unsigned long long src_paddr; unsigned long long dst_paddr; unsigned int flags; #if GIET_DEBUG_DMA_DRIVER unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<