From ec34b48b9b87462276f93ab07f7522b84c1819bd Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Fri, 26 Aug 2016 01:52:52 +0200 Subject: [PATCH] arm/raspberrypi: DMA API: ensure that channel is enabled when it is configured. I am not sure if channel has to be (power) enabled to access registers. Consider that even for plain access enable is required to be on safe side. --- c/src/lib/libbsp/arm/raspberrypi/misc/dma.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c b/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c index 37b764b7bd8..71d8668138c 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c +++ b/c/src/lib/libbsp/arm/raspberrypi/misc/dma.c @@ -61,6 +61,7 @@ #define BCM_PAGE_SIZE 4096 #define BCM_PAGE_MASK ( BCM_PAGE_SIZE - 1 ) + /** * @brief Table that indicates if a channel is currently occupied. */ @@ -70,6 +71,8 @@ static void rpi_dma_intr( void *arg ); rtems_status_code rpi_dma_reset( int ch ); +RTEMS_INTERRUPT_LOCK_DEFINE( static, bcm_dma_lock, "bcm_dma_lock" ); + int bus_dmamap_load_buffer( bus_dma_segment_t segs[], void *buf, @@ -361,7 +364,9 @@ rtems_status_code rpi_dma_start( int len ) { + rtems_interrupt_lock_context lock_context; struct bcm_dma_cb *cb; + uint32_t ch_mask = 1 << ch; /* Check the channel number provided */ if ( ch < 0 || ch >= BCM_DMA_CH_MAX ) @@ -407,6 +412,12 @@ rtems_status_code rpi_dma_start( /* Change the state of the channel */ BCM2835_REG( BCM_DMA_CS( ch ) ) = CS_ACTIVE; + if ( ! ( BCM2835_REG( BCM_DMA_ENABLE ) & ch_mask) ) { + rtems_interrupt_lock_acquire(&bcm_dma_lock, &lock_context); + BCM2835_REG( BCM_DMA_ENABLE ) |= ch_mask; + rtems_interrupt_lock_release(&bcm_dma_lock, &lock_context); + } + return RTEMS_SUCCESSFUL; } @@ -504,6 +515,7 @@ int bus_dmamap_load_buffer( int rpi_dma_init( int channel ) { + rtems_interrupt_lock_context lock_context; struct bcm_dma_ch *ch; void *cb_virt; vm_paddr_t cb_phys = 0; @@ -581,6 +593,13 @@ int rpi_dma_init( int channel ) /* reset DMA */ BCM2835_REG( BCM_DMA_CS( channel ) ) = CS_RESET; + rtems_interrupt_lock_acquire(&bcm_dma_lock, &lock_context); + BCM2835_REG( BCM_DMA_ENABLE ) |= 1 << channel; + rtems_interrupt_lock_release(&bcm_dma_lock, &lock_context); + + /* reset DMA */ + BCM2835_REG( BCM_DMA_CS( channel ) ) = CS_RESET; + return 0; }