Skip to content

Commit 16e5e77

Browse files
author
Mudit Jain
committed
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
1 parent f328c4c commit 16e5e77

File tree

4 files changed

+113
-64
lines changed

4 files changed

+113
-64
lines changed

c/src/lib/libbsp/arm/raspberrypi/include/dma.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,8 @@
3737
#define BCM2835_VCBUS_SDRAM_UNCACHED 0xC0000000
3838

3939
#ifdef SOC_BCM2836
40-
#define BCM2835_ARM_IO_BASE 0x3f000000
4140
#define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED
4241
#else
43-
#define BCM2835_ARM_IO_BASE 0x20000000
4442
#define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_CACHED
4543
#endif
4644
#define BCM2835_ARM_IO_SIZE 0x01000000
@@ -52,14 +50,14 @@
5250
#define PHYS_TO_VCBUS( pa ) ( ( pa ) + BCM2835_VCBUS_SDRAM_BASE )
5351

5452
/* Check whether pa bellong top IO window */
55-
#define BCM2835_ARM_IS_IO( pa ) ( ( ( pa ) >= BCM2835_ARM_IO_BASE ) && \
56-
( ( pa ) < BCM2835_ARM_IO_BASE + \
53+
#define BCM2835_ARM_IS_IO( pa ) ( ( ( pa ) >= RPI_PERIPHERAL_BASE ) && \
54+
( ( pa ) < RPI_PERIPHERAL_BASE + \
5755
BCM2835_ARM_IO_SIZE ) )
5856

5957
/*
6058
* Convert physical address in IO space to VC bus address.
6159
*/
62-
#define IO_TO_VCBUS( pa ) ( ( pa - BCM2835_ARM_IO_BASE ) + \
60+
#define IO_TO_VCBUS( pa ) ( ( ( pa ) - RPI_PERIPHERAL_BASE ) + \
6361
BCM2835_VCBUS_IO_BASE )
6462

6563
/*
@@ -111,6 +109,7 @@ struct bcm_dma_ch {
111109
void *
112110
);
113111
void *intr_arg;
112+
Atomic_Flag dma_lock;
114113
};
115114

116115
/* API */
@@ -188,12 +187,14 @@ rtems_status_code rpi_dma_start(
188187
/*
189188
* Initializes the DMA
190189
*/
191-
static int rpi_dma_init();
190+
int rpi_dma_init( int ch );
192191

193192
/*
194193
* Get length requested for DMA transaction
195194
* ch - channel number
196195
*/
197196
uint32_t rpi_dma_length( int ch );
198197

198+
static void rpi_dma_intr( void *arg );
199+
199200
#endif /* LIBBSP_ARM_RASPBERRYPI_DMA_H */

c/src/lib/libbsp/arm/raspberrypi/include/irq.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535

3636
#define BCM2835_INTC_TOTAL_IRQ 64 + 8
3737

38+
/* DMA Interrupt is routed to IRQ 16 for DMA Channel 0,
39+
IRQ 17 for Channel 1, and so on till IRQ 28 for Channel 12.
40+
*/
41+
42+
#define BCM2835_IRQ_ID_DMA_CH0 16
3843

3944
#define BCM2835_IRQ_ID_AUX 29
4045
#define BCM2835_IRQ_ID_SPI_SLAVE 43

c/src/lib/libbsp/arm/raspberrypi/irq/irq.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ void bsp_interrupt_dispatch(void)
6464
{
6565
vector = BCM2835_IRQ_ID_UART;
6666
}
67+
/* DMA 0 */
68+
else if ( BCM2835_REG(BCM2835_IRQ_PENDING1) & BCM2835_BIT(16) )
69+
{
70+
vector = BCM2835_IRQ_ID_DMA_CH0;
71+
}
6772
/* GPIO 0*/
6873
else if ( BCM2835_REG(BCM2835_IRQ_PENDING2) & BCM2835_BIT(17) )
6974
{
@@ -114,6 +119,11 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
114119
{
115120
BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(25);
116121
}
122+
/* DMA 0 */
123+
else if ( vector == BCM2835_IRQ_ID_DMA_CH0 )
124+
{
125+
BCM2835_REG(BCM2835_IRQ_ENABLE1) = BCM2835_BIT(16);
126+
}
117127
/* GPIO 0 */
118128
else if ( vector == BCM2835_IRQ_ID_GPIO_0 )
119129
{
@@ -164,6 +174,11 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
164174
{
165175
BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(25);
166176
}
177+
/* DMA 0 */
178+
else if ( vector == BCM2835_IRQ_ID_DMA_CH0 )
179+
{
180+
BCM2835_REG(BCM2835_IRQ_DISABLE1) = BCM2835_BIT(16);
181+
}
167182
/* GPIO 0 */
168183
else if ( vector == BCM2835_IRQ_ID_GPIO_0 )
169184
{

c/src/lib/libbsp/arm/raspberrypi/misc/dma.c

Lines changed: 86 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <bsp.h>
1010
#include <bsp/raspberrypi.h>
1111
#include <bsp/dma.h>
12+
#include <bsp/irq.h>
1213
#include <stdlib.h>
1314
#include <errno.h>
1415

@@ -64,7 +65,18 @@
6465
* @brief Table that indicates if a channel is currently occupied.
6566
*/
6667
static struct bcm_dma_ch bcm_dma_ch[ BCM_DMA_CH_MAX ];
67-
static Atomic_Flag dma_mutex;
68+
69+
rtems_status_code rpi_dma_reset( int ch );
70+
71+
int bus_dmamap_load_buffer(
72+
bus_dma_segment_t segs[],
73+
void *buf,
74+
unsigned int buflen,
75+
int flags,
76+
vm_offset_t *lastaddrp,
77+
int *segp,
78+
int first
79+
);
6880

6981
static void rpi_dmamap_cb(
7082
void *arg,
@@ -124,7 +136,7 @@ rtems_status_code rpi_dma_reset( int ch )
124136
/* Reset control block */
125137
cb = bcm_dma_ch[ ch ].cb;
126138
bzero( cb, sizeof( *cb ) );
127-
cb->info - INFO_WAIT_RESP;
139+
cb->info = INFO_WAIT_RESP;
128140

129141
return RTEMS_SUCCESSFUL;
130142
}
@@ -138,10 +150,9 @@ rtems_status_code rpi_dma_allocate( int req_ch )
138150
if ( req_ch >= BCM_DMA_CH_MAX )
139151
return ( RTEMS_INVALID_ID );
140152

141-
if ( _Atomic_Flag_test_and_set( &dma_mutex,
153+
if ( _Atomic_Flag_test_and_set( &bcm_dma_ch[ req_ch ].dma_lock,
142154
ATOMIC_ORDER_ACQUIRE ) != 0 ) {
143-
printk( "Could not lock the DMA mutex\n" );
144-
return RTEMS_UNSATISFIED;
155+
return RTEMS_RESOURCE_IN_USE;
145156
}
146157

147158
/* 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 )
152163
return ( RTEMS_RESOURCE_IN_USE );
153164
}
154165

155-
_Atomic_Flag_clear( &dma_mutex, ATOMIC_ORDER_RELEASE );
166+
_Atomic_Flag_clear( &bcm_dma_ch[ req_ch ].dma_lock, ATOMIC_ORDER_RELEASE );
156167

157168
return ( RTEMS_SUCCESSFUL );
158169
}
@@ -162,12 +173,11 @@ rtems_status_code rpi_dma_allocate( int req_ch )
162173
*/
163174
rtems_status_code rpi_dma_free( int ch )
164175
{
165-
rtems_status_code status_code;
176+
rtems_status_code status_code = RTEMS_SUCCESSFUL;
166177

167-
if ( _Atomic_Flag_test_and_set( &dma_mutex,
178+
if ( _Atomic_Flag_test_and_set( &bcm_dma_ch[ ch ].dma_lock,
168179
ATOMIC_ORDER_ACQUIRE ) != 0 ) {
169-
printk( "Could not lock the DMA mutex\n" );
170-
return RTEMS_UNSATISFIED;
180+
return RTEMS_RESOURCE_IN_USE;
171181
}
172182

173183
/* Check the channel number provided */
@@ -185,7 +195,11 @@ rtems_status_code rpi_dma_free( int ch )
185195
status_code = rpi_dma_reset( ch );
186196
}
187197

188-
_Atomic_Flag_clear( &dma_mutex, ATOMIC_ORDER_RELEASE );
198+
status_code = rtems_interrupt_handler_remove( BCM2835_IRQ_ID_DMA_CH0 + ch,
199+
rpi_dma_intr,
200+
NULL );
201+
202+
_Atomic_Flag_clear( &bcm_dma_ch[ ch ].dma_lock, ATOMIC_ORDER_RELEASE );
189203

190204
return ( status_code );
191205
}
@@ -381,6 +395,10 @@ rtems_status_code rpi_dma_start(
381395
(void *) bcm_dma_ch[ ch ].dma_map->buffer_begin,
382396
bcm_dma_ch[ ch ].dma_map->buffer_size );
383397

398+
rtems_cache_invalidate_multiple_data_lines(
399+
(void *) bcm_dma_ch[ ch ].dma_map->buffer_begin,
400+
bcm_dma_ch[ ch ].dma_map->buffer_size );
401+
384402
/* Write the physical address of the control block into the register */
385403
BCM2835_REG( BCM_DMA_CBADDR( ch ) ) = bcm_dma_ch[ ch ].vc_cb;
386404

@@ -425,7 +443,7 @@ int bus_dmamap_load_buffer(
425443
)
426444
{
427445
unsigned int sgsize;
428-
unsigned int curaddr, lastaddr, baddr, bmask;
446+
unsigned int curaddr, lastaddr, bmask;
429447
vm_offset_t vaddr = (vm_offset_t) buf;
430448
int seg;
431449

@@ -482,74 +500,84 @@ int bus_dmamap_load_buffer(
482500
return ( buflen != 0 ? 27 : 0 );
483501
}
484502

485-
static int rpi_dma_init()
503+
int rpi_dma_init( int channel )
486504
{
487-
int i;
488505
struct bcm_dma_ch *ch;
489506
void *cb_virt;
490-
vm_paddr_t cb_phys;
507+
vm_paddr_t cb_phys = 0;
491508
int error, nsegs;
492509
vm_offset_t lastaddr;
510+
bus_dma_segment_t dm_segments[ 1 ];
493511

494512
/* Setup Initial Setting */
495-
for ( i = 0; i < BCM_DMA_CH_MAX; i++ ) {
496-
bus_dma_segment_t dm_segments[ 1 ];
497513

498-
ch = &bcm_dma_ch[ i ];
514+
/* Check the channel number provided */
515+
if ( channel < 0 || channel >= BCM_DMA_CH_MAX )
516+
return ( RTEMS_INVALID_ID );
499517

500-
bzero( ch, sizeof( struct bcm_dma_ch ) );
501-
ch->ch = i;
502-
ch->flags = BCM_DMA_CH_UNMAP;
518+
/* Check whether the channel is in use */
519+
if ( !( bcm_dma_ch[ channel ].flags & BCM_DMA_CH_USED ) )
520+
return ( RTEMS_RESOURCE_IN_USE );
503521

504-
ch->dma_map = malloc( sizeof( struct bus_dmamap ) );
522+
ch = &bcm_dma_ch[ channel ];
505523

506-
if ( ch->dma_map == NULL ) {
507-
return ENOMEM;
508-
}
524+
bzero( ch, sizeof( struct bcm_dma_ch ) );
525+
ch->ch = channel;
526+
ch->flags = BCM_DMA_CH_UNMAP;
509527

510-
/* Alignment = 1 , Boundary = 0 */
511-
cb_virt = rtems_cache_coherent_allocate(
512-
sizeof( struct bcm_dma_cb ), 1, 0 );
528+
ch->dma_map = malloc( sizeof( struct bus_dmamap ) );
513529

514-
if ( cb_virt == NULL ) {
515-
free( ch->dma_map );
530+
if ( ch->dma_map == NULL ) {
531+
return ENOMEM;
532+
}
516533

517-
return ENOMEM;
518-
}
534+
/* Alignment = 1 , Boundary = 0 */
535+
cb_virt = rtems_cache_aligned_malloc(
536+
sizeof( struct bcm_dma_cb ) );
519537

520-
ch->dma_map->buffer_begin = cb_virt;
521-
ch->dma_map->buffer_size = sizeof( struct bcm_dma_cb );
538+
if ( cb_virt == NULL ) {
539+
free( ch->dma_map );
522540

523-
memset( cb_virt, 0, sizeof( struct bcm_dma_cb ) );
541+
return ENOMEM;
542+
}
524543

525-
/*
526-
* Least alignment for busdma-allocated stuff is cache
527-
* line size, so just make sure nothing stupid happened
528-
* and we got properly aligned address
529-
*/
530-
if ( (unsigned long int) cb_virt & 0x1f )
531-
break;
544+
ch->dma_map->buffer_begin = cb_virt;
545+
ch->dma_map->buffer_size = sizeof( struct bcm_dma_cb );
532546

533-
//FIXME : Verify mapping buffer into bus space using the dmamap
534-
lastaddr = (vm_offset_t) 0;
535-
nsegs = 0;
547+
memset( cb_virt, 0, sizeof( struct bcm_dma_cb ) );
536548

537-
error = bus_dmamap_load_buffer( dm_segments, cb_virt,
538-
sizeof( struct bcm_dma_cb ), 0x00, &lastaddr, &nsegs, 1 );
549+
/*
550+
* Least alignment for busdma-allocated stuff is cache
551+
* line size, so just make sure nothing stupid happened
552+
* and we got properly aligned address
553+
*/
554+
if ( (unsigned long int) cb_virt & 0x1f )
555+
return RTEMS_UNSATISFIED;
539556

540-
if ( error == 0 )
541-
rpi_dmamap_cb( &cb_phys, dm_segments, nsegs + 1, 0 );
542-
else
543-
rpi_dmamap_cb( &cb_phys, NULL, 0, error );
557+
lastaddr = (vm_offset_t) 0;
558+
nsegs = 0;
544559

545-
ch->cb = cb_virt;
546-
ch->vc_cb = cb_phys;
547-
ch->flags = BCM_DMA_CH_FREE;
548-
ch->cb->info = INFO_WAIT_RESP;
560+
error = bus_dmamap_load_buffer( dm_segments, cb_virt,
561+
sizeof( struct bcm_dma_cb ), 0x00, &lastaddr, &nsegs, 1 );
549562

550-
/* reset DMA */
551-
BCM2835_REG( BCM_DMA_CS( i ) ) = CS_RESET;
552-
}
563+
if ( error == 0 )
564+
rpi_dmamap_cb( &cb_phys, dm_segments, nsegs + 1, 0 );
565+
else
566+
rpi_dmamap_cb( &cb_phys, NULL, 0, error );
567+
568+
ch->cb = cb_virt;
569+
ch->vc_cb = cb_phys;
570+
ch->flags = BCM_DMA_CH_FREE;
571+
ch->cb->info = INFO_WAIT_RESP;
572+
573+
rtems_interrupt_handler_install( BCM2835_IRQ_ID_DMA_CH0 + channel,
574+
"DMA copy",
575+
RTEMS_INTERRUPT_UNIQUE,
576+
rpi_dma_intr,
577+
NULL );
578+
579+
/* reset DMA */
580+
BCM2835_REG( BCM_DMA_CS( channel ) ) = CS_RESET;
553581

554582
return 0;
555583
}

0 commit comments

Comments
 (0)