From 16e5e77a91ce4f4cfff6c73ebce4269c9cd0d97a Mon Sep 17 00:00:00 2001 From: Mudit Jain Date: Sat, 6 Aug 2016 15:17:30 +0530 Subject: [PATCH] Suggested changes to the API 1. Added an atomic flag in the channel structure and used it accordingly in allocate and free. 2. Cosmetic Changes. 3. Changed the logic in rpi_dma_init. 4. Installed the interrupt handler. 5. Used cache_aligned_malloc instead of cache_coherent_allocate. 6. Added RTEMS_COMPILER_MEMORY_BARRIER in the dma_start function. 7. Added cache invalidating in dma_start. 8. Updated irq.c and irq.h --- .../lib/libbsp/arm/raspberrypi/include/dma.h | 13 +- .../lib/libbsp/arm/raspberrypi/include/irq.h | 5 + c/src/lib/libbsp/arm/raspberrypi/irq/irq.c | 15 ++ c/src/lib/libbsp/arm/raspberrypi/misc/dma.c | 144 +++++++++++------- 4 files changed, 113 insertions(+), 64 deletions(-) diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/dma.h b/c/src/lib/libbsp/arm/raspberrypi/include/dma.h index eeb18237d5d..c49a5755f2e 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/include/dma.h +++ b/c/src/lib/libbsp/arm/raspberrypi/include/dma.h @@ -37,10 +37,8 @@ #define BCM2835_VCBUS_SDRAM_UNCACHED 0xC0000000 #ifdef SOC_BCM2836 -#define BCM2835_ARM_IO_BASE 0x3f000000 #define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED #else -#define BCM2835_ARM_IO_BASE 0x20000000 #define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_CACHED #endif #define BCM2835_ARM_IO_SIZE 0x01000000 @@ -52,14 +50,14 @@ #define PHYS_TO_VCBUS( pa ) ( ( pa ) + BCM2835_VCBUS_SDRAM_BASE ) /* Check whether pa bellong top IO window */ -#define BCM2835_ARM_IS_IO( pa ) ( ( ( pa ) >= BCM2835_ARM_IO_BASE ) && \ - ( ( pa ) < BCM2835_ARM_IO_BASE + \ +#define BCM2835_ARM_IS_IO( pa ) ( ( ( pa ) >= RPI_PERIPHERAL_BASE ) && \ + ( ( pa ) < RPI_PERIPHERAL_BASE + \ BCM2835_ARM_IO_SIZE ) ) /* * Convert physical address in IO space to VC bus address. */ -#define IO_TO_VCBUS( pa ) ( ( pa - BCM2835_ARM_IO_BASE ) + \ +#define IO_TO_VCBUS( pa ) ( ( ( pa ) - RPI_PERIPHERAL_BASE ) + \ BCM2835_VCBUS_IO_BASE ) /* @@ -111,6 +109,7 @@ struct bcm_dma_ch { void * ); void *intr_arg; + Atomic_Flag dma_lock; }; /* API */ @@ -188,7 +187,7 @@ rtems_status_code rpi_dma_start( /* * Initializes the DMA */ -static int rpi_dma_init(); +int rpi_dma_init( int ch ); /* * Get length requested for DMA transaction @@ -196,4 +195,6 @@ static int rpi_dma_init(); */ uint32_t rpi_dma_length( int ch ); +static void rpi_dma_intr( void *arg ); + #endif /* LIBBSP_ARM_RASPBERRYPI_DMA_H */ diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/irq.h b/c/src/lib/libbsp/arm/raspberrypi/include/irq.h index 8436c2dfc60..418a566012b 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/include/irq.h +++ b/c/src/lib/libbsp/arm/raspberrypi/include/irq.h @@ -35,6 +35,11 @@ #define BCM2835_INTC_TOTAL_IRQ 64 + 8 +/* DMA Interrupt is routed to IRQ 16 for DMA Channel 0, + IRQ 17 for Channel 1, and so on till IRQ 28 for Channel 12. + */ + +#define BCM2835_IRQ_ID_DMA_CH0 16 #define BCM2835_IRQ_ID_AUX 29 #define BCM2835_IRQ_ID_SPI_SLAVE 43 diff --git a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c index 7b3b2be3cb6..ba5bff0ce5d 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c +++ b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c @@ -64,6 +64,11 @@ void bsp_interrupt_dispatch(void) { vector = BCM2835_IRQ_ID_UART; } + /* DMA 0 */ + else if ( BCM2835_REG(BCM2835_IRQ_PENDING1) & BCM2835_BIT(16) ) + { + vector = BCM2835_IRQ_ID_DMA_CH0; + } /* GPIO 0*/ else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(17) ) { @@ -114,6 +119,11 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) { BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(25); } + /* DMA 0 */ + else if ( vector == BCM2835_IRQ_ID_DMA_CH0 ) + { + BCM2835_REG(BCM2835_IRQ_ENABLE1) = BCM2835_BIT(16); + } /* GPIO 0 */ else if ( vector == BCM2835_IRQ_ID_GPIO_0 ) { @@ -164,6 +174,11 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) { BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(25); } + /* DMA 0 */ + else if ( vector == BCM2835_IRQ_ID_DMA_CH0 ) + { + BCM2835_REG(BCM2835_IRQ_DISABLE1) = BCM2835_BIT(16); + } /* GPIO 0 */ else if ( vector == BCM2835_IRQ_ID_GPIO_0 ) { diff --git a/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c b/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c index 34d0f64525f..4fbf73b385e 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c +++ b/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -64,7 +65,18 @@ * @brief Table that indicates if a channel is currently occupied. */ static struct bcm_dma_ch bcm_dma_ch[ BCM_DMA_CH_MAX ]; -static Atomic_Flag dma_mutex; + +rtems_status_code rpi_dma_reset( int ch ); + +int bus_dmamap_load_buffer( + bus_dma_segment_t segs[], + void *buf, + unsigned int buflen, + int flags, + vm_offset_t *lastaddrp, + int *segp, + int first +); static void rpi_dmamap_cb( void *arg, @@ -124,7 +136,7 @@ rtems_status_code rpi_dma_reset( int ch ) /* Reset control block */ cb = bcm_dma_ch[ ch ].cb; bzero( cb, sizeof( *cb ) ); - cb->info - INFO_WAIT_RESP; + cb->info = INFO_WAIT_RESP; return RTEMS_SUCCESSFUL; } @@ -138,10 +150,9 @@ rtems_status_code rpi_dma_allocate( int req_ch ) if ( req_ch >= BCM_DMA_CH_MAX ) return ( RTEMS_INVALID_ID ); - if ( _Atomic_Flag_test_and_set( &dma_mutex, + if ( _Atomic_Flag_test_and_set( &bcm_dma_ch[ req_ch ].dma_lock, ATOMIC_ORDER_ACQUIRE ) != 0 ) { - printk( "Could not lock the DMA mutex\n" ); - return RTEMS_UNSATISFIED; + return RTEMS_RESOURCE_IN_USE; } /* Check whether a channel is in use or not and allocate accordingly */ @@ -152,7 +163,7 @@ rtems_status_code rpi_dma_allocate( int req_ch ) return ( RTEMS_RESOURCE_IN_USE ); } - _Atomic_Flag_clear( &dma_mutex, ATOMIC_ORDER_RELEASE ); + _Atomic_Flag_clear( &bcm_dma_ch[ req_ch ].dma_lock, ATOMIC_ORDER_RELEASE ); return ( RTEMS_SUCCESSFUL ); } @@ -162,12 +173,11 @@ rtems_status_code rpi_dma_allocate( int req_ch ) */ rtems_status_code rpi_dma_free( int ch ) { - rtems_status_code status_code; + rtems_status_code status_code = RTEMS_SUCCESSFUL; - if ( _Atomic_Flag_test_and_set( &dma_mutex, + if ( _Atomic_Flag_test_and_set( &bcm_dma_ch[ ch ].dma_lock, ATOMIC_ORDER_ACQUIRE ) != 0 ) { - printk( "Could not lock the DMA mutex\n" ); - return RTEMS_UNSATISFIED; + return RTEMS_RESOURCE_IN_USE; } /* Check the channel number provided */ @@ -185,7 +195,11 @@ rtems_status_code rpi_dma_free( int ch ) status_code = rpi_dma_reset( ch ); } - _Atomic_Flag_clear( &dma_mutex, ATOMIC_ORDER_RELEASE ); + status_code = rtems_interrupt_handler_remove( BCM2835_IRQ_ID_DMA_CH0 + ch, + rpi_dma_intr, + NULL ); + + _Atomic_Flag_clear( &bcm_dma_ch[ ch ].dma_lock, ATOMIC_ORDER_RELEASE ); return ( status_code ); } @@ -381,6 +395,10 @@ rtems_status_code rpi_dma_start( (void *) bcm_dma_ch[ ch ].dma_map->buffer_begin, bcm_dma_ch[ ch ].dma_map->buffer_size ); + rtems_cache_invalidate_multiple_data_lines( + (void *) bcm_dma_ch[ ch ].dma_map->buffer_begin, + bcm_dma_ch[ ch ].dma_map->buffer_size ); + /* Write the physical address of the control block into the register */ BCM2835_REG( BCM_DMA_CBADDR( ch ) ) = bcm_dma_ch[ ch ].vc_cb; @@ -425,7 +443,7 @@ int bus_dmamap_load_buffer( ) { unsigned int sgsize; - unsigned int curaddr, lastaddr, baddr, bmask; + unsigned int curaddr, lastaddr, bmask; vm_offset_t vaddr = (vm_offset_t) buf; int seg; @@ -482,74 +500,84 @@ int bus_dmamap_load_buffer( return ( buflen != 0 ? 27 : 0 ); } -static int rpi_dma_init() +int rpi_dma_init( int channel ) { - int i; struct bcm_dma_ch *ch; void *cb_virt; - vm_paddr_t cb_phys; + vm_paddr_t cb_phys = 0; int error, nsegs; vm_offset_t lastaddr; + bus_dma_segment_t dm_segments[ 1 ]; /* Setup Initial Setting */ - for ( i = 0; i < BCM_DMA_CH_MAX; i++ ) { - bus_dma_segment_t dm_segments[ 1 ]; - ch = &bcm_dma_ch[ i ]; + /* Check the channel number provided */ + if ( channel < 0 || channel >= BCM_DMA_CH_MAX ) + return ( RTEMS_INVALID_ID ); - bzero( ch, sizeof( struct bcm_dma_ch ) ); - ch->ch = i; - ch->flags = BCM_DMA_CH_UNMAP; + /* Check whether the channel is in use */ + if ( !( bcm_dma_ch[ channel ].flags & BCM_DMA_CH_USED ) ) + return ( RTEMS_RESOURCE_IN_USE ); - ch->dma_map = malloc( sizeof( struct bus_dmamap ) ); + ch = &bcm_dma_ch[ channel ]; - if ( ch->dma_map == NULL ) { - return ENOMEM; - } + bzero( ch, sizeof( struct bcm_dma_ch ) ); + ch->ch = channel; + ch->flags = BCM_DMA_CH_UNMAP; - /* Alignment = 1 , Boundary = 0 */ - cb_virt = rtems_cache_coherent_allocate( - sizeof( struct bcm_dma_cb ), 1, 0 ); + ch->dma_map = malloc( sizeof( struct bus_dmamap ) ); - if ( cb_virt == NULL ) { - free( ch->dma_map ); + if ( ch->dma_map == NULL ) { + return ENOMEM; + } - return ENOMEM; - } + /* Alignment = 1 , Boundary = 0 */ + cb_virt = rtems_cache_aligned_malloc( + sizeof( struct bcm_dma_cb ) ); - ch->dma_map->buffer_begin = cb_virt; - ch->dma_map->buffer_size = sizeof( struct bcm_dma_cb ); + if ( cb_virt == NULL ) { + free( ch->dma_map ); - memset( cb_virt, 0, sizeof( struct bcm_dma_cb ) ); + return ENOMEM; + } - /* - * Least alignment for busdma-allocated stuff is cache - * line size, so just make sure nothing stupid happened - * and we got properly aligned address - */ - if ( (unsigned long int) cb_virt & 0x1f ) - break; + ch->dma_map->buffer_begin = cb_virt; + ch->dma_map->buffer_size = sizeof( struct bcm_dma_cb ); -//FIXME : Verify mapping buffer into bus space using the dmamap - lastaddr = (vm_offset_t) 0; - nsegs = 0; + memset( cb_virt, 0, sizeof( struct bcm_dma_cb ) ); - error = bus_dmamap_load_buffer( dm_segments, cb_virt, - sizeof( struct bcm_dma_cb ), 0x00, &lastaddr, &nsegs, 1 ); + /* + * Least alignment for busdma-allocated stuff is cache + * line size, so just make sure nothing stupid happened + * and we got properly aligned address + */ + if ( (unsigned long int) cb_virt & 0x1f ) + return RTEMS_UNSATISFIED; - if ( error == 0 ) - rpi_dmamap_cb( &cb_phys, dm_segments, nsegs + 1, 0 ); - else - rpi_dmamap_cb( &cb_phys, NULL, 0, error ); + lastaddr = (vm_offset_t) 0; + nsegs = 0; - ch->cb = cb_virt; - ch->vc_cb = cb_phys; - ch->flags = BCM_DMA_CH_FREE; - ch->cb->info = INFO_WAIT_RESP; + error = bus_dmamap_load_buffer( dm_segments, cb_virt, + sizeof( struct bcm_dma_cb ), 0x00, &lastaddr, &nsegs, 1 ); - /* reset DMA */ - BCM2835_REG( BCM_DMA_CS( i ) ) = CS_RESET; - } + if ( error == 0 ) + rpi_dmamap_cb( &cb_phys, dm_segments, nsegs + 1, 0 ); + else + rpi_dmamap_cb( &cb_phys, NULL, 0, error ); + + ch->cb = cb_virt; + ch->vc_cb = cb_phys; + ch->flags = BCM_DMA_CH_FREE; + ch->cb->info = INFO_WAIT_RESP; + + rtems_interrupt_handler_install( BCM2835_IRQ_ID_DMA_CH0 + channel, + "DMA copy", + RTEMS_INTERRUPT_UNIQUE, + rpi_dma_intr, + NULL ); + + /* reset DMA */ + BCM2835_REG( BCM_DMA_CS( channel ) ) = CS_RESET; return 0; }