summaryrefslogtreecommitdiffstats
path: root/bsps/arm/lpc24xx/start/dma-copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/lpc24xx/start/dma-copy.c')
-rw-r--r--bsps/arm/lpc24xx/start/dma-copy.c194
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;
+}