9
9
#include <bsp.h>
10
10
#include <bsp/raspberrypi.h>
11
11
#include <bsp/dma.h>
12
+ #include <bsp/irq.h>
12
13
#include <stdlib.h>
13
14
#include <errno.h>
14
15
64
65
* @brief Table that indicates if a channel is currently occupied.
65
66
*/
66
67
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
+ );
68
80
69
81
static void rpi_dmamap_cb (
70
82
void * arg ,
@@ -124,7 +136,7 @@ rtems_status_code rpi_dma_reset( int ch )
124
136
/* Reset control block */
125
137
cb = bcm_dma_ch [ ch ].cb ;
126
138
bzero ( cb , sizeof ( * cb ) );
127
- cb -> info - INFO_WAIT_RESP ;
139
+ cb -> info = INFO_WAIT_RESP ;
128
140
129
141
return RTEMS_SUCCESSFUL ;
130
142
}
@@ -138,10 +150,9 @@ rtems_status_code rpi_dma_allocate( int req_ch )
138
150
if ( req_ch >= BCM_DMA_CH_MAX )
139
151
return ( RTEMS_INVALID_ID );
140
152
141
- if ( _Atomic_Flag_test_and_set ( & dma_mutex ,
153
+ if ( _Atomic_Flag_test_and_set ( & bcm_dma_ch [ req_ch ]. dma_lock ,
142
154
ATOMIC_ORDER_ACQUIRE ) != 0 ) {
143
- printk ( "Could not lock the DMA mutex\n" );
144
- return RTEMS_UNSATISFIED ;
155
+ return RTEMS_RESOURCE_IN_USE ;
145
156
}
146
157
147
158
/* 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 )
152
163
return ( RTEMS_RESOURCE_IN_USE );
153
164
}
154
165
155
- _Atomic_Flag_clear ( & dma_mutex , ATOMIC_ORDER_RELEASE );
166
+ _Atomic_Flag_clear ( & bcm_dma_ch [ req_ch ]. dma_lock , ATOMIC_ORDER_RELEASE );
156
167
157
168
return ( RTEMS_SUCCESSFUL );
158
169
}
@@ -162,12 +173,11 @@ rtems_status_code rpi_dma_allocate( int req_ch )
162
173
*/
163
174
rtems_status_code rpi_dma_free ( int ch )
164
175
{
165
- rtems_status_code status_code ;
176
+ rtems_status_code status_code = RTEMS_SUCCESSFUL ;
166
177
167
- if ( _Atomic_Flag_test_and_set ( & dma_mutex ,
178
+ if ( _Atomic_Flag_test_and_set ( & bcm_dma_ch [ ch ]. dma_lock ,
168
179
ATOMIC_ORDER_ACQUIRE ) != 0 ) {
169
- printk ( "Could not lock the DMA mutex\n" );
170
- return RTEMS_UNSATISFIED ;
180
+ return RTEMS_RESOURCE_IN_USE ;
171
181
}
172
182
173
183
/* Check the channel number provided */
@@ -185,7 +195,11 @@ rtems_status_code rpi_dma_free( int ch )
185
195
status_code = rpi_dma_reset ( ch );
186
196
}
187
197
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 );
189
203
190
204
return ( status_code );
191
205
}
@@ -381,6 +395,10 @@ rtems_status_code rpi_dma_start(
381
395
(void * ) bcm_dma_ch [ ch ].dma_map -> buffer_begin ,
382
396
bcm_dma_ch [ ch ].dma_map -> buffer_size );
383
397
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
+
384
402
/* Write the physical address of the control block into the register */
385
403
BCM2835_REG ( BCM_DMA_CBADDR ( ch ) ) = bcm_dma_ch [ ch ].vc_cb ;
386
404
@@ -425,7 +443,7 @@ int bus_dmamap_load_buffer(
425
443
)
426
444
{
427
445
unsigned int sgsize ;
428
- unsigned int curaddr , lastaddr , baddr , bmask ;
446
+ unsigned int curaddr , lastaddr , bmask ;
429
447
vm_offset_t vaddr = (vm_offset_t ) buf ;
430
448
int seg ;
431
449
@@ -482,74 +500,84 @@ int bus_dmamap_load_buffer(
482
500
return ( buflen != 0 ? 27 : 0 );
483
501
}
484
502
485
- static int rpi_dma_init ()
503
+ int rpi_dma_init ( int channel )
486
504
{
487
- int i ;
488
505
struct bcm_dma_ch * ch ;
489
506
void * cb_virt ;
490
- vm_paddr_t cb_phys ;
507
+ vm_paddr_t cb_phys = 0 ;
491
508
int error , nsegs ;
492
509
vm_offset_t lastaddr ;
510
+ bus_dma_segment_t dm_segments [ 1 ];
493
511
494
512
/* Setup Initial Setting */
495
- for ( i = 0 ; i < BCM_DMA_CH_MAX ; i ++ ) {
496
- bus_dma_segment_t dm_segments [ 1 ];
497
513
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 );
499
517
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 ) ;
503
521
504
- ch -> dma_map = malloc ( sizeof ( struct bus_dmamap ) ) ;
522
+ ch = & bcm_dma_ch [ channel ] ;
505
523
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 ;
509
527
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 ) );
513
529
514
- if ( cb_virt == NULL ) {
515
- free ( ch -> dma_map );
530
+ if ( ch -> dma_map == NULL ) {
531
+ return ENOMEM ;
532
+ }
516
533
517
- return ENOMEM ;
518
- }
534
+ /* Alignment = 1 , Boundary = 0 */
535
+ cb_virt = rtems_cache_aligned_malloc (
536
+ sizeof ( struct bcm_dma_cb ) );
519
537
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 );
522
540
523
- memset ( cb_virt , 0 , sizeof ( struct bcm_dma_cb ) );
541
+ return ENOMEM ;
542
+ }
524
543
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 );
532
546
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 ) );
536
548
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 ;
539
556
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 ;
544
559
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 );
549
562
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 ;
553
581
554
582
return 0 ;
555
583
}
0 commit comments