Skip to content

Commit

Permalink
Suggested changes to the API
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Mudit Jain committed Aug 6, 2016
1 parent f328c4c commit 16e5e77
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 64 deletions.
13 changes: 7 additions & 6 deletions c/src/lib/libbsp/arm/raspberrypi/include/dma.h
Expand Up @@ -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
Expand All @@ -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 )

/*
Expand Down Expand Up @@ -111,6 +109,7 @@ struct bcm_dma_ch {
void *
);
void *intr_arg;
Atomic_Flag dma_lock;
};

/* API */
Expand Down Expand Up @@ -188,12 +187,14 @@ 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
* ch - channel number
*/
uint32_t rpi_dma_length( int ch );

static void rpi_dma_intr( void *arg );

#endif /* LIBBSP_ARM_RASPBERRYPI_DMA_H */
5 changes: 5 additions & 0 deletions c/src/lib/libbsp/arm/raspberrypi/include/irq.h
Expand Up @@ -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.
*/

This comment has been minimized.

Copy link
@gedare

gedare Aug 6, 2016

no blank space between comment and code. I think multi-line comments usually are

/* ...
 * ... */

or like

/*
 * ...
 * ...
 */

Look to see if you can find some examples.

#define BCM2835_IRQ_ID_DMA_CH0 16

#define BCM2835_IRQ_ID_AUX 29
#define BCM2835_IRQ_ID_SPI_SLAVE 43
Expand Down
15 changes: 15 additions & 0 deletions c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
Expand Up @@ -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) )
{
Expand Down Expand Up @@ -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 )
{
Expand Down Expand Up @@ -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 )
{
Expand Down
144 changes: 86 additions & 58 deletions c/src/lib/libbsp/arm/raspberrypi/misc/dma.c
Expand Up @@ -9,6 +9,7 @@
#include <bsp.h>
#include <bsp/raspberrypi.h>
#include <bsp/dma.h>
#include <bsp/irq.h>
#include <stdlib.h>
#include <errno.h>

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand All @@ -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 */
Expand All @@ -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 );
}
Expand All @@ -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 */
Expand All @@ -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 );
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 16e5e77

Please sign in to comment.