373 lines
16 KiB
C
Raw Normal View History

2025-04-10 17:31:33 +08:00
/****************************************************************************
*
* Copy right: 2017-, Copyrigths of EigenComm Ltd.
* File name: dma.h
* Description: EC718 dma controller driver header file
* History: Rev1.0 2018-08-08
*
****************************************************************************/
#ifndef _DMA_EC7XX_H
#define _DMA_EC7XX_H
#include "ec7xx.h"
#include "Driver_Common.h"
/**
\addtogroup dma_interface_gr
\{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/** \brief List of DMA source/target address increment control options */
typedef enum
{
DMA_ADDRESS_INCREMENT_NONE = 0, /**< Increment neither source or target address */
DMA_ADDRESS_INCREMENT_SOURCE = 1U, /**< Increment source address */
DMA_ADDRESS_INCREMENT_TARGET = 2U, /**< Increment target address */
DMA_ADDRESS_INCREMENT_BOTH = 3U, /**< Increment both source and target address */
} DmaAddressIncrement_e;
/** \brief List of DMA flow control options */
typedef enum
{
DMA_FLOW_CONTROL_NONE = 0U, /**< No flow control */
DMA_FLOW_CONTROL_SOURCE = 1U, /**< Only source */
DMA_FLOW_CONTROL_TARGET = 2U, /**< Only target */
} DmaFlowControl_e;
/** \brief List of DMA transfer data width in peripheral involved case */
typedef enum
{
DMA_DATA_WIDTH_NO_USE = 0, /**< Data width is set to 0 in memory to memory transfer */
DMA_DATA_WIDTH_ONE_BYTE = 1U, /**< Data widath is 1 byte in peripheral involved transfer */
DMA_DATA_WIDTH_TWO_BYTES = 2U, /**< Data widath is 2 bytes in peripheral involved transfer */
DMA_DATA_WIDTH_FOUR_BYTES = 3U, /**< Data widath is 4 bytes in peripheral involved transfer */
} DmaDataWidth_e;
/** \brief Maximum burst size of each data transfer */
typedef enum
{
DMA_BURST_4_BYTES = 0, /**< Burst size is set to 4 bytes */
DMA_BURST_8_BYTES = 1U, /**< Burst size is set to 8 bytes */
DMA_BURST_16_BYTES = 2U, /**< Burst size is set to 16 bytes */
DMA_BURST_32_BYTES = 3U, /**< Burst size is set to 32 bytes */
DMA_BURST_64_BYTES = 4U, /**< Burst size is set to 64 bytes */
} DmaBurstSize_e;
/** \brief DMA transfer configuration structure */
typedef struct
{
void *sourceAddress; /**< Source address */
void *targetAddress; /**< Target address */
DmaFlowControl_e flowControl; /**< Flow control setting */
DmaAddressIncrement_e addressIncrement; /**< Address increment setting */
DmaDataWidth_e dataWidth; /**< Data width setting */
DmaBurstSize_e burstSize; /**< Burst size setting */
uint32_t totalLength; /**< Transfer length onetime, less than 8k bytes. In descriptor chain it means every transfer's size */
} DmaTransferConfig_t;
/** \brief DMA descriptor extra configuration structure for descriptor-chain mode */
typedef struct
{
void *nextDesriptorAddress; /**< Next descriptor address */
bool stopDecriptorFetch; /**< Indicate whether this is the last descriptor */
bool enableStartInterrupt; /**< Start interrupt control */
bool enableEndInterrupt; /**< End interrupt control */
} DmaExtraConfig_t;
/** \brief DMA descriptor structure */
typedef struct
{
uint32_t DAR; /**< DMA Descriptor Address */
uint32_t SAR; /**< DMA Source Address */
uint32_t TAR; /**< DMA Target Address */
uint32_t CMDR; /**< DMA Command */
} DmaDescriptor_t;
/** \brief List of DMA interrupt sources */
typedef enum
{
/** Stop interrupt enable, when enabled, interrupt is triggered after the channel stops */
DMA_STOP_INTERRUPT_ENABLE = (1U << 29U),
/** EOR interrupt enable, when enabled, interrupt is triggered on End-Of-Receive condition */
DMA_EOR_INTERRUPT_ENABLE = (1U << 28U),
/** Start interrupt enable, when enabled, interrupt is triggered as soon as descriptor is loaded, valid for descriptor-chain-mode */
DMA_START_INTERRUPT_ENABLE = (1U << 22U),
/** End interrupt enable, when enabled, interrupt is triggered when transfer length decrements to 0 */
DMA_END_INTERRUPT_ENABLE = (1U << 21U),
} DmaInterruptEnable_e;
/** \brief List of DMA available intances */
typedef enum
{
DMA_INSTANCE_AP,
DMA_INSTANCE_MP,
DMA_INSTANCE_MAX,
} DmaInstance_e;
/** DMA specific error codes */
#define ARM_DMA_ERROR_CHANNEL_ALLOC (ARM_DRIVER_ERROR_SPECIFIC - 1) /**< No free channel any more */
#define ARM_DMA_ERROR_CHANNEL_NOT_OPEN (ARM_DRIVER_ERROR_SPECIFIC - 2) /**< Specific channel not open */
#define ARM_DMA_ERROR_CHANNEL_NOT_STOPPED (ARM_DRIVER_ERROR_SPECIFIC - 3) /**< Specific channel not stopped */
#define ARM_DMA_ERROR_ADDRESS_NOT_ALIGNED (ARM_DRIVER_ERROR_SPECIFIC - 4) /**< Address alignment check failure */
/** List of events reported to application */
#define DMA_EVENT_ERROR (1) /**< Bus error */
#define DMA_EVENT_START (2) /**< Descriptor load successfully */
#define DMA_EVENT_END (3) /**< Transaction end */
#define DMA_EVENT_EOR (4) /**< Receive EOR signal */
#define DMA_EVENT_STOP (5) /**< Channel has stopped */
/**
\brief Defines callback function prototype.
Callback function will be called in DMA interrupt service routine after a transaction is complete
\param event transaction event for the current transaction, application can get the tansaction
result from this paramter, available events: DMA_EVENT_ERROR, DMA_EVENT_START, DMA_EVENT_END, DMA_EVENT_EOR, DMA_EVENT_STOP
*/
typedef void (*dma_callback_t)(uint32_t event);
/** \brief timeout value when stopping channel */
#define DMA_STOP_TIMEOUT (5000U)
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/**
\fn void DMA_init(DmaInstance_e instance)
\brief Intialize DMA hareware and internal used structure, call this function before any other DMA APIs
*/
void DMA_init(DmaInstance_e instance);
/** \name DMA Channel operation API */
/** \{ */
/**
\fn int32_t DMA_openChannel(DmaInstance_e instance)
\brief Opens a DMA channel
\return Channel on successful allocate
ARM_DMA_ERROR_CHANNEL_ALLOC when no free channel is found
\note Caller shall check the return code
*/
int32_t DMA_openChannel(DmaInstance_e instance);
/**
\fn int32_t DMA_closeChannel(DmaInstance_e instance, uint32_t channel)
\brief Closes a DMA channel
\param[in] instance
\param[in] channel DMA channel number
\return ARM_DRIVER_OK if no error happens
ARM_DMA_ERROR_CHANNEL_NOT_OPEN when channel is not open
\note This API will call \ref DMA_stopChannel to stop channel first if channel is running before close
*/
int32_t DMA_closeChannel(DmaInstance_e instance, uint32_t channel);
/**
\fn void DMA_startChannel(DmaInstance_e instance, uint32_t channel)
\brief Activates the DMA channel
\param[in] instance
\param[in] channel DMA channel number
*/
void DMA_startChannel(DmaInstance_e instance, uint32_t channel);
/**
\fn int32_t DMA_stopChannel(uint32_t channel, bool waitForStop)
\brief Stops the DMA channel from running
\param[in] channel DMA channel number
\param[in] waitForStop whether to wait channel to fully stop or not
\return ARM_DRIVER_OK if stops successfully
ARM_DMA_ERROR_CHANNEL_NOT_STOPPED if channel fails to stop until timeout expires
\note staus and interrupt flags will be cleared in this function call
*/
int32_t DMA_stopChannel(DmaInstance_e instance, uint32_t channel, bool waitForStop);
/**
\fn void DMA_resetChannel(uint32_t channel)
\brief Put the DMA channel to reset state
\param[in] channel DMA channel number
\note Make sure DMA is stopped before calling this function
*/
void DMA_resetChannel(DmaInstance_e instance, uint32_t channel);
/**
\fn void DMA_rigisterChannelCallback(uint32_t channel, dma_callback_t callback)
\brief Registers a DMA callback
\param[in] channel DMA channel number
\param[in] callback Given by the application and will be called in DMA interrupt service routine
*/
void DMA_rigisterChannelCallback(DmaInstance_e instance, uint32_t channel, dma_callback_t callback);
/**
\fn void DMA_enableChannelInterrupts(uint32_t channel, uint32_t mask)
\brief Enables DMA interrupts
\param[in] channel DMA channel number
\param[in] mask Mask of interrupt source to be set, can be ORed by items list in \ref DmaInterruptEnable_e
\note In no-descriptor-fetch mode, all interrupt sources can be enabled by calling this API, however, in descritor-fetch
mode, only \ref DMA_STOP_INTERRUPT_ENABLE \ref DMA_EOR_INTERRUPT_ENABLE can be done by this function call,
the \ref DMA_START_INTERRUPT_ENABLE and \ref DMA_END_INTERRUPT_ENABLE is controlled by setting in \ref DmaExtraConfig_t respectively.
*/
void DMA_enableChannelInterrupts(DmaInstance_e instance, uint32_t channel, uint32_t mask);
/**
\fn void DMA_disableChannelInterrupts(uint32_t channel, uint32_t mask)
\brief Disables DMA interrupts
\param[in] channel DMA channel number
\param[in] mask Mask of interrupt source to be disabled, can be ORed by items list in \ref DmaInterruptEnable_e
\note In no-descriptor-fetch mode, all interrupt sources can be disabled by calling this API, however, in descritor-fetch
mode, only \ref DMA_STOP_INTERRUPT_ENABLE \ref DMA_EOR_INTERRUPT_ENABLE can be done by this function call ,
the \ref DMA_START_INTERRUPT_ENABLE and \ref DMA_END_INTERRUPT_ENABLE is controlled by setting in \ref DmaExtraConfig_t respectively.
*/
void DMA_disableChannelInterrupts(DmaInstance_e instance, uint32_t channel, uint32_t mask);
/**
\fn uint32_t DMA_getEnabledInterrupts(uint32_t channel)
\brief Gets current enabled DMA channel interrupts
\param[in] channel DMA channel number
\return The logical OR of members of the enumeration \ref DmaInterruptEnable_e
*/
uint32_t DMA_getEnabledInterrupts(DmaInstance_e instance, uint32_t channel);
/**
\fn uint32_t DMA_getChannelCount(uint32_t channel)
\brief Obtains courrent transferred data length of a transaction in unit of byte
\param[in] channel DMA channel number
\return Size of data has been transferred
\note In descritor-fetch mode, Start Interrupt shall be enabled by enableStartInterrupt setting in \ref DmaExtraConfig_t
so that driver can load total transfer number for calculation before transferring.
*/
uint32_t DMA_getChannelCount(DmaInstance_e instance, uint32_t channel);
/**
\fn void DMA_setChannelRequestSource(uint32_t channel, DmaRequestSource_e request)
\brief Configures DMA request source
\param[in] channel DMA channel number
\param[in] request DMA request binded to this channel
*/
void DMA_setChannelRequestSource(DmaInstance_e instance, uint32_t channel, DmaRequestSource_e request);
/** \} */
/** \name DMA register mode API */
/** \{ */
/**
\fn void DMA_transferSetup(DmaInstance_e instance, uint32_t channel, const DmaTransferConfig_t* config)
\brief Setups DMA channel according to user's transfer configuration, usded for register mode
\param[in] instance
\param[in] channel DMA channel number
\param[in] config Pointer to transfer configuration
\note user configuration shall be retaining(global variable) for it will be used again after exit from low power
*/
void DMA_transferSetup(DmaInstance_e instance, uint32_t channel, const DmaTransferConfig_t* config);
/** \} */
/** \name DMA descriptor chain mode API */
/** \{ */
/**
\fn void DMA_buildDescriptor(DmaDescriptor_t* descriptor, const DmaTransferConfig_t* config, const DmaExtraConfig_t* extraConfig)
\brief Builds a descritor for DMA mode use
\param[out] descriptor Pointer to DMA descriptor instance
\param[in] config Pointer to transfer configuration
\param[in] extraConfig Pointer to extra configuration which is invalid in descriptor-chain-mode only
\note descriptor shall be retaining(global variable) for it will be used again after exit from low power
*/
void DMA_buildDescriptor(DmaDescriptor_t* descriptor, const DmaTransferConfig_t* config, const DmaExtraConfig_t* extraConfig);
/**
\fn void DMA_buildDescriptorChain(DmaDescriptor_t* descriptorArray, const DmaTransferConfig_t* config, const uint16_t chainCnt)
\brief Builds a descritor for DMA chain mode use
\param[out] descriptorArray Pointer to DMA descriptor chain array, should aligned with 16byte
\param[in] config Pointer to transfer configuration
\param[in] chainCnt The count of descriptor chain
\param[in] needStop Need cycling transfer data or not
\param[in] needIrq Need irq or not for the last descriptor
\param[in] needChain If need chain, last descriptor should points to first one.
If during building chain, should set this param false,
when building the last descriptor, should set TRUE.
\note descriptor shall be retaining(global variable) for it will be used again after exit from low power
*/
void DMA_buildDescriptorChain(DmaDescriptor_t* descriptorArray, const DmaTransferConfig_t* config,
const uint16_t chainCnt,
bool needStop,
bool needIrq,
bool needChain);
/**
\fn int32_t DMA_loadChannelFirstDescriptor(DmaInstance_e instance, uint32_t channel, void* descriptorAddress)
\brief Loads first descritor
\param[in] instance
\param[in] channel DMA channel number
\param[in] descriptorAddress Address of descriptor from which to load, shall be aligend on a 16-byte boundary in memory
\return ARM_DRIVER_OK if success
ARM_DMA_ERROR_ADDRESS_NOT_ALIGNED on address alignment check failure
*/
int32_t DMA_loadChannelFirstDescriptor(DmaInstance_e instance, uint32_t channel, void* descriptorAddress);
/**
\fn void DMA_loadChannelDescriptorAndRun(DmaInstance_e instance, uint32_t channel, void* descriptorAddress)
\brief Loads first descritor and run
\param[in] instance
\param[in] channel DMA channel number
\param[in] descriptorAddress Address of descriptor from which to load, shall be aligend on a 16-byte boundary in memory
\return ARM_DRIVER_OK if success
ARM_DMA_ERROR_ADDRESS_NOT_ALIGNED on address alignment check failure
*/
void DMA_loadChannelDescriptorAndRun(DmaInstance_e instance, uint32_t channel, void* descriptorAddress);
/**
\fn bool DMA_getMPActiveStateExceptUnilog(void)
\brief Get mp dma active state, except unilog channel
\return true: some channel active, do not go doze
false: all channel except unilog are deactived, safe to go doze
*/
bool DMA_getMPActiveStateExceptUnilog(void);
/**
\fn bool DMA_tryDeactiveExceptUnilog(void)
\brief deactive all dma channel except unilog
\return true: deactive success
false: deactive failed
*/
bool DMA_tryDeactiveExceptUnilog(void);
#ifdef TYPE_EC718M
/**
\fn bool DMA_resumeAllExceptUnilog(void)
\brief resume all dma channel except unilog
\return NULL
*/
void DMA_resumeAllExceptUnilog(void);
#endif
/**
\fn void DMA_getMPRunFlag(uint32_t *runAll, uint32_t *actAll);
\brief get dma run flag for mp doze debug
\return NULL
*/
void DMA_getMPRunFlag(uint32_t *runAll, uint32_t *actAll);
/** \} */
/** \} */
#ifdef __cplusplus
}
#endif
#endif