// #################################################################################################
// # << NEORV32: neorv32_dma.h - Direct Memory Access Controller (DMA) HW Driver >>                #
// # ********************************************************************************************* #
// # BSD 3-Clause License                                                                          #
// #                                                                                               #
// # Copyright (c) 2024, Stephan Nolting. All rights reserved.                                     #
// #                                                                                               #
// # Redistribution and use in source and binary forms, with or without modification, are          #
// # permitted provided that the following conditions are met:                                     #
// #                                                                                               #
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
// #    conditions and the following disclaimer.                                                   #
// #                                                                                               #
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
// #    conditions and the following disclaimer in the documentation and/or other materials        #
// #    provided with the distribution.                                                            #
// #                                                                                               #
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
// #    endorse or promote products derived from this software without specific prior written      #
// #    permission.                                                                                #
// #                                                                                               #
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
// # ********************************************************************************************* #
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
// #################################################################################################


/**********************************************************************//**
 * @file neorv32_dma.h
 * @brief Direct Memory Access Controller (DMA) HW driver header file.
 *
 * @note These functions should only be used if the DMA controller was synthesized (IO_DMA_EN = true).
 **************************************************************************/

#ifndef neorv32_dma_h
#define neorv32_dma_h

/**********************************************************************//**
 * @name IO Device: Direct Memory Access Controller (DMA)
 **************************************************************************/
/**@{*/
/** DMA module prototype */
typedef volatile struct __attribute__((packed,aligned(4))) {
  uint32_t CTRL;     /**< offset  0: control and status register (#NEORV32_DMA_CTRL_enum) */
  uint32_t SRC_BASE; /**< offset  4: source base address register */
  uint32_t DST_BASE; /**< offset  8: destination base address register */
  uint32_t TTYPE;    /**< offset 12: transfer type configuration register & manual trigger (#NEORV32_DMA_TTYPE_enum) */
} neorv32_dma_t;

/** DMA module hardware access (#neorv32_dma_t) */
#define NEORV32_DMA ((neorv32_dma_t*) (NEORV32_DMA_BASE))

/** DMA control and status register bits */
enum NEORV32_DMA_CTRL_enum {
  DMA_CTRL_EN            =  0, /**< DMA control register(0) (r/w): DMA enable */
  DMA_CTRL_AUTO          =  1, /**< DMA control register(1) (r/w): Automatic trigger mode enable */
  DMA_CTRL_FENCE         =  2, /**< DMA control register(2) (r/w): Issue FENCE downstream operation when DMA transfer is completed */

  DMA_CTRL_ERROR_RD      =  8, /**< DMA control register(8)  (r/-): Error during read access; SRC_BASE shows the faulting address */
  DMA_CTRL_ERROR_WR      =  9, /**< DMA control register(9)  (r/-): Error during write access; DST_BASE shows the faulting address */
  DMA_CTRL_BUSY          = 10, /**< DMA control register(10) (r/-): DMA busy / transfer in progress */
  DMA_CTRL_DONE          = 11, /**< DMA control register(11) (r/c): A transfer was executed when set */

  DMA_CTRL_FIRQ_MASK_LSB = 16, /**< DMA control register(16) (r/w): FIRQ trigger mask LSB */
  DMA_CTRL_FIRQ_MASK_MSB = 31  /**< DMA control register(31) (r/w): FIRQ trigger mask MSB */
};

/** DMA transfer type bits */
enum NEORV32_DMA_TTYPE_enum {
  DMA_TTYPE_NUM_LSB  =  0, /**< DMA transfer type register(0)  (r/w): Number of elements to transfer, LSB */
  DMA_TTYPE_NUM_MSB  = 23, /**< DMA transfer type register(23) (r/w): Number of elements to transfer, MSB */

  DMA_TTYPE_QSEL_LSB = 27, /**< DMA transfer type register(27) (r/w): Data quantity select, LSB */
  DMA_TTYPE_QSEL_MSB = 28, /**< DMA transfer type register(28) (r/w): Data quantity select, MSB */
  DMA_TTYPE_SRC_INC  = 29, /**< DMA transfer type register(29) (r/w): SRC constant (0) or incrementing (1) address */
  DMA_TTYPE_DST_INC  = 30, /**< DMA transfer type register(30) (r/w): SRC constant (0) or incrementing (1) address */
  DMA_TTYPE_ENDIAN   = 31  /**< DMA transfer type register(31) (r/w): Convert Endianness when set */
};
/**@}*/


/**********************************************************************//**
 * DMA transfer type commands
 **************************************************************************/
/**@{*/
#define DMA_CMD_B2B  (0b00 << DMA_TTYPE_QSEL_LSB) // byte to byte
#define DMA_CMD_B2UW (0b01 << DMA_TTYPE_QSEL_LSB) // byte to unsigned word
#define DMA_CMD_B2SW (0b10 << DMA_TTYPE_QSEL_LSB) // byte to signed word
#define DMA_CMD_W2W  (0b11 << DMA_TTYPE_QSEL_LSB) // word to word

#define DMA_CMD_SRC_CONST (0b0 << DMA_TTYPE_SRC_INC) // constant source address
#define DMA_CMD_SRC_INC   (0b1 << DMA_TTYPE_SRC_INC) // incrementing source address

#define DMA_CMD_DST_CONST (0b0 << DMA_TTYPE_DST_INC) // constant destination address
#define DMA_CMD_DST_INC   (0b1 << DMA_TTYPE_DST_INC) // incrementing destination address

#define DMA_CMD_ENDIAN (0b1 << DMA_TTYPE_ENDIAN) // convert endianness
/**@}*/


/**********************************************************************//**
 * DMA status
 **************************************************************************/
enum NEORV32_DMA_STATUS_enum {
  DMA_STATUS_ERR_WR = -2, /**< write access error during last transfer (-2) */
  DMA_STATUS_ERR_RD = -1, /**< read access error during last transfer (-1) */
  DMA_STATUS_IDLE   =  0, /**< DMA idle (0) */
  DMA_STATUS_BUSY   =  1  /**< DMA busy (1) */
};


/**********************************************************************//**
 * @name Prototypes
 **************************************************************************/
/**@{*/
int  neorv32_dma_available(void);
void neorv32_dma_enable(void);
void neorv32_dma_disable(void);
void neorv32_dma_fence_enable(void);
void neorv32_dma_fence_disable(void);
void neorv32_dma_transfer(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config);
void neorv32_dma_transfer_auto(uint32_t base_src, uint32_t base_dst, uint32_t num, uint32_t config, uint32_t firq_mask);
int  neorv32_dma_status(void);
int  neorv32_dma_done(void);
/**@}*/


#endif // neorv32_dma_h
