/**
******************************************************************************
 * @file    kpm32xx_ddl_dma.h
 * @author  Kiwi Software Team
 * @brief   Header file of DMA DDL module.
 * @note
 *          V1.0.0, 2024/12/20.
 *
 * Copyright (c) 2024, Kiwi Instruments Co., Ltd.
 *
 * 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.
 ******************************************************************************
 */


#ifndef __KPM32xx_DDL_DMA_H
#define __KPM32xx_DDL_DMA_H

#ifdef __cplusplus
extern "C" {
#endif

#include "kpm32xx_ddl_def.h"


/* DMA priority levels */
#define DMA_PRIORITY_NORMAL          0x00000000U      /* priority level: Low       */
#define DMA_PRIORITY_HIGH            0x00000001U      /* priority level: High      */

/* DMA peripheral/memory data size */
#define DMA_DATAALIGN_BYTE           DMA_CHCTRL_DATASIZE_BYTE           /* Peripheral data alignment: Byte     */
#define DMA_DATAALIGN_HALFWORD       DMA_CHCTRL_DATASIZE_HALFWORD       /* Peripheral data alignment: HalfWord */
#define DMA_DATAALIGN_WORD           DMA_CHCTRL_DATASIZE_WORD           /* Peripheral data alignment: Word     */

/* DMA transmit type */
#define DMA_TRANSMIT_INVALID         DMA_CHCTRL_TRANSMITTYPE_INVAL      /* invalid transmit type                */
#define DMA_TRANSMIT_NORMAL          DMA_CHCTRL_TRANSMITTYPE_NORMAL     /* basic transmit type, for P2M and M2P */
#define DMA_TRANSMIT_AUTO            DMA_CHCTRL_TRANSMITTYPE_AUTO       /* auto request transmit type, for M2M  */

/* DMA arbitration time */
#define DMA_ARBIT_INTERVAL_1         DMA_CHCTRL_INTERVAL_ONE            /* after one DMA transmit   */
#define DMA_ARBIT_INTERVAL_2         DMA_CHCTRL_INTERVAL_TWO            /* after two DMA transmit   */
#define DMA_ARBIT_INTERVAL_4         DMA_CHCTRL_INTERVAL_FOUR           /* after four DMA transmit  */
#define DMA_ARBIT_INTERVAL_8         DMA_CHCTRL_INTERVAL_EIGHT          /* after eight DMA transmit */

#define DDL_DMA_CHANNEL_NUM          8                /* DMA channel count                     */

#define DDL_DMA_DEVICE_NUM           16               /* the device count each channel support */

/* DMA channel index */
typedef enum
{
	DMA_CHANNEL_0                  = 0x00U,          /* DMA channel 0 */
	DMA_CHANNEL_1                  = 0x01U,          /* DMA channel 1 */
	DMA_CHANNEL_2                  = 0x02U,          /* DMA channel 2 */
	DMA_CHANNEL_3                  = 0x03U,          /* DMA channel 3 */
	DMA_CHANNEL_4                  = 0x04U,          /* DMA channel 4 */
	DMA_CHANNEL_5                  = 0x05U,          /* DMA channel 5 */
	DMA_CHANNEL_6                  = 0x06U,          /* DMA channel 6 */
	DMA_CHANNEL_7                  = 0x07U,          /* DMA channel 7 */
} DMA_ChannelIndex_T;

/* DMA device index */
typedef enum
{
	DMA_DEVICE_0                   = 0x00U,          /* Device 0             */
	DMA_DEVICE_1                   = 0x01U,          /* Device 1             */
	DMA_DEVICE_2                   = 0x02U,          /* Device 2             */
	DMA_DEVICE_3                   = 0x03U,          /* Device 3             */
	DMA_DEVICE_4                   = 0x04U,          /* Device 4             */
	DMA_DEVICE_5                   = 0x05U,          /* Device 5             */
	DMA_DEVICE_6                   = 0x06U,          /* Device 6             */
	DMA_DEVICE_7                   = 0x07U,          /* Device 7             */
	DMA_DEVICE_8                   = 0x08U,          /* Device 8             */
	DMA_DEVICE_9                   = 0x09U,          /* Device 9             */
	DMA_DEVICE_10                  = 0x0AU,          /* Device 10            */
	DMA_DEVICE_11                  = 0x0BU,          /* Device 11            */
	DMA_DEVICE_12                  = 0x0CU,          /* Device 12            */
	DMA_DEVICE_13                  = 0x0DU,          /* Device 13            */
	DMA_DEVICE_14                  = 0x0EU,          /* Device 14            */
	DMA_DEVICE_15                  = 0x0FU,          /* Device 15            */
	DEVICE_RESERVE                 = 0xFFU,          /* Invalid device index */
} DMA_DeviceIndex_T;

/* Device type requested for DMA channel */
typedef enum
{
	SCI0_DMA_TX                    = 0x00U,					 /* SCI0_DMA_TX request type */
	SCI0_DMA_RX                    = 0x01U,					 /* SCI0_DMA_RX request type */
	SCI1_DMA_TX                    = 0x02U,					 /* SCI1_DMA_TX request type */
	SCI1_DMA_RX                    = 0x03U,					 /* SCI1_DMA_RX request type */
	SCI2_DMA_TX                    = 0x04U,					 /* SCI2_DMA_TX request type */
	SCI2_DMA_RX                    = 0x05U,					 /* SCI2_DMA_RX request type */
	IIC0_DMA_TX                    = 0x06U,					 /* IIC0_DMA_TX request type */
	IIC0_DMA_RX                    = 0x07U,					 /* IIC0_DMA_RX request type */
	IIC1_DMA_TX                    = 0x08U,					 /* IIC1_DMA_TX request type */
	IIC1_DMA_RX                    = 0x09U,					 /* IIC1_DMA_RX request type */
	SPI0_DMA_TX                    = 0x0AU,					 /* SPI0_DMA_TX request type */
	SPI0_DMA_RX                    = 0x0BU,					 /* SPI0_DMA_RX request type */
	ADC0_DMA_RX                    = 0x0CU,					 /* ADC0_DMA_RX request type */
	ADC1_DMA_RX                    = 0x0DU,					 /* ADC1_DMA_RX request type */
	TIMA0_TD        	           = 0x0EU,					 /* TIMA0_TD request type    */
	TIMA0_UD        	           = 0x0FU,					 /* TIMA0_UD request type    */
	TIMA1_TD        	           = 0x10U,					 /* TIMA1_TD request type    */
	TIMA1_UD        	           = 0x11U,					 /* TIMA1_UD request type    */
	TIMA2_TD        	           = 0x12U,					 /* TIMA2_TD request type    */
	TIMA2_UD        	           = 0x13U,					 /* TIMA2_UD request type    */
	TIMG0_TD        	           = 0x14U,					 /* TIMG0_TD request type    */
	TIMG0_UD        	           = 0x15U,					 /* TIMG0_UD request type    */
	TIMG1_TD        	           = 0x16U,					 /* TIMG1_TD request type    */
	TIMG1_UD        	           = 0x17U,					 /* TIMG1_UD request type    */
	TIMG2_TD        	           = 0x18U,					 /* TIMG2_TD request type    */
	TIMG2_UD        	           = 0x19U,					 /* TIMG2_UD request type    */
	TIMG0_CC0D                     = 0x1AU,					 /* TIMG0_CC0D request type  */
	TIMG0_CC1D                     = 0x1BU,					 /* TIMG0_CC1D request type  */
	TIMG0_CC2D                     = 0x1CU,					 /* TIMG0_CC2D request type  */
	TIMG0_CC3D                     = 0x1DU,					 /* TIMG0_CC3D request type  */
	TIMG1_CC0D                     = 0x1EU,					 /* TIMG1_CC0D request type  */
	TIMG1_CC1D                     = 0x1FU,					 /* TIMG1_CC1D request type  */
	TIMG1_CC2D                     = 0x20U,					 /* TIMG1_CC2D request type  */
	TIMG1_CC3D                     = 0x21U,					 /* TIMG1_CC3D request type  */
	TIMG2_CC0D                     = 0x22U,					 /* TIMG2_CC0D request type  */
	TIMG2_CC1D                     = 0x23U,					 /* TIMG2_CC1D request type  */
	TIMG2_CC2D                     = 0x24U,					 /* TIMG2_CC2D request type  */
	TIMG2_CC3D                     = 0x25U,					 /* TIMG2_CC3D request type  */
	TIMA0_CC0D                     = 0x26U,					 /* TIMA0_CC0D request type  */
	TIMA0_CC1D                     = 0x27U,					 /* TIMA0_CC1D request type  */
	TIMA0_CC2D                     = 0x28U,					 /* TIMA0_CC2D request type  */
	TIMA0_CC3D                     = 0x29U,					 /* TIMA0_CC3D request type  */
	TIMA1_CC0D                     = 0x2AU,					 /* TIMA1_CC0D request type  */
	TIMA1_CC1D                     = 0x2BU,					 /* TIMA1_CC1D request type  */
	TIMA1_CC2D                     = 0x2CU,					 /* TIMA1_CC2D request type  */
	TIMA1_CC3D                     = 0x2DU,					 /* TIMA1_CC3D request type  */
	TIMA2_CC0D                     = 0x2EU,					 /* TIMA2_CC0D request type  */
	TIMA2_CC1D                     = 0x2FU,					 /* TIMA2_CC1D request type  */
	TIMA2_CC2D                     = 0x30U,					 /* TIMA2_CC2D request type  */
	TIMA2_CC3D                     = 0x31U,					 /* TIMA2_CC3D request type  */
	TIMA0_COMD                     = 0x32U,					 /* TIMA0_COMD request type  */
	TIMA1_COMD                     = 0x33U,					 /* TIMA1_COMD request type  */
	TIMA2_COMD                     = 0x34U,					 /* TIMA2_COMD request type  */
	DNU_CH0                        = 0x35U,                  /* DNU channel 0 request type */
	DNU_CH1                        = 0x36U,                  /* DNU channel 1 request type */
	DNU_CH2                        = 0x37U,                  /* DNU channel 2 request type */
	MEM_TO_MEM                     = 0x38U,                  /* MEM_TO_MEM request type  */
	INVALID_TYPE                   = 0xFFU,                  /* Invalid request type     */
} DMA_DeviceRequest_T;

/* DMA state structure definition */
typedef enum
{
	DDL_DMA_STATE_RESET             = 0x00U,  /* DMA not yet initialized or disabled */
	DDL_DMA_STATE_READY             = 0x01U,  /* DMA initialized and ready for use   */
	DDL_DMA_STATE_BUSY              = 0x02U,  /* DMA process is ongoing              */
	DDL_DMA_STATE_TIMEOUT           = 0x03U,  /* DMA timeout state                   */
	DDL_DMA_STATE_ERROR             = 0x04U,  /* DMA error state                     */
	DDL_DMA_STATE_ABORT             = 0x05U,  /* DMA Abort state                     */
} DMA_State_T;

/* DMA address increment type */
typedef enum
{
	DMA_SRC_INC_DST_INC             = 0x00U,  /* both source address and destination address increment     */
	DMA_SRC_KEEP_DST_INC            = 0x01U,  /* source address unchanged,  destination address increment  */
	DMA_SRC_INC_DST_KEEP            = 0x02U,  /* source address increment,  destination address unchanged  */
} DMA_AddrIncrement_T;

/* DMA callback event */
typedef enum
{
	DMA_EVENT_TRANS_COMPLETE        = 0x00U,  /* DMA transmit complete event. */
	DMA_EVENT_TRANS_ERROR           = 0x01U   /* DMA transmit error event.    */
} DMA_CallbackEvent_T;


/* DMA Configuration Structure definition */
typedef struct
{
	uint32_t                 arbitInterval;    /* Specifies the arbitration time                      */
	uint32_t                 dataAlignment;    /* Specifies the Peripheral data width                 */
	uint32_t                 transmitType;     /* Specifies the transmit type of the DMA channel      */
	uint32_t                 priority;         /* Specifies the priority for the DMA channel          */
	uint32_t                 ebusEnable;       /* Enable Ebus to trigger DMA                          */
	uint32_t                 ebusEvent;        /* Specifies the EBUS event for the DMA channel        */
	DMA_AddrIncrement_T      increment;        /* Specifies the address increment type                */
    uint32_t                 srcAddress;       /* The source memory Buffer address */
    uint32_t                 dstAddress;       /* The destination memory Buffer address */
    uint32_t                 dataLength;       /* The length of data to be transferred from source to destination,
                                                * it should be set according to data size, for example,
                                                * if data size is 'word', it means transfer dataLength word,
                                                * if data size is 'byte', it means tranfer dataLength byte. */
} DMA_ChannelConfig_T;


/* Enable DMA. */
#define __DDL_DMA_ENABLE(__INSTANCE__)      ((__INSTANCE__)->CTRL |= DMA_CTRL_ENABLE)

/* Disable DMA. */
#define __DDL_DMA_DISABLE(__INSTANCE__)     ((__INSTANCE__)->CTRL &= ~DMA_CTRL_ENABLE)

/* Set the specified channel' software request. */
#define __DDL_DMA_SOFT_REQUEST_SET(__INSTANCE__, __CHANNEL__)    SET_BIT((__INSTANCE__)->CH_SW_REQ, __CHANNEL__)

/* Enable the specified channel's interrupt. */
#define __DDL_DMA_ENABLE_IT(__INSTANCE__, __CHANNEL__)    SET_BIT((__INSTANCE__)->INT_EN, __CHANNEL__)

/* Disable the specified channel's interrupt. */
#define __DDL_DMA_DISABLE_IT(__INSTANCE__, __CHANNEL__)    CLEAR_BIT((__INSTANCE__)->INT_EN, __CHANNEL__)

/* Clear the specified channel's interrupt flag. */
#define __DDL_DMA_CLEAR_IT_FLAG(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->INT_FLAG, __CHANNEL__)

/* Get DMA error status. */
#define __DDL_DMA_GET_ERR_STATUS(__INSTANCE__)    ((__INSTANCE__)->ERR & DMA_STATUS_ERROR)

/* Clear DMA error status. */
#define __DDL_DMA_CLEAR_ERR_STATUS(__INSTANCE__)    WRITE_REG((__INSTANCE__)->ERR, DMA_STATUS_ERROR)

/* Set the specified channel's mask request. */
#define __DDL_DMA_MASK_REQUEST_SET(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->MASK_REQ_SET, __CHANNEL__)

/* Clear the specified channel's mask request. */
#define __DDL_DMA_MASK_REQUEST_CLEAR(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->MASK_REQ_CLR, __CHANNEL__)

/* Enable the specified channel. */
#define __DDL_DMA_CHANNEL_ENABLE(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->CH_EN_SET, __CHANNEL__)

/* Disable the specified channel. */
#define __DDL_DMA_CHANNEL_DISABLE(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->CH_EN_CLR, __CHANNEL__)

/* set the high priority for the specified channel. */
#define __DDL_DMA_SET_HIGH_PRIORITY(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->CH_PRI_SET, __CHANNEL__)

/* clear the high priority for the specified channel. */
#define __DDL_DMA_CLEAR_HIGH_PRIORITY(__INSTANCE__, __CHANNEL__)    WRITE_REG((__INSTANCE__)->CH_PRI_CLR, __CHANNEL__)

/* set channel X source end address. */
#define __DDL_DMA_SET_CHANNEL_SRC_END_ADDR(__CH_BASE__, __ADDR__)\
       WRITE_REG(__CH_BASE__->CH_SRC, __ADDR__)

/* set channel X destination end address. */
#define __DDL_DMA_SET_CHANNEL_DST_END_ADDR(__CH_BASE__, __ADDR__)\
       WRITE_REG(__CH_BASE__->CH_DST, __ADDR__)

/* set channel X transmit type. */
#define __DDL_DMA_SET_CHANNEL_TRANSMIT_TYPE(__CH_BASE__, __TYPE__)\
       SET_BITMASK(__CH_BASE__->CH_CTRL, DMA_CHCTRL_TRANSMITTYPE_Mask, __TYPE__)

/* set channel X arbit interval. */
#define __DDL_DMA_SET_CHANNEL_ARBIT_INTERVAL(__CH_BASE__, __INTERVAL__)\
       SET_BITMASK(__CH_BASE__->CH_CTRL, DMA_CHCTRL_INTERVAL_Mask, __INTERVAL__)

/* set channel X data size. */
#define __DDL_DMA_SET_CHANNEL_DATA_SIZE(__CH_BASE__, __DATASIZE__)\
       SET_BITMASK(__CH_BASE__->CH_CTRL, DMA_CHCTRL_DATASIZE_Mask, __DATASIZE__)
       
/**
  * @brief  Makes DMA active.
  * @param  none
  * 
  * @retval none
  */
void DDL_DMA_Instance_Active(void);


/**
  * @brief  Configure the elements of structure DMA_Init_T to default values.
  * @param  pDMAStruct Pointer to a DMA_Init_T structure that contains
  *                  the configuration information for the given DMA module.
  *
  * @retval None
  */
void DDL_DMA_StructInit(void);


/**
  * @brief  Stop the DMA channel
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @retval None
  */
void DDL_DMA_ChannelStop(DMA_Type *DMAx, DMA_ChannelIndex_T channel);


/**
  * @brief  Configure the elements of channel structure DMA_Init_T to default values.
  * @param  pDMAStruct Pointer to a DMA_Init_T structure that contains
  *                  the configuration information for the given DMA module.
  *
  * @retval None
  */
void DDL_DMA_ChannelStructInit(DMA_ChannelConfig_T *pDMAStruct);
    

/**
  * @brief  Initialize the DMA according to the specified
  *         parameters in the DMA_Init_T and create the associated handle.
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @retval None
  */
void DDL_DMA_Init(DMA_Type* DMAx);


/**
  * @brief  Enable DMA interrupt with specified type.
  * @param  DMAx      DMA instance.
  * @param  channel   DMA channel select.
  *
  * @retval None.
  */
void DDL_DMA_IntEnable(DMA_Type* DMAx, DMA_ChannelIndex_T channel);


/**
  * @brief  Enable DMA interrupt with specified type.
  * @param  DMAx      DMA instance.
  * @param  channel   DMA channel select.
  *
  * @retval None.
  */
void DDL_DMA_IntDisable(DMA_Type* DMAx, DMA_ChannelIndex_T channel);


/**
  * @brief  Set the DMA channel Transfer parameter.
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @param  channel DMA channel select.
  * @retval None
  */
void DDL_DMA_SetChannelConfig(DMA_Type *DMAx, DMA_ChannelIndex_T channel, DMA_ChannelConfig_T *pDMAStruct);


/**
  * @brief  Start the DMA Transfer without interrupt.
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @param  channel DMA channel select.
  * @param  device DMA device select.
  * @param  pDMAStruct Pointer to a DMA_Init_T structure that contains
  *         the configuration information for the given DMA module.
  * @retval None
  * @note   This API will not generate DMA interrupt when DMA transfer complete, it only
  *         uses in the case : the other IP will generate interrupt when operate finish.
  */
void DDL_DMA_ChannelStart(DMA_Type* DMAx, DMA_ChannelIndex_T channel, DMA_DeviceIndex_T device, DMA_ChannelConfig_T *pDMAStruct);

/**
  * @brief  enable channel config hold feature .
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @param  channel DMA channel select.
  * @retval DDL status
  */
DDL_Status_T DDL_DMA_EnableChannelCfgHold(DMA_Type *DMAx, DMA_ChannelIndex_T channel);

/**
  * @brief  disable channel config hold feature .
  * @param  DMAx  DMAx Pointer to DMA instance.
  * @param  channel DMA channel select.
  * @retval DDL status
  */
DDL_Status_T DDL_DMA_DisableChannelCfgHold(DMA_Type *DMAx, DMA_ChannelIndex_T channel);


#ifdef __cplusplus
}
#endif

#endif   /* __KPM32xx_DDL_DMA_H */
