945 lines
30 KiB
C
945 lines
30 KiB
C
/**
|
|
* @file sdrv_dma.h
|
|
* @brief SemiDrive DMA driver header file.
|
|
*
|
|
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#ifndef __SDRV_DMA_H__
|
|
#define __SDRV_DMA_H__
|
|
|
|
#include <part.h>
|
|
#include "common.h"
|
|
#include "../source/dma/sdrv_dma_regdef.h"
|
|
#include "compiler.h"
|
|
#include "regs_base.h"
|
|
#include "sdrv_common.h"
|
|
#define SDRV_DMA_LP2_TT(n) ((((n)-1) << 4) & 0xfffff0)
|
|
#define SDRV_DMA_LP2_LPSIZE(n) ((__builtin_ffs(n) - 1) & 0xf)
|
|
/* bit4 ~ bit23 */
|
|
#define SDRV_DMA_LP2_LPSIZE_MAX (0x000FFFFF)
|
|
|
|
/* bit12 ~ bit23 */
|
|
#define SDRV_DMA_LP1_LP_COUNT_MAX (0X00000FFF)
|
|
/* bit0 ~ bit11 */
|
|
#define SDRV_DMA_LP1_LPSIZE_MAX (0X00000FFF)
|
|
|
|
/* bit0 ~ bit */
|
|
#define SDRV_DMA_LP0_LPSIZE_MAX (0x00FFFFFF)
|
|
|
|
#define SDRV_DMA_MAD_CRC_REGISTERS (7)
|
|
/**
|
|
* @brief DMA status return code
|
|
*/
|
|
enum {
|
|
/* dma channel id is invalid. */
|
|
SDRV_DMA_INVALID_CHANNEL_ID = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_DMA, 0),
|
|
/* dma channel config unsupport*/
|
|
SDRV_DMA_UNSUPPORT_CONFIG = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_DMA, 1),
|
|
/* dma channel invalid muxid*/
|
|
SDRV_DMA_INVALID_MUXID = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_DMA, 2),
|
|
};
|
|
|
|
/**
|
|
* @brief DMA Channel ID.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_CHANNEL_INVALID = -1,
|
|
SDRV_DMA_CHANNEL_0 = 0,
|
|
SDRV_DMA_CHANNEL_1,
|
|
SDRV_DMA_CHANNEL_2,
|
|
SDRV_DMA_CHANNEL_3,
|
|
SDRV_DMA_CHANNEL_4,
|
|
SDRV_DMA_CHANNEL_5,
|
|
SDRV_DMA_CHANNEL_6,
|
|
SDRV_DMA_CHANNEL_7,
|
|
SDRV_DMA_CHANNEL_8,
|
|
SDRV_DMA_CHANNEL_9,
|
|
SDRV_DMA_CHANNEL_10,
|
|
SDRV_DMA_CHANNEL_11,
|
|
SDRV_DMA_CHANNEL_12,
|
|
SDRV_DMA_CHANNEL_13,
|
|
SDRV_DMA_CHANNEL_14,
|
|
SDRV_DMA_CHANNEL_15,
|
|
SDRV_DMA_CHANNEL_16,
|
|
SDRV_DMA_CHANNEL_17,
|
|
SDRV_DMA_CHANNEL_18,
|
|
SDRV_DMA_CHANNEL_19,
|
|
SDRV_DMA_CHANNEL_20,
|
|
SDRV_DMA_CHANNEL_21,
|
|
SDRV_DMA_CHANNEL_22,
|
|
SDRV_DMA_CHANNEL_23,
|
|
} sdrv_dma_channel_id_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer mode.
|
|
*/
|
|
typedef enum {
|
|
/**< Single mode. */
|
|
SDRV_DMA_TRANSFER_MODE_SINGLE = 0,
|
|
/**< Continuous mode. */
|
|
SDRV_DMA_TRANSFER_MODE_CONTINUOUS,
|
|
/**< Link list mode. */
|
|
SDRV_DMA_TRANSFER_MODE_LINKLIST,
|
|
/**< Channel link mode. */
|
|
SDRV_DMA_TRANSFER_MODE_CHAN_LINK,
|
|
SDRV_DMA_TRANSFER_MODE_NOT_DEFINED,
|
|
} sdrv_dma_xfer_mode_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer types.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_DIR_MEM2MEM = 0, /**< memory to memory */
|
|
SDRV_DMA_DIR_MEM2DEV, /**< memory to device */
|
|
SDRV_DMA_DIR_DEV2MEM, /**< device to memory */
|
|
SDRV_DMA_DIR_DEV2DEV, /**< device to device */
|
|
SDRV_DMA_DIR_REG2MEM, /**< register to memory */
|
|
SDRV_DMA_DIR_REG2DEV, /**< register to device */
|
|
SDRV_DMA_DIR_MEM2REG, /**< memory to register */
|
|
SDRV_DMA_DIR_DEV2REG, /**< device to register */
|
|
SDRV_DMA_DIR_NOT_DEFINED,
|
|
} sdrv_dma_xfer_type_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer address increase mode.
|
|
*/
|
|
typedef enum {
|
|
/**< Automatically increase DMA source or target address after each
|
|
* transaction, usually for memory buffers.
|
|
*/
|
|
SDRV_DMA_ADDR_INC = 0,
|
|
/**< Do not increase DMA source or target address after each
|
|
* transaction, usually for device registers.
|
|
*/
|
|
SDRV_DMA_ADDR_NO_INC,
|
|
} sdrv_dma_addr_inc_e;
|
|
|
|
/**
|
|
* @brief DMA channel data width for each transaction.
|
|
*
|
|
* This is actually the burst size, i.e., AXI AWSIZE and ARSIZE, for
|
|
* DMA transactions. For memory to memory transactions, use 8 bytes
|
|
* width to get better throughput. However for peripheral transactions,
|
|
* you should set bus width according to hardware register data width.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_BUSWIDTH_1_BYTE = 1, /**< 1 byte per transaction */
|
|
SDRV_DMA_BUSWIDTH_2_BYTES = 2, /**< 2 bytes per transaction */
|
|
SDRV_DMA_BUSWIDTH_4_BYTES = 4, /**< 4 bytes per transaction */
|
|
SDRV_DMA_BUSWIDTH_8_BYTES = 8, /**< 8 bytes per transaction */
|
|
} sdrv_dma_bus_width_e;
|
|
|
|
/**
|
|
* @brief DMA channel burst length for each transaction.
|
|
*
|
|
* This is actually the burst length, i.e. AXI AWLEN and ARLEN,for
|
|
* DMA burst transactions. for peripheral transactions,you should
|
|
* set burst length according to peripheral FIFO LEVEL.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_BURST_LEN_1 = 0, /**< 1 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_2, /**< 2 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_3, /**< 3 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_4, /**< 4 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_5, /**< 5 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_6, /**< 6 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_7, /**< 7 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_8, /**< 8 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_9, /**< 9 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_10, /**< 10 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_11, /**< 11 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_12, /**< 12 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_13, /**< 13 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_14, /**< 14 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_15, /**< 15 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_16, /**< 16 x bus_width per transaction */
|
|
SDRV_DMA_BURST_LEN_UNDEFINED,
|
|
} sdrv_dma_burst_len_e;
|
|
|
|
/**
|
|
* @brief The master port used by DMA source and target ports.
|
|
*
|
|
* The DMA controller as a bus master, has both AXI64 port (for memory access)
|
|
* and AHB32 master port (for device register access). You can configure DMA
|
|
* channels to use different ports for different source and target addresses.
|
|
*/
|
|
typedef enum {
|
|
/**< The AXI64 port, used when the source or target buffer is in
|
|
* normal memory (IRAM, SDRAM).
|
|
*/
|
|
SDRV_DMA_PORT_AXI64 = 0,
|
|
/**< The AHB32 port, used when the source or target buffer is
|
|
* peripheral register.
|
|
*/
|
|
SDRV_DMA_PORT_AHB32,
|
|
SDRV_DMA_PROT_NOT_DEFINED,
|
|
} sdrv_dma_port_sel_e;
|
|
|
|
/**
|
|
* @brief The buffer mode used by different application scenarios.
|
|
*
|
|
* MAD (Memory access description) - one transaction configuration include
|
|
* source address, target address,transfer mode,transfer length,link
|
|
* address,etc..
|
|
*
|
|
* Buffer mode is related to transfer mode and loop mode (For details see
|
|
* sdrv_dma_loop_mode_e), when Single Mode selected,buffer mode should be set to
|
|
* SINGLE_BUFFER or 2D_BUFFER. when Continuous Mode selected,buffer mode should
|
|
* be set to DOUBLE_BUFFER or CIRCULAR_BUFFER.
|
|
*/
|
|
typedef enum {
|
|
/**< single buffer should be used with Single Mode.
|
|
* When the entire length data is transferred, DMA is terminated.
|
|
*/
|
|
SDRV_DMA_SINGLE_BUFFER = 0,
|
|
/**< double buffer should be used with Continuous Mode.
|
|
* DMA need two memory areas (IRAM, SDRAM), one memory address is filled in
|
|
* source address of MAD and the another is filled in link address of MAD.
|
|
* When one memory area is transferred,the another continues to be
|
|
* transferred.
|
|
*
|
|
* Set STATUS_ABORT or STATUS_STOP if you want to terminate DMA transfer.
|
|
*/
|
|
SDRV_DMA_DOUBLE_BUFFER,
|
|
/**< circular buffer should be used with Continuous Mode.
|
|
* When the entire length data is transferred, DMA will continue to transfer
|
|
* from source address of MAD.
|
|
*
|
|
* Set STATUS_ABORT or STATUS_STOP if you want to terminate DMA transfer.
|
|
*/
|
|
SDRV_DMA_CIRCULAR_BUFFER,
|
|
/**< 2d buffer is similar to single buffer.
|
|
* The difference is that the entire length data can be transmitted at one
|
|
* handshake request regardless of LOOP_MODE_x. (For details see
|
|
* sdrv_dma_loop_mode_e)
|
|
*/
|
|
SDRV_DMA_2D_BUFFER,
|
|
SDRV_DMA_BUFFER_NOT_DEFINED,
|
|
} sdrv_dma_buffer_mode_e;
|
|
|
|
/**
|
|
* @brief Hardware control after MAD completed just for LOOP_MODE_1.
|
|
*
|
|
* When one transaction is completed according to MAD, DMA will trigger
|
|
* different control.
|
|
*/
|
|
typedef enum {
|
|
/**< DMA will be stopped and trigger interrupt when MAD done. */
|
|
SDRV_DMA_SWT_EVT_CTL_STOP_WTH_INT = 0,
|
|
/**< DMA will be halted and trigger interrupt when MAD done. If you need to
|
|
* continue to use it, you need to configure the resume register. */
|
|
SDRV_DMA_SWT_EVT_CTL_SUSPEND_WTH_INT,
|
|
/**< DMA will be continued and trigger interrupt when MAD done. Such as
|
|
linklist mode. */
|
|
SDRV_DMA_SWT_EVT_CTL_CONTINUE_WTH_INT,
|
|
/**< DMA will be continued and not trigger interrupt when MAD done. Such as
|
|
linklist mode. */
|
|
SDRV_DMA_SWT_EVT_CTL_CONTINUE_WTHOUT_INT,
|
|
SDRV_DMA_SWT_EVT_CTL_UNDEFINED,
|
|
} sdrv_dma_switch_event_ctrl_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer triggered by which mode.
|
|
*
|
|
* Select appropriate trigger mode according to transfer type and
|
|
* transfer mode. Hardware trigger actually for peripheral transactions,
|
|
* Software trigger actually for memory transactions,Gtimer trigger
|
|
* actually use DMA internal timer for period transactions, Internal event
|
|
* trigger actually for linklist transactions.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_TRIGGER_BY_HARDWARE = 0, /**< for peripheral transaction */
|
|
SDRV_DMA_TRIGGER_BY_SOFTWARE, /**< for memory transaction */
|
|
SDRV_DMA_TRIGGER_BY_GTIMER, /**< for period transaction */
|
|
SDRV_DMA_TRIGGER_BY_INTERNAL_EVENT, /**< for linklist transaction */
|
|
SDRV_DMA_TRIGGER_MODE_NOT_DEFINED,
|
|
} sdrv_dma_trigger_mode_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer data mode in one handshake.
|
|
*
|
|
* LOOP_MODE_0: when one handshake request, DMA transfers the entire length data
|
|
* then terminated according to MAD.
|
|
* LOOP_MODE_1: DMA transfers the specified length (burst length x bus_width)
|
|
* data through one handshake request. LOOP_MODE_2: DMA transfers the specified
|
|
* length (power of 2) data through one handshake request.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_LOOP_MODE_0 = 0, /**< entire length data transaction */
|
|
SDRV_DMA_LOOP_MODE_1, /**< burst length data transaction */
|
|
SDRV_DMA_LOOP_MODE_2, /**< power of 2 length data transaction */
|
|
SDRV_DMA_LOOP_MODE_UNDEFINED,
|
|
} sdrv_dma_loop_mode_e;
|
|
|
|
/**
|
|
* @brief DMA channel mux direction.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_MUX_RD = 0x1, /**< only peripheral to memory */
|
|
SDRV_DMA_MUX_WR = 0x2, /**< only memory to peripheral */
|
|
/**< both peripheral to memory and memory to peripheral */
|
|
SDRV_DMA_MUX_BOTH = (SDRV_DMA_MUX_RD | SDRV_DMA_MUX_WR),
|
|
} sdrv_dma_mux_direction_e;
|
|
|
|
/**
|
|
* @brief DMA channel current status.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_CH_STATUS_STOP = 0, /**< transfer stopped */
|
|
SDRV_DMA_CH_STATUS_FLUSH = 1, /**< next MAD config executed directly */
|
|
SDRV_DMA_CH_STATUS_REQ_FLUSH = 2, /**< periphal handshake request cleared */
|
|
SDRV_DMA_CH_STATUS_HALT = 3, /**< transfer halted */
|
|
SDRV_DMA_CH_STATUS_ENABLE = 4, /**< transfer enabled */
|
|
SDRV_DMA_CH_STATUS_RESUME = 5, /**< transfer resumed */
|
|
SDRV_DMA_CH_STATUS_ABORT = 6, /**< transfer aborted */
|
|
} sdrv_dma_channel_status_e;
|
|
|
|
/**
|
|
* @brief DMA channel interrupt types.
|
|
*/
|
|
typedef enum {
|
|
/** DMA Handshake e2e check correctable error */
|
|
SDRV_DMA_HANDSHAKE_E2E_COR_ERR = (1 << 0),
|
|
/** DMA Handshake e2e check uncorrectable error */
|
|
SDRV_DMA_HANDSHAKE_E2E_UNCOR_ERR = (1 << 1),
|
|
/** Channel FIFO data ecc check correctable error */
|
|
SDRV_DMA_CHANNEL_FIFO_ECC_COR_ERR = (1 << 2),
|
|
/** Channel FIFO data ecc check uncorrectable error */
|
|
SDRV_DMA_CHANNEL_FIFO_ECC_UNCOR_ERR = (1 << 3),
|
|
/** AHB read response error */
|
|
SDRV_DMA_AHB_READ_ERR = (1 << 4),
|
|
/** AHB write response error */
|
|
SDRV_DMA_AHB_WRITE_ERR = (1 << 5),
|
|
/** AXI read response error */
|
|
SDRV_DMA_AXI_READ_ERR = (1 << 6),
|
|
/** AXI write response error */
|
|
SDRV_DMA_AXI_WRITE_ERR = (1 << 7),
|
|
/** Channel link error */
|
|
SDRV_DMA_CHANNEL_LINK_ERR = (1 << 8),
|
|
/** MAD crc error */
|
|
SDRV_DMA_MAD_CRC_ERR = (1 << 9),
|
|
/** Firewall protection read error */
|
|
SDRV_DMA_FIREWALL_RD_ERR = (1 << 10),
|
|
/** Firewall protection write error */
|
|
SDRV_DMA_FIREWALL_WR_ERR = (1 << 11),
|
|
/** Data crc error */
|
|
SDRV_DMA_DATA_CRC_ERR = (1 << 12),
|
|
/** Pattern detected */
|
|
SDRV_DMA_PATTERN_DETECTED = (1 << 13),
|
|
/**< DMA channel all MAD transfer completed */
|
|
SDRV_DMA_LAST_MAD_DONE = (1 << 14),
|
|
/**< DMA channel every MAD transfer completed
|
|
* (actually for Continuous and Liklist mode). */
|
|
SDRV_DMA_EVERY_MAD_DONE = (1 << 15),
|
|
/** DMA channel stop*/
|
|
SDRV_DMA_CH_STOP = (1 << 16),
|
|
/** DMA channel flush*/
|
|
SDRV_DMA_CH_FLUSH = (1 << 17),
|
|
/** DMA channel requst flush*/
|
|
SDRV_DMA_CH_REQ_FLUSH = (1 << 18),
|
|
/**< DMA channel transfer halted */
|
|
SDRV_DMA_CH_HALT = (1 << 19),
|
|
/**< DMA channel transfer aborted */
|
|
SDRV_DMA_CH_ABORT = (1 << 20),
|
|
/** The handshake request timeout */
|
|
SDRV_DMA_REQ_TIMEOUT = (1 << 21),
|
|
/** In the loop mode enable with total size unfixed */
|
|
SDRV_DMA_SWITCH_EVENT = (1 << 22),
|
|
/**< DMA channel handshake request completed */
|
|
SDRV_DMA_HS_COMP = (1 << 23),
|
|
/** In the pattern mode with 3'b101 or 3'b110, The pattern status for
|
|
pattern poll mismatch */
|
|
SDRV_DMA_PATTERN_POLL_MISMACTCH = (1 << 24),
|
|
/** AXI read or write outstanding UTID error */
|
|
SDRV_DMA_AXI_OUTSTANDING_UTID_ERR = (1 << 26),
|
|
/** DMA programing sequence error */
|
|
SDRV_DMA_PROGRAMING_SEQUENCE_ERR = (1 << 27),
|
|
} sdrv_dma_interrupt_type_e;
|
|
|
|
/**
|
|
* @brief DMA channel linklist mad types.
|
|
*/
|
|
typedef enum {
|
|
/**< DMA channel middle MAD */
|
|
SDRV_DMA_LINKLIST_NORMAL_MAD = 0,
|
|
/**< DMA channel first MAD*/
|
|
SDRV_DMA_LINKLIST_FIRST_MAD,
|
|
/**< DMA channel last MAD */
|
|
SDRV_DMA_LINKLIST_LAST_MAD,
|
|
} sdrv_dma_linklist_type_e;
|
|
|
|
/**
|
|
* @brief DMA channel transfer status.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_COMPLETED = 0, /**< DMA channel will not accept requests */
|
|
SDRV_DMA_BLOCK_DONE, /**< DMA channel transfer every block done */
|
|
SDRV_DMA_IN_PROGRESS, /**< DMA channel in transmission */
|
|
SDRV_DMA_PAUSED, /**< DMA channel transfer paused*/
|
|
SDRV_DMA_ABORT, /**< DMA channel transfer abort*/
|
|
SDRV_DMA_ERR, /**< DMA channel transfer error */
|
|
SDRV_DMA_PENDING, /**< DMA channel transfer pending */
|
|
} sdrv_dma_status_e;
|
|
|
|
/**
|
|
* @brief DMA channel control state machine status.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_CH_FSM_IDLE = 0, /**< DMA channel idle state */
|
|
SDRV_DMA_CH_FSM_MAD_CHECK, /**< DMA channel mad check state */
|
|
SDRV_DMA_CH_FSM_POLL_OPD2, /**< DMA channel poll opd2 state */
|
|
SDRV_DMA_CH_FSM_DATA_TRANSFER, /**< DMA channel data_transfer state */
|
|
SDRV_DMA_CH_FSM_STOP, /**< DMA channel stop state */
|
|
SDRV_DMA_CH_FSM_HALT, /**< DMA channel halt state */
|
|
SDRV_DMA_CH_FSM_DONE, /**< DMA channel done state */
|
|
} sdrv_dma_channle_ctrl_fsm_e;
|
|
|
|
/**
|
|
* @brief DMA MAD CRC.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_NO_MAD_CRC = 0, /**< DMA MAD CRC Disable */
|
|
SDRV_DMA_CHECK_CURR_MAD = 1, /**< DMA MAD CRC Check current mad */
|
|
SDRV_DMA_CHECK_CURR_MAD_AND_PREVIOUS =
|
|
3, /**< DMA MAD CRC check LADR of previous MAD and current MAD(Except
|
|
LADR of current MAD) */
|
|
} sdrv_dma_mad_crc_mode_e;
|
|
|
|
/**
|
|
* @brief DMA Data CRC.
|
|
*/
|
|
typedef enum {
|
|
SDRV_DMA_NO_DATA_CRC = 0, /**< DMA Data crc disable */
|
|
SDRV_DMA_DATA_CRC_SENSE =
|
|
1, /**< DMA Data crc calculated CRC value is stored in OPD*/
|
|
SDRV_DMA_DATA_CRC_VERIFY_WITH_OPD =
|
|
2, /**< DMA Data crc verification with OPD, mismatch CRC verification
|
|
error interupt is generated */
|
|
SDRV_DMA_DATA_CRC_VERIFY_BETWEEN_WR_RD =
|
|
3, /**< DMA Data crc verification between writing data and reading data,
|
|
mismatch CRC verification error interupt is generated */
|
|
|
|
} sdrv_dma_data_crc_mode_e;
|
|
|
|
/**
|
|
* @brief DMA Data CRC Sel.
|
|
*/
|
|
typedef enum {
|
|
CRC32_802P3 = 0,
|
|
CRC16_CCITT = 1,
|
|
CRC8_CCITT = 2,
|
|
} sdrv_dma_data_crc_sel_e;
|
|
|
|
/**
|
|
* @brief DMA channel mux param structure.
|
|
*/
|
|
typedef struct {
|
|
uint32_t port; /**< mux id */
|
|
uint64_t start_addr; /**< periphal base address */
|
|
uint64_t len; /**< periphal address range */
|
|
sdrv_dma_mux_direction_e direct; /**< mux direction */
|
|
} sdrv_dma_mux_param_t;
|
|
|
|
/**
|
|
* @brief DMA link list descriptor
|
|
*
|
|
* The descriptor indicates one MAD configuration, linklist is to connect
|
|
* multiple MAD configurations in series.
|
|
*/
|
|
typedef struct {
|
|
/**< DMA channel source address register */
|
|
sdrv_dma_ch_src_reg src;
|
|
/**< DMA channel target address register */
|
|
sdrv_dma_ch_dst_reg dst;
|
|
/**< DMA channel transaction control register */
|
|
sdrv_dma_ch_tr_ctrl_reg xfer_ctrl;
|
|
/**< DMA channel block config register */
|
|
sdrv_dma_ch_blk_cfg_reg blk_cfg;
|
|
/**< DMA channel operation mode register */
|
|
sdrv_dma_ch_op_mod_reg op_mod;
|
|
/**< DMA channel operation data register */
|
|
sdrv_dma_ch_op_data_reg op_data;
|
|
/**< DMA channel mad crc register */
|
|
sdrv_dma_ch_mad_crc_reg mad_crc;
|
|
/**< DMA channel link address register */
|
|
sdrv_dma_ch_ll_addr_reg link_addr;
|
|
} sdrv_dma_linklist_descriptor_t;
|
|
|
|
/**
|
|
* @brief DMA controller structure.
|
|
*/
|
|
typedef struct sdrv_dma {
|
|
sdrv_dma_ctrl_t *dma; /**< DMA controller core register structure */
|
|
} sdrv_dma_t;
|
|
|
|
/**
|
|
* @brief DMA channel configuration structure.
|
|
*/
|
|
typedef struct {
|
|
/**< DMA controller */
|
|
sdrv_dma_t *instance;
|
|
/**< ID of this channel */
|
|
sdrv_dma_channel_id_e channel_id;
|
|
/**< Transfer mode */
|
|
sdrv_dma_xfer_mode_e xfer_mode;
|
|
/**< Transfer type - source and target buffer types */
|
|
sdrv_dma_xfer_type_e xfer_type;
|
|
|
|
/**< Source buffer address */
|
|
paddr_t src_addr;
|
|
/**< Source port bus width */
|
|
sdrv_dma_bus_width_e src_width;
|
|
/**< Increase source address after each transaction? */
|
|
sdrv_dma_addr_inc_e src_inc;
|
|
/**< Source port burst length */
|
|
uint32_t src_burst_len;
|
|
|
|
/**< Target buffer address */
|
|
paddr_t dst_addr;
|
|
/**< Target port bus width */
|
|
sdrv_dma_bus_width_e dst_width;
|
|
/**< Increase target address after each transaction? */
|
|
sdrv_dma_addr_inc_e dst_inc;
|
|
/**< Target port burst length */
|
|
uint32_t dst_burst_len;
|
|
|
|
/**< Number of bytes to transfer. */
|
|
uint32_t xfer_bytes;
|
|
|
|
/**< DMA Mux ID */
|
|
int mux_id;
|
|
|
|
/**< DMA source port select */
|
|
sdrv_dma_port_sel_e src_port_sel;
|
|
/**< DMA target port select */
|
|
sdrv_dma_port_sel_e dst_port_sel;
|
|
/**< DMA source cache enable */
|
|
uint32_t src_cache;
|
|
/**< DMA target cache enable */
|
|
uint32_t dst_cache;
|
|
/**< DMA interrupt type */
|
|
uint32_t interrupt_type;
|
|
|
|
/**< Buffer mode */
|
|
sdrv_dma_buffer_mode_e buffer_mode;
|
|
/**< Handshake request mode */
|
|
sdrv_dma_loop_mode_e loop_mode;
|
|
/**< Switch event control */
|
|
sdrv_dma_switch_event_ctrl_e switch_event_ctrl;
|
|
/**< Transfer trigger mode */
|
|
sdrv_dma_trigger_mode_e trig_mode;
|
|
|
|
/**< Link address - next MAD address */
|
|
paddr_t linklist_addr;
|
|
/**< Linklist MAD type */
|
|
sdrv_dma_linklist_type_e linklist_mad_type;
|
|
/**< MAD CRC type */
|
|
sdrv_dma_mad_crc_mode_e mad_crc_mode;
|
|
/**< Data CRC mode */
|
|
sdrv_dma_data_crc_mode_e data_crc_mode;
|
|
/**< Data CRC sel */
|
|
sdrv_dma_data_crc_sel_e data_crc_sel;
|
|
} sdrv_dma_channel_config_t;
|
|
|
|
/**
|
|
* @brief DMA channel interrupt callback type.
|
|
*/
|
|
typedef void (*sdrv_dma_irq_handler)(uint32_t status, uint32_t param,
|
|
void *context);
|
|
|
|
/**
|
|
* @brief DMA channel structure.
|
|
*/
|
|
typedef struct {
|
|
/**< DMA controller register structure */
|
|
sdrv_dma_ctrl_t *dma;
|
|
/**< DMA channel ID */
|
|
sdrv_dma_channel_id_e channel_id;
|
|
/**< DMA channel controller register structure */
|
|
sdrv_dma_channel_ctrl_t *channel;
|
|
/**< DMA channel interrupt callback */
|
|
sdrv_dma_irq_handler irq_callback;
|
|
/**< DMA channel private data for interrupt callback */
|
|
void *irq_context;
|
|
} sdrv_dma_channel_t;
|
|
|
|
/**
|
|
* @brief get dma channel controller base address.
|
|
*
|
|
* This function get dma channel base address by dma controller
|
|
* base address and channel id.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
* @param[in] channel dma channel id.
|
|
* @retval channel controller base address.
|
|
*/
|
|
static inline sdrv_dma_channel_ctrl_t *
|
|
sdrv_dma_get_channel_ctrl_base(sdrv_dma_ctrl_t *dma_base,
|
|
sdrv_dma_channel_id_e channel)
|
|
{
|
|
paddr_t ch_base = (paddr_t)(dma_base);
|
|
|
|
return (sdrv_dma_channel_ctrl_t *)(ch_base + SDRV_DMA_CHANNEL_BASE_OFFSET +
|
|
SDRV_DMA_CHANNEL_SIZE * channel);
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel software handshake.
|
|
*
|
|
* This function set software handshake for memory transactions.
|
|
*
|
|
* @param[in] channel_base dma channel controller base address.
|
|
*/
|
|
static inline void
|
|
sdrv_dma_set_channel_sw_handshake(sdrv_dma_channel_ctrl_t *channel_base)
|
|
{
|
|
#define SDRV_DMA_LIMIT_TIMES 5
|
|
int32_t limit = SDRV_DMA_LIMIT_TIMES;
|
|
|
|
while (limit--) {
|
|
if (channel_base->swhs.v == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
channel_base->swhs.req = 1;
|
|
|
|
while (channel_base->ch_status.ctrl_fsm == SDRV_DMA_CH_FSM_DATA_TRANSFER)
|
|
;
|
|
|
|
channel_base->swhs.req = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel mux id.
|
|
*
|
|
* This function set mux id for periphal transactions.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
* @param[in] channel dma channel id.
|
|
* @param[in] mux_id dma channel mux id.
|
|
*/
|
|
static inline void sdrv_dma_set_channel_muxid(sdrv_dma_ctrl_t *dma_base,
|
|
sdrv_dma_channel_id_e channel,
|
|
uint32_t mux_id)
|
|
{
|
|
sdrv_dma_channel_ctrl_t *ch_base =
|
|
sdrv_dma_get_channel_ctrl_base(dma_base, channel);
|
|
|
|
ch_base->port_cfg.csel = mux_id;
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel read outstanding.
|
|
*
|
|
* This function set read outstanding for memory transactions to get better
|
|
* performance.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
* @param[in] channel dma channel id.
|
|
* @param[in] value read outstanding value.
|
|
*/
|
|
static inline void sdrv_dma_set_channel_rd_outstanding(
|
|
sdrv_dma_ctrl_t *dma_base, sdrv_dma_channel_id_e channel, uint8_t value)
|
|
{
|
|
sdrv_dma_channel_ctrl_t *ch_base =
|
|
sdrv_dma_get_channel_ctrl_base(dma_base, channel);
|
|
|
|
ch_base->port_cfg.rot = value;
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel write outstanding.
|
|
*
|
|
* This function set write outstanding for memory transactions to get better
|
|
* performance.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
* @param[in] channel dma channel id.
|
|
* @param[in] value write outstanding value.
|
|
*/
|
|
static inline void sdrv_dma_set_channel_wr_outstanding(
|
|
sdrv_dma_ctrl_t *dma_base, sdrv_dma_channel_id_e channel, uint8_t value)
|
|
{
|
|
sdrv_dma_channel_ctrl_t *ch_base =
|
|
sdrv_dma_get_channel_ctrl_base(dma_base, channel);
|
|
|
|
ch_base->port_cfg.wot = value;
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel interrupt type.
|
|
*
|
|
* This function set dma channel interrupt type.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
* @param[in] channel dma channel id.
|
|
* @param[in] int_type interrupt type.
|
|
*/
|
|
static inline void sdrv_dma_set_channel_interrupt(sdrv_dma_ctrl_t *dma_base,
|
|
sdrv_dma_channel_id_e channel,
|
|
uint32_t int_type)
|
|
{
|
|
sdrv_dma_channel_ctrl_t *ch_base =
|
|
sdrv_dma_get_channel_ctrl_base(dma_base, channel);
|
|
|
|
ch_base->int_en.v = int_type;
|
|
}
|
|
|
|
/**
|
|
* @brief reset dma interrupt type.
|
|
*
|
|
* This function reset dma controller interrupt status.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
*/
|
|
static inline void sdrv_dma_reset_core_int_status(sdrv_dma_ctrl_t *dma_base)
|
|
{
|
|
dma_base->int_cfg.cont_int_clr.v = 0xFFFFFFFF;
|
|
dma_base->int_cfg.cont_int_clr.v = 0x00000000;
|
|
dma_base->int_cfg.int_clr.v = 0xFFFFFFFF;
|
|
dma_base->int_cfg.int_clr.v = 0x00000000;
|
|
}
|
|
|
|
/**
|
|
* @brief reset dma fifo.
|
|
*
|
|
* This function reset dma controller fifo.
|
|
*
|
|
* @param[in] dma_base dma controller base address.
|
|
*/
|
|
static inline void sdrv_dma_reset_fifo(sdrv_dma_ctrl_t *dma_base)
|
|
{
|
|
uint32_t *dma_fifo_addr =
|
|
(uint32_t *)((paddr_t)dma_base + SDRV_DMA_FIFO_OFFSET);
|
|
int index = 0;
|
|
|
|
for (index = 0; index < (SDRV_DMA_FIFO_SIZE / sizeof(uint32_t)); index++) {
|
|
dma_fifo_addr[index] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief set dma channel status.
|
|
*
|
|
* @param[in] channel_base dma channel controller base address.
|
|
* @param[in] status dma channel status.
|
|
*/
|
|
static inline void
|
|
sdrv_dma_set_channel_status(sdrv_dma_channel_ctrl_t *channel_base,
|
|
sdrv_dma_channel_status_e status)
|
|
{
|
|
switch (status) {
|
|
case SDRV_DMA_CH_STATUS_STOP:
|
|
channel_base->ch_cfg.stop = 1;
|
|
while (channel_base->ch_cfg.stop)
|
|
;
|
|
break;
|
|
case SDRV_DMA_CH_STATUS_FLUSH:
|
|
channel_base->ch_cfg.flush = 1;
|
|
break;
|
|
case SDRV_DMA_CH_STATUS_REQ_FLUSH:
|
|
channel_base->ch_cfg.req_flush = 1;
|
|
break;
|
|
case SDRV_DMA_CH_STATUS_HALT:
|
|
#if CONFIG_E3L
|
|
if (IS_P1)
|
|
channel_base->ch_cfg.halt = 1;
|
|
else if (channel_base->shadow_op_mod.trigger_mode !=
|
|
SDRV_DMA_TRIGGER_BY_INTERNAL_EVENT)
|
|
channel_base->ch_cfg.halt = 1;
|
|
#else
|
|
if (channel_base->shadow_op_mod.trigger_mode !=
|
|
SDRV_DMA_TRIGGER_BY_INTERNAL_EVENT)
|
|
channel_base->ch_cfg.halt = 1;
|
|
#endif
|
|
break;
|
|
case SDRV_DMA_CH_STATUS_RESUME:
|
|
channel_base->ch_cfg.resume = 1;
|
|
break;
|
|
case SDRV_DMA_CH_STATUS_ABORT:
|
|
channel_base->ch_cfg.abort = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize the DMA controller.
|
|
*
|
|
* This function initialize dma controller with reset status and fifo.
|
|
*
|
|
* @param[in] base DMA controller base address.
|
|
*/
|
|
void sdrv_dma_init_dmac(paddr_t base);
|
|
|
|
/**
|
|
* @brief Create DMA controller instance.
|
|
*
|
|
* This function create instance by dma controller base address.
|
|
*
|
|
* @param[in] dma_instance Pointer to DMA instance structure.
|
|
* @param[in] base DMA controller base address.
|
|
*/
|
|
status_t sdrv_dma_create_instance(sdrv_dma_t *dma_instance, paddr_t base);
|
|
|
|
/**
|
|
* @brief Initialize default configuration for DMA channel.
|
|
*
|
|
* This function get channel default configuration.
|
|
*
|
|
* @param[in] config DMA channel configuration to initialize.
|
|
* @param[in] dma_instance DMA controller instance.
|
|
*/
|
|
status_t sdrv_dma_init_channel_config(sdrv_dma_channel_config_t *config,
|
|
sdrv_dma_t *instance);
|
|
|
|
/**
|
|
* @brief Initialize DMA channel.
|
|
*
|
|
* This function set configuration to channel.
|
|
*
|
|
* @param[in] channel The channel to initialize.
|
|
* @param[in] config DMA channel configuration.
|
|
* @return True if the DMA channel is initialized successfully.
|
|
*/
|
|
status_t sdrv_dma_init_channel(sdrv_dma_channel_t *channel,
|
|
const sdrv_dma_channel_config_t *config);
|
|
|
|
/**
|
|
* @brief Start DMA transaction.
|
|
*
|
|
* This function start transfer.
|
|
*
|
|
* @param[in] channel The DMA channel to start.
|
|
*/
|
|
status_t sdrv_dma_start_channel_xfer(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief Stop DMA transaction.
|
|
*
|
|
* This function stop transfer.
|
|
*
|
|
* @param[in] channel The DMA channel to stop.
|
|
*/
|
|
status_t sdrv_dma_stop_channel_xfer(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief De-initialize the DMA channel.
|
|
*
|
|
* This function reset channel registers to default value.
|
|
*
|
|
* @param[in] channel The DMA channel to de-initialize.
|
|
*/
|
|
status_t sdrv_dma_deinit_channel(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief Initialize DMA link list descriptor.
|
|
*
|
|
* This function initializes a DMA link list descriptor, using specified
|
|
* channel configuration.
|
|
*
|
|
* @param[in] desc Link list descriptor.
|
|
* @param[in] config DMA channel config.
|
|
* @return
|
|
*/
|
|
status_t sdrv_dma_init_linklist_entry(sdrv_dma_linklist_descriptor_t *desc,
|
|
const sdrv_dma_channel_config_t *config);
|
|
|
|
/**
|
|
* @brief Set DMA channel source address.
|
|
*
|
|
* This function set source address to channel.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @param[in] addr source address.
|
|
*/
|
|
status_t sdrv_dma_set_channel_source_address(sdrv_dma_channel_t *channel,
|
|
paddr_t addr);
|
|
|
|
/**
|
|
* @brief set dma channel single transmit buffer size
|
|
*
|
|
* This is an unsafe interface. The parameters filled in need to be calculated
|
|
* by yourself, and there is no verification inside the function.
|
|
*
|
|
* @param channel dma channel ptr
|
|
* @param loop_mode loop mode
|
|
* @param total_size total bytes
|
|
* @param loop_size every handshake transmic bytes(The loop mode 0 does not take
|
|
* effect)
|
|
*
|
|
* @return
|
|
*/
|
|
void sdrv_dma_set_channel_buffer_size(sdrv_dma_channel_t *channel,
|
|
sdrv_dma_loop_mode_e loop_mode,
|
|
uint32_t total_size,
|
|
uint32_t loop_size);
|
|
|
|
/**
|
|
* @brief Set DMA channel target address.
|
|
*
|
|
* This function set target address to channel.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @param[in] addr target address.
|
|
*/
|
|
status_t sdrv_dma_set_channel_destination_address(sdrv_dma_channel_t *channel,
|
|
paddr_t addr);
|
|
|
|
/**
|
|
* @brief Set transfer length in bytes for the channel.
|
|
*
|
|
* This function set transfer length in one transaction.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @param[in] xfer_bytes transfer bytes.
|
|
*/
|
|
status_t sdrv_dma_set_channel_xfer_bytes(sdrv_dma_channel_t *channel,
|
|
uint32_t xfer_bytes);
|
|
|
|
/**
|
|
* @brief Get number of transfered bytes for the channel
|
|
*
|
|
* This function get transfered length in bytes.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @return Number of transfered bytes.
|
|
*/
|
|
uint32_t sdrv_dma_get_channel_xfer_bytes(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief Clear DMA channel transfered bytes counter.
|
|
*
|
|
* This function clear transfered bytes counter.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
*/
|
|
status_t sdrv_dma_clear_channel_xfer_bytes(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief Get DMA channel status.
|
|
*
|
|
* This function get channel current status.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @return channel status.
|
|
*/
|
|
uint32_t sdrv_dma_get_channel_xfer_status(sdrv_dma_channel_t *channel);
|
|
|
|
/**
|
|
* @brief Clear DMA channel status.
|
|
*
|
|
* This function clear channel current status.
|
|
*
|
|
* @param[in] channel DMA channel.
|
|
* @param[in] status Channel status bitmask.
|
|
*/
|
|
status_t sdrv_dma_clear_channel_xfer_status(sdrv_dma_channel_t *channel,
|
|
uint32_t status);
|
|
|
|
#endif
|