You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/06/16 17:23:28 UTC
[incubator-nuttx] branch master updated: risc-v/mpfs: add dma
support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 673f951 risc-v/mpfs: add dma support
673f951 is described below
commit 673f9519eb84a3a6ec2c5a16424e1b5d383ac216
Author: Janne Rosberg <ja...@offcode.fi>
AuthorDate: Fri May 28 18:27:01 2021 +0300
risc-v/mpfs: add dma support
---
arch/risc-v/src/mpfs/Kconfig | 10 +-
arch/risc-v/src/mpfs/Make.defs | 4 +
arch/risc-v/src/mpfs/hardware/mpfs_dma.h | 136 +++++++
arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h | 3 +-
arch/risc-v/src/mpfs/mpfs_dma.c | 516 +++++++++++++++++++++++++
arch/risc-v/src/mpfs/mpfs_dma.h | 93 +++++
6 files changed, 760 insertions(+), 2 deletions(-)
diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig
index 44bb9f3..dc8ced7 100755
--- a/arch/risc-v/src/mpfs/Kconfig
+++ b/arch/risc-v/src/mpfs/Kconfig
@@ -105,7 +105,15 @@ config MPFS_I2C1
endmenu
-menu "MPFS Others"
+config MPFS_DMA
+ bool "MPFS DMA (PDMA)"
+ default n
+ select ARCH_DMA
+ ---help---
+ Enable DMA Support. MPFS DMA is Memory-to-Memory only.
+menu "MPFS Others"
endmenu
+
+
diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs
index 5582815..35bbc00 100755
--- a/arch/risc-v/src/mpfs/Make.defs
+++ b/arch/risc-v/src/mpfs/Make.defs
@@ -54,6 +54,10 @@ CHIP_CSRCS += mpfs_lowputc.c mpfs_serial.c
CHIP_CSRCS += mpfs_start.c mpfs_timerisr.c
CHIP_CSRCS += mpfs_gpio.c mpfs_systemreset.c
+ifeq ($(CONFIG_MPFS_DMA),y)
+CHIP_CSRCS += mpfs_dma.c
+endif
+
ifeq ($(CONFIG_BUILD_PROTECTED),y)
CMN_CSRCS += riscv_task_start.c riscv_pthread_start.c
CMN_CSRCS += riscv_signal_dispatch.c riscv_pmp.c
diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_dma.h b/arch/risc-v/src/mpfs/hardware/mpfs_dma.h
new file mode 100755
index 0000000..4226529
--- /dev/null
+++ b/arch/risc-v/src/mpfs/hardware/mpfs_dma.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/hardware/mpfs_dma.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_DMA_H
+#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_DMA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/mpfs_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define MPFS_DMA_CONTROL_OFFSET 0x0000 /* Channel control register */
+#define MPFS_DMA_NEXT_CONFIG_OFFSET 0x0004 /* Next transfer type */
+#define MPFS_DMA_NEXT_BYTES_OFFSET 0x0008 /* Number of bytes to move */
+#define MPFS_DMA_NEXT_DESTINATION_OFFSET 0x0010 /* Destination start address */
+#define MPFS_DMA_NEXT_SOURCE_OFFSET 0x0018 /* Source start address */
+#define MPFS_DMA_EXEC_CONFIG_OFFSET 0x0104 /* Active transfer type */
+#define MPFS_DMA_EXEC_BYTES_OFFSET 0x0108 /* Number of bytes remaining */
+#define MPFS_DMA_EXEC_DESTINATION_OFFSET 0x0110 /* Destination current address */
+#define MPFS_DMA_EXEC_SOURCE_OFFSET 0x0118 /* Source current address */
+
+#define MPFS_DMA_CHANNEL_OFFSET 0x1000 /* Offset to channels */
+
+#define MPFS_DMA_REG_OFFSET(x) \
+ (uint64_t)(MPFS_PDMA_BASE + (MPFS_DMA_CHANNEL_OFFSET * (x)))
+
+/* Register bit field definitions *******************************************/
+
+/* Control register */
+
+/* Indicates that the channel is in use. Setting this bit clears all of the
+ * channel’s Next registers (NextConfig, NextBytes, NextDestination, and
+ * NextSource). This bit can only be cleared when run (CR bit 0) is low.
+ */
+
+#define DMA_CONTROL_CLAIM_SHIFT (0) /* Bit: 0: claim */
+#define DMA_CONTROL_CLAIM_MASK (1 << DMA_CONTROL_CLAIM_SHIFT)
+# define DMA_CONTROL_CLAIM (0 << DMA_CONTROL_CLAIM_SHIFT)
+
+/* Setting this bit starts a DMA transfer by copying the Next registers
+ * into their Exec counterparts.
+ */
+
+#define DMA_CONTROL_RUN_SHIFT (1) /* Bit: 1: run */
+#define DMA_CONTROL_RUN_MASK (1 << DMA_CONTROL_RUN_SHIFT)
+# define DMA_CONTROL_RUN (1 << DMA_CONTROL_RUN_SHIFT)
+
+/* Setting this bit will trigger the channel’s Done interrupt once
+ * a transfer is complete.
+ */
+
+#define DMA_CONTROL_DONEIE_SHIFT (14) /* Bit: 14: Done Irq enable */
+#define DMA_CONTROL_DONEIE_MASK (1 << DMA_CONTROL_DONEIE_SHIFT)
+# define DMA_CONTROL_DONEIE (1 << DMA_CONTROL_DONEIE_SHIFT)
+
+/* Setting this bit will trigger the channel’s Done interrupt once
+ * a transfer is complete.
+ */
+
+#define DMA_CONTROL_ERRORIE_SHIFT (15) /* Bit: 15: Error Irq enable */
+#define DMA_CONTROL_ERRORIE_MASK (1 << DMA_CONTROL_ERRORIE_SHIFT)
+# define DMA_CONTROL_ERRORIE (1 << DMA_CONTROL_ERRORIE_SHIFT)
+
+/* Indicates that a transfer has completed since the channel was claimed */
+
+#define DMA_CONTROL_DONE_SHIFT (30) /* Bit: 30: Done */
+#define DMA_CONTROL_DONE_MASK (1 << DMA_CONTROL_DONE_SHIFT)
+# define DMA_CONTROL_DONE (1 << DMA_CONTROL_DONE_SHIFT)
+
+/* Indicates that a transfer error has occurred since the channel
+ * was claimed
+ */
+
+#define DMA_CONTROL_ERROR_SHIFT (31) /* Bit: 31: Error */
+#define DMA_CONTROL_ERROR_MASK (1 << DMA_CONTROL_ERROR_SHIFT)
+# define DMA_CONTROL_ERROR (1 << DMA_CONTROL_ERROR_SHIFT)
+
+/* Channel Next Configuration Register */
+
+/* If set, the Exec registers are reloaded from the Next registers once a
+ * transfer is complete. The repeat bit must be cleared by software
+ * for the sequence to stop
+ */
+
+#define DMA_NEXT_CONFIG_REPEAT_SHIFT (2) /* Bit: 2: repeat */
+#define DMA_NEXT_CONFIG_REPEAT_MASK (1 << DMA_NEXT_CONFIG_REPEAT_SHIFT)
+# define DMA_NEXT_CONFIG_REPEAT (1 << DMA_NEXT_CONFIG_REPEAT_SHIFT)
+
+/* Enforces strict ordering by only allowing one of each transfer type
+ * in-flight at a time
+ */
+
+#define DMA_NEXT_CONFIG_ORDER_SHIFT (3) /* Bit: 3: order */
+#define DMA_NEXT_CONFIG_ORDER_MASK (1 << DMA_NEXT_CONFIG_ORDER_SHIFT)
+# define DMA_NEXT_CONFIG_ORDER (1 << DMA_NEXT_CONFIG_ORDER_SHIFT)
+
+/* WSIZE and RSIZE. Base 2 Logarithm of DMA transaction sizes.
+ * Example: 0 is 1 byte, 3 is 8 bytes, 5 is 32 bytes
+ * These fields are WARL (Write-Any Read-Legal), so the actual size used
+ * can be determined by reading the field after writing the requested size.
+ * */
+
+#define DMA_NEXT_CONFIG_WSIZE_SHIFT (24) /* Bits: 24-27: write size */
+#define DMA_NEXT_CONFIG_WSIZE_MASK (15 << DMA_NEXT_CONFIG_WSIZE_SHIFT)
+# define DMA_NEXT_CONFIG_WSIZE(x) (x << DMA_NEXT_CONFIG_WSIZE_SHIFT)
+
+#define DMA_NEXT_CONFIG_RSIZE_SHIFT (28) /* Bits: 28-31: read size */
+#define DMA_NEXT_CONFIG_RSIZE_MASK (15 << DMA_NEXT_CONFIG_RSIZE_SHIFT)
+# define DMA_NEXT_CONFIG_RSIZE(x) (x << DMA_NEXT_CONFIG_RSIZE_SHIFT)
+
+#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_DMA_H */
diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h
index 4d07554..ff7c0e6 100755
--- a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h
+++ b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h
@@ -27,8 +27,9 @@
/* Register Base Address ****************************************************/
-#define MPFS_PLIC_BASE (0x0C000000UL)
#define MPFS_CLINT_BASE (0x02000000UL)
+#define MPFS_PDMA_BASE (0x03000000UL)
+#define MPFS_PLIC_BASE (0x0C000000UL)
#define MPFS_UART0_LO_BASE (0x20000000UL)
#define MPFS_WDOG0_LO_BASE (0x20001000UL)
diff --git a/arch/risc-v/src/mpfs/mpfs_dma.c b/arch/risc-v/src/mpfs/mpfs_dma.c
new file mode 100755
index 0000000..d2454c5
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_dma.c
@@ -0,0 +1,516 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_dma.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <arch/board/board.h>
+
+#include "riscv_arch.h"
+#include "hardware/mpfs_dma.h"
+#include "mpfs_dma.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define DMA_MAX_TRANSACTION_SIZE (0x0f)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uint8_t g_channel_nextcfg_wsize[MPFS_DMA_NUM_CHANNELS] =
+{
+ DMA_MAX_TRANSACTION_SIZE, DMA_MAX_TRANSACTION_SIZE,
+ DMA_MAX_TRANSACTION_SIZE, DMA_MAX_TRANSACTION_SIZE
+};
+
+static uint8_t g_channel_nextcfg_rsize[MPFS_DMA_NUM_CHANNELS] =
+{
+ DMA_MAX_TRANSACTION_SIZE, DMA_MAX_TRANSACTION_SIZE,
+ DMA_MAX_TRANSACTION_SIZE, DMA_MAX_TRANSACTION_SIZE
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpfs_dma_setup_transfer
+ *
+ * Description:
+ * Set DMA transfer config for channel.
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ * config - Pointer to the config structure.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int mpfs_dma_setup_transfer(unsigned int channel,
+ struct mpfs_dma_channel_config *config)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel");
+ return -EINVAL;
+ }
+
+ if (config->src_addr == 0)
+ {
+ dmawarn("Illegal source address\n");
+ return -EINVAL;
+ }
+
+ if (config->dest_addr == 0)
+ {
+ dmawarn("Illegal destination address\n");
+ return -EINVAL;
+ }
+
+ /* If transaction is in progress, return error. */
+
+ if (getreg32(MPFS_DMA_REG_OFFSET(channel)) & DMA_CONTROL_RUN_MASK)
+ {
+ dmawarn("channel busy\n");
+ return -EBUSY;
+ }
+
+ /* Set or clear the interrupts for the transfer. */
+
+ if (config->enable_done_int)
+ {
+ dmainfo("enable done irq\n");
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ 0, DMA_CONTROL_DONEIE);
+ }
+ else
+ {
+ dmainfo("disable done irq\n");
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ DMA_CONTROL_DONEIE_MASK, 0);
+ }
+
+ if (config->enable_err_int)
+ {
+ dmainfo("enable err irq\n");
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ 0, DMA_CONTROL_ERRORIE);
+ }
+ else
+ {
+ dmainfo("disable err irq\n");
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ DMA_CONTROL_ERRORIE_MASK, 0);
+ }
+
+ /* clear Next registers. */
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ 0, DMA_CONTROL_CLAIM);
+
+ /* clear Done and Error */
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ DMA_CONTROL_DONE_MASK | DMA_CONTROL_ERROR_MASK, 0);
+
+ /* Setup the source and destination addresses. */
+
+ putreg64(config->dest_addr,
+ MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_DESTINATION_OFFSET);
+ putreg64(config->src_addr,
+ MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_SOURCE_OFFSET);
+
+ /* Set the transfer size. */
+
+ putreg64(config->num_bytes,
+ MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_BYTES_OFFSET);
+
+ /* Setup repeat and force order requirements. */
+
+ if (config->repeat)
+ {
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ 0, DMA_NEXT_CONFIG_REPEAT);
+ }
+ else
+ {
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ DMA_NEXT_CONFIG_REPEAT_MASK, 0);
+ }
+
+ if (config->force_order)
+ {
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ 0, DMA_NEXT_CONFIG_ORDER);
+ }
+ else
+ {
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ DMA_NEXT_CONFIG_ORDER_MASK, 0);
+ }
+
+ /* Set PDMA transaction size to maximum. */
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ DMA_NEXT_CONFIG_WSIZE_MASK,
+ DMA_NEXT_CONFIG_WSIZE(g_channel_nextcfg_wsize[channel]));
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_NEXT_CONFIG_OFFSET,
+ DMA_NEXT_CONFIG_RSIZE_MASK,
+ DMA_NEXT_CONFIG_RSIZE(g_channel_nextcfg_wsize[channel]));
+
+ dmainfodumpbuffer("dma regs", (uint8_t *)MPFS_DMA_REG_OFFSET(channel),
+ MPFS_DMA_NEXT_SOURCE_OFFSET + 8);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_set_transaction_size
+ *
+ * Description:
+ * Set read and write transaction size for mpfs_dma_setup_transfer()
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ * write_size - Write transaction size
+ * read_size - Read transaction size
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int mpfs_dma_set_transaction_size(unsigned int channel,
+ uint8_t write_size, uint8_t read_size)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return -EINVAL;
+ }
+
+ if (write_size > DMA_MAX_TRANSACTION_SIZE)
+ {
+ dmawarn("Illegal write size\n");
+ return -EINVAL;
+ }
+
+ if (read_size > DMA_MAX_TRANSACTION_SIZE)
+ {
+ dmawarn("Illegal write size\n");
+ return -EINVAL;
+ }
+
+ dmainfo("new default dma transaction size. channel:%d write:%d, read:%d\n",
+ channel, write_size, read_size);
+ g_channel_nextcfg_wsize[channel] = write_size;
+ g_channel_nextcfg_rsize[channel] = read_size;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_start
+ *
+ * Description:
+ * Start DMA transfer.
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int mpfs_dma_start(unsigned int channel)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return -EINVAL;
+ }
+
+ dmainfo("start dma channel:%d\n", channel);
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ 0, DMA_CONTROL_RUN);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_transfer_type
+ *
+ * Description:
+ * Return channels active config.
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * 0 - Illegal channel
+ * bit 2 - Repeat
+ * bit 3 - Strict ordering
+ *
+ ****************************************************************************/
+
+uint32_t mpfs_dma_get_transfer_type(unsigned int channel)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ return getreg32(MPFS_DMA_REG_OFFSET(channel) +
+ MPFS_DMA_EXEC_CONFIG_OFFSET);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_bytes_remaining
+ *
+ * Description:
+ * Return number of bytes remaining on transfer.
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * Number of bytes remaining
+ *
+ ****************************************************************************/
+
+uint64_t mpfs_dma_get_bytes_remaining(unsigned int channel)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ return getreg64(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_EXEC_BYTES_OFFSET);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_current_dest
+ *
+ * Description:
+ * Return current destination address of transfer
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * Current destination address
+ *
+ ****************************************************************************/
+
+uint64_t mpfs_dma_get_current_destination(unsigned int channel)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ return getreg64(MPFS_DMA_REG_OFFSET(channel) +
+ MPFS_DMA_EXEC_DESTINATION_OFFSET);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_current_source
+ *
+ * Description:
+ * Return current sourceaddress of transfer
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * Current source address
+ *
+ ****************************************************************************/
+
+uint64_t mpfs_dma_get_current_source(unsigned int channel)
+{
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ return getreg64(MPFS_DMA_REG_OFFSET(channel) +
+ MPFS_DMA_EXEC_SOURCE_OFFSET);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_complete_status
+ *
+ * Description:
+ * Return complete status for DMA channel
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * 0 - Not completed
+ * 1 - Transfer completed
+ *
+ ****************************************************************************/
+
+int mpfs_dma_get_complete_status(unsigned int channel)
+{
+ uint32_t control;
+
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ control = getreg32(MPFS_DMA_REG_OFFSET(channel) +
+ MPFS_DMA_CONTROL_OFFSET);
+
+ return ((control & DMA_CONTROL_DONE_MASK) >> DMA_CONTROL_DONE_SHIFT);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_get_error_status
+ *
+ * Description:
+ * Return error status for DMA channel
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * 0 - No Error
+ * 1 - Transfer Errror
+ *
+ ****************************************************************************/
+
+int mpfs_dma_get_error_status(unsigned int channel)
+{
+ uint32_t control;
+
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ control = getreg32(MPFS_DMA_REG_OFFSET(channel) +
+ MPFS_DMA_CONTROL_OFFSET);
+
+ return ((control & DMA_CONTROL_ERROR_MASK) >> DMA_CONTROL_ERROR_SHIFT);
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_clear_complete_status
+ *
+ * Description:
+ * Clear and return complete status for DMA channel
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * 0 - Not completed
+ * 1 - Transfer completed
+ *
+ ****************************************************************************/
+
+int mpfs_dma_clear_complete_status(unsigned int channel)
+{
+ int status = 0;
+ uint32_t control;
+
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ control = getreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET);
+ if (control & DMA_CONTROL_DONE)
+ {
+ status = 1;
+ }
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ DMA_CONTROL_DONE_MASK, 0);
+
+ return status;
+}
+
+/****************************************************************************
+ * Name: mpfs_dma_clear_error_status
+ *
+ * Description:
+ * Clear and return error status for DMA channel
+ *
+ * Parameters:
+ * channel - Channel number 0-3
+ *
+ * Returned Value:
+ * 0 - No Error
+ * 1 - Transfer Errror
+ *
+ ****************************************************************************/
+
+int mpfs_dma_clear_error_status(unsigned int channel)
+{
+ int status = 0;
+ uint32_t control;
+
+ if (channel >= MPFS_DMA_NUM_CHANNELS)
+ {
+ dmawarn("Illegal channel\n");
+ return 0;
+ }
+
+ control = getreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET);
+ if (control & DMA_CONTROL_ERROR)
+ {
+ status = 1;
+ }
+
+ modifyreg32(MPFS_DMA_REG_OFFSET(channel) + MPFS_DMA_CONTROL_OFFSET,
+ DMA_CONTROL_ERROR, 0);
+
+ return status;
+}
diff --git a/arch/risc-v/src/mpfs/mpfs_dma.h b/arch/risc-v/src/mpfs/mpfs_dma.h
new file mode 100755
index 0000000..7f401a7
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_dma.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_dma.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_DMA_H
+#define __ARCH_RISCV_SRC_MPFS_MPFS_DMA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include "mpfs_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MPFS_DMA_NUM_CHANNELS (4)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+struct mpfs_dma_channel_config
+{
+ uint64_t src_addr; /* source address */
+ uint64_t dest_addr; /* destination address */
+ uint64_t num_bytes; /* Number of bytes to be transfered. (Base-2) */
+ uint8_t enable_done_int; /* enable transfer complete interrupt */
+ uint8_t enable_err_int; /* enable transfer error interrupt */
+ uint8_t repeat; /* repeat the transaction */
+ uint8_t force_order; /* Enforces strict ordering by only
+ * allowing one of each transfer type
+ * in-flight at a time */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+EXTERN int mpfs_dma_setup_transfer(unsigned int channel,
+ struct mpfs_dma_channel_config *config);
+EXTERN int mpfs_dma_set_transaction_size(unsigned int channel,
+ uint8_t write_size,
+ uint8_t read_size);
+EXTERN int mpfs_dma_start(unsigned int channel);
+EXTERN uint32_t mpfs_dma_get_transfer_type(unsigned int channel);
+EXTERN uint64_t mpfs_dma_get_bytes_remaining(unsigned int channel);
+EXTERN uint64_t mpfs_dma_get_current_destination(unsigned int channel);
+EXTERN uint64_t mpfs_dma_get_current_source(unsigned int channel);
+EXTERN int mpfs_dma_get_complete_status(unsigned int channel);
+EXTERN int mpfs_dma_get_error_status(unsigned int channel);
+EXTERN int mpfs_dma_clear_complete_status(unsigned int channel);
+EXTERN int mpfs_dma_clear_error_status(unsigned int channel);
+
+#if defined(__cplusplus)
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_DMA_H */