[19260fb] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @ingroup lpc176x_dma |
---|
| 5 | * |
---|
| 6 | * @brief Direct memory access (DMA) support. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /* |
---|
| 10 | * Copyright (c) 2008, 2009 |
---|
| 11 | * embedded brains GmbH |
---|
| 12 | * Obere Lagerstr. 30 |
---|
| 13 | * D-82178 Puchheim |
---|
| 14 | * Germany |
---|
| 15 | * <rtems@embedded-brains.de> |
---|
| 16 | * |
---|
| 17 | * The license and distribution terms for this file may be |
---|
| 18 | * found in the file LICENSE in this distribution or at |
---|
[d4edbdbc] | 19 | * http://www.rtems.org/license/LICENSE. |
---|
[19260fb] | 20 | */ |
---|
| 21 | |
---|
| 22 | #include <bsp/lpc176x.h> |
---|
| 23 | #include <bsp/dma.h> |
---|
| 24 | #include <bsp/irq.h> |
---|
| 25 | |
---|
| 26 | static rtems_id lpc176x_dma_sema_table[ GPDMA_CH_NUMBER ]; |
---|
| 27 | static bool lpc176x_dma_status_table[ GPDMA_CH_NUMBER ]; |
---|
| 28 | |
---|
| 29 | static void lpc176x_dma_copy_handler( void *arg ) |
---|
| 30 | { |
---|
| 31 | /* Get interrupt status */ |
---|
| 32 | uint32_t tc = GPDMA_INT_TCSTAT; |
---|
| 33 | uint32_t err = GPDMA_INT_ERR_STAT; |
---|
| 34 | |
---|
| 35 | /* Clear interrupt status */ |
---|
| 36 | GPDMA_INT_TCCLR = tc; |
---|
| 37 | GPDMA_INT_ERR_CLR = err; |
---|
| 38 | |
---|
| 39 | if ( ( tc & GPDMA_STATUS_CH_0 ) != 0 ) { |
---|
| 40 | rtems_semaphore_release( lpc176x_dma_sema_table[ 0 ] ); |
---|
| 41 | } |
---|
| 42 | |
---|
| 43 | /* else implies that the channel is not the 0. Also, |
---|
| 44 | there is nothing to do. */ |
---|
| 45 | |
---|
| 46 | lpc176x_dma_status_table[ 0 ] = ( err & GPDMA_STATUS_CH_0 ) == 0; |
---|
| 47 | |
---|
| 48 | if ( ( tc & GPDMA_STATUS_CH_1 ) != 0 ) { |
---|
| 49 | rtems_semaphore_release( lpc176x_dma_sema_table[ 1 ] ); |
---|
| 50 | } |
---|
| 51 | |
---|
| 52 | /* else implies that the channel is not the 1. Also, |
---|
| 53 | there is nothing to do. */ |
---|
| 54 | |
---|
| 55 | lpc176x_dma_status_table[ 1 ] = ( err & GPDMA_STATUS_CH_1 ) == 0; |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | rtems_status_code lpc176x_dma_copy_initialize( void ) |
---|
| 59 | { |
---|
| 60 | rtems_status_code status_code = RTEMS_SUCCESSFUL; |
---|
| 61 | rtems_id id0 = RTEMS_ID_NONE; |
---|
| 62 | rtems_id id1 = RTEMS_ID_NONE; |
---|
| 63 | |
---|
| 64 | /* Create semaphore for channel 0 */ |
---|
| 65 | status_code = rtems_semaphore_create( rtems_build_name( 'D', 'M', 'A', '0' ), |
---|
| 66 | 0, |
---|
| 67 | RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, |
---|
| 68 | 0, |
---|
| 69 | &id0 ); |
---|
| 70 | |
---|
| 71 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 72 | return status_code; |
---|
| 73 | } |
---|
| 74 | |
---|
| 75 | /* else implies that the semaphore to the channel 0 was created succefully. |
---|
| 76 | Also, there is nothing to do. */ |
---|
| 77 | |
---|
| 78 | /* Create semaphore for channel 1 */ |
---|
| 79 | status_code = rtems_semaphore_create( rtems_build_name( 'D', 'M', 'A', '1' ), |
---|
| 80 | 0, |
---|
| 81 | RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, |
---|
| 82 | 0, |
---|
| 83 | &id1 ); |
---|
| 84 | |
---|
| 85 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 86 | rtems_semaphore_delete( id0 ); |
---|
| 87 | |
---|
| 88 | return status_code; |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | /* else implies that the semaphore to the channel 1 was created succefully. |
---|
| 92 | Also, there is nothing to do. */ |
---|
| 93 | |
---|
| 94 | /* Install DMA interrupt handler */ |
---|
| 95 | status_code = rtems_interrupt_handler_install( LPC176X_IRQ_DMA, |
---|
| 96 | "DMA copy", |
---|
| 97 | RTEMS_INTERRUPT_UNIQUE, |
---|
| 98 | lpc176x_dma_copy_handler, |
---|
| 99 | NULL ); |
---|
| 100 | |
---|
| 101 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 102 | rtems_semaphore_delete( id0 ); |
---|
| 103 | rtems_semaphore_delete( id1 ); |
---|
| 104 | |
---|
| 105 | return status_code; |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | /* else implies that the interrupt handler was installed succefully. Also, |
---|
| 109 | there is nothing to do. */ |
---|
| 110 | |
---|
| 111 | /* Initialize global data */ |
---|
| 112 | lpc176x_dma_sema_table[ 0 ] = id0; |
---|
| 113 | lpc176x_dma_sema_table[ 1 ] = id1; |
---|
| 114 | |
---|
| 115 | return RTEMS_SUCCESSFUL; |
---|
| 116 | } |
---|
| 117 | |
---|
| 118 | rtems_status_code lpc176x_dma_copy_release( void ) |
---|
| 119 | { |
---|
| 120 | rtems_status_code status_code = RTEMS_SUCCESSFUL; |
---|
| 121 | rtems_status_code status_code_aux = RTEMS_SUCCESSFUL; |
---|
| 122 | |
---|
| 123 | status_code = rtems_interrupt_handler_remove( LPC176X_IRQ_DMA, |
---|
| 124 | lpc176x_dma_copy_handler, |
---|
| 125 | NULL ); |
---|
| 126 | |
---|
| 127 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 128 | status_code_aux = status_code; |
---|
| 129 | } |
---|
| 130 | |
---|
| 131 | /* else implies that the interrupt handler was removed succefully. Also, |
---|
| 132 | there is nothing to do. */ |
---|
| 133 | |
---|
| 134 | status_code = rtems_semaphore_delete( lpc176x_dma_sema_table[ 0 ] ); |
---|
| 135 | |
---|
| 136 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 137 | status_code_aux = status_code; |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | /* else implies that the semaphore to the channel 0 was deleted succefully. |
---|
| 141 | Also, there is nothing to do. */ |
---|
| 142 | |
---|
| 143 | status_code = rtems_semaphore_delete( lpc176x_dma_sema_table[ 1 ] ); |
---|
| 144 | |
---|
| 145 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 146 | status_code_aux = status_code; |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | /* else implies that the semaphore to the channel 1 was deleted succefully. |
---|
| 150 | Also, there is nothing to do. */ |
---|
| 151 | |
---|
| 152 | return status_code_aux; |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | rtems_status_code lpc176x_dma_copy( |
---|
| 156 | unsigned channel, |
---|
| 157 | const void *const dest, |
---|
| 158 | const void *const src, |
---|
| 159 | size_t n, |
---|
| 160 | const size_t width |
---|
| 161 | ) |
---|
| 162 | { |
---|
| 163 | rtems_status_code status_code = RTEMS_SUCCESSFUL; |
---|
| 164 | volatile lpc176x_dma_channel *e = GPDMA_CH_BASE_ADDR( channel ); |
---|
| 165 | uint32_t w = GPDMA_CH_CTRL_W_8; |
---|
| 166 | |
---|
| 167 | switch ( width ) { |
---|
| 168 | case 4: |
---|
| 169 | w = GPDMA_CH_CTRL_W_32; |
---|
| 170 | break; |
---|
| 171 | case 2: |
---|
| 172 | w = GPDMA_CH_CTRL_W_16; |
---|
| 173 | break; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | n = n >> w; |
---|
| 177 | |
---|
| 178 | if ( n > 0 && n < 4096 ) { |
---|
| 179 | e->desc.src = (uint32_t) src; |
---|
| 180 | e->desc.dest = (uint32_t) dest; |
---|
| 181 | e->desc.lli = 0; |
---|
| 182 | e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ( 0, n ) | |
---|
| 183 | SET_GPDMA_CH_CTRL_SBSZ( 0, GPDMA_CH_CTRL_BSZ_1 ) | |
---|
| 184 | SET_GPDMA_CH_CTRL_DBSZ( 0, GPDMA_CH_CTRL_BSZ_1 ) | |
---|
| 185 | SET_GPDMA_CH_CTRL_SW( 0, w ) | |
---|
| 186 | SET_GPDMA_CH_CTRL_DW( 0, w ) | |
---|
| 187 | GPDMA_CH_CTRL_ITC | |
---|
| 188 | GPDMA_CH_CTRL_SI | |
---|
| 189 | GPDMA_CH_CTRL_DI; |
---|
| 190 | e->cfg = SET_GPDMA_CH_CFG_FLOW( 0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA ) | |
---|
| 191 | GPDMA_CH_CFG_IE | |
---|
| 192 | GPDMA_CH_CFG_ITC | |
---|
| 193 | GPDMA_CH_CFG_EN; |
---|
| 194 | } else { |
---|
| 195 | status_code = RTEMS_INVALID_SIZE; |
---|
| 196 | } |
---|
| 197 | |
---|
| 198 | return status_code; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | rtems_status_code lpc176x_dma_copy_wait( const unsigned channel ) |
---|
| 202 | { |
---|
| 203 | rtems_status_code status_code = RTEMS_SUCCESSFUL; |
---|
| 204 | |
---|
| 205 | status_code = rtems_semaphore_obtain( lpc176x_dma_sema_table[ channel ], |
---|
| 206 | RTEMS_WAIT, |
---|
| 207 | RTEMS_NO_TIMEOUT ); |
---|
| 208 | |
---|
| 209 | if ( status_code != RTEMS_SUCCESSFUL ) { |
---|
| 210 | return status_code; |
---|
| 211 | } |
---|
| 212 | |
---|
| 213 | /* else implies that the semaphore was obtained succefully. Also, |
---|
| 214 | there is nothing to do. */ |
---|
| 215 | |
---|
| 216 | status_code = lpc176x_dma_status_table[ channel ] |
---|
| 217 | ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR; |
---|
| 218 | |
---|
| 219 | return status_code; |
---|
| 220 | } |
---|