diff options
Diffstat (limited to 'bsps/arm/lpc24xx/start/dma-copy.c')
-rw-r--r-- | bsps/arm/lpc24xx/start/dma-copy.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/bsps/arm/lpc24xx/start/dma-copy.c b/bsps/arm/lpc24xx/start/dma-copy.c new file mode 100644 index 0000000000..73a8cdc3ab --- /dev/null +++ b/bsps/arm/lpc24xx/start/dma-copy.c @@ -0,0 +1,194 @@ +/** + * @file + * + * @ingroup lpc24xx_dma + * + * @brief Direct memory access (DMA) support. + */ + +/* + * Copyright (c) 2008, 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp/lpc24xx.h> +#include <bsp/dma.h> +#include <bsp/irq.h> + +static rtems_id lpc24xx_dma_sema_table [GPDMA_CH_NUMBER]; + +static bool lpc24xx_dma_status_table [GPDMA_CH_NUMBER]; + +static void lpc24xx_dma_copy_handler(void *arg) +{ + /* Get interrupt status */ + uint32_t tc = GPDMA_INT_TCSTAT; + uint32_t err = GPDMA_INT_ERR_STAT; + + /* Clear interrupt status */ + GPDMA_INT_TCCLR = tc; + GPDMA_INT_ERR_CLR = err; + + /* Check channel 0 */ + if ((tc & GPDMA_STATUS_CH_0) != 0) { + rtems_semaphore_release(lpc24xx_dma_sema_table [0]); + } + lpc24xx_dma_status_table [0] = (err & GPDMA_STATUS_CH_0) == 0; + + /* Check channel 1 */ + if ((tc & GPDMA_STATUS_CH_1) != 0) { + rtems_semaphore_release(lpc24xx_dma_sema_table [1]); + } + lpc24xx_dma_status_table [1] = (err & GPDMA_STATUS_CH_1) == 0; +} + +rtems_status_code lpc24xx_dma_copy_initialize(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_id id0 = RTEMS_ID_NONE; + rtems_id id1 = RTEMS_ID_NONE; + + /* Create semaphore for channel 0 */ + sc = rtems_semaphore_create( + rtems_build_name('D', 'M', 'A', '0'), + 0, + RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &id0 + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Create semaphore for channel 1 */ + sc = rtems_semaphore_create( + rtems_build_name('D', 'M', 'A', '1'), + 0, + RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &id1 + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_semaphore_delete(id0); + + return sc; + } + + /* Install DMA interrupt handler */ + sc = rtems_interrupt_handler_install( + LPC24XX_IRQ_DMA, + "DMA copy", + RTEMS_INTERRUPT_UNIQUE, + lpc24xx_dma_copy_handler, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_semaphore_delete(id0); + rtems_semaphore_delete(id1); + + return sc; + } + + /* Initialize global data */ + lpc24xx_dma_sema_table [0] = id0; + lpc24xx_dma_sema_table [1] = id1; + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_dma_copy_release(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_status_code rsc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_remove( + LPC24XX_IRQ_DMA, + lpc24xx_dma_copy_handler, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [0]); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [1]); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + return rsc; +} + +rtems_status_code lpc24xx_dma_copy( + unsigned channel, + void *dest, + const void *src, + size_t n, + size_t width +) +{ + volatile lpc24xx_dma_channel *e = GPDMA_CH_BASE_ADDR(channel); + uint32_t w = GPDMA_CH_CTRL_W_8; + + switch (width) { + case 4: + w = GPDMA_CH_CTRL_W_32; + break; + case 2: + w = GPDMA_CH_CTRL_W_16; + break; + } + + n = n >> w; + + if (n > 0U && n < 4096U) { + e->desc.src = (uint32_t) src; + e->desc.dest = (uint32_t) dest; + e->desc.lli = 0; + e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) + | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_1) + | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_1) + | SET_GPDMA_CH_CTRL_SW(0, w) + | SET_GPDMA_CH_CTRL_DW(0, w) + | GPDMA_CH_CTRL_ITC + | GPDMA_CH_CTRL_SI + | GPDMA_CH_CTRL_DI; + e->cfg = SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA) + | GPDMA_CH_CFG_IE + | GPDMA_CH_CFG_ITC + | GPDMA_CH_CFG_EN; + } else { + return RTEMS_INVALID_SIZE; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_dma_copy_wait(unsigned channel) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_semaphore_obtain( + lpc24xx_dma_sema_table [channel], + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return lpc24xx_dma_status_table [channel] + ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR; +} |