You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
8.2 KiB
296 lines
8.2 KiB
/* |
|
* Copyright (c) 2022 Intel Corporation. |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#ifndef ZEPHYR_DRIVERS_DMA_DMA_DW_COMMON_H_ |
|
#define ZEPHYR_DRIVERS_DMA_DMA_DW_COMMON_H_ |
|
|
|
#include <zephyr/sys/atomic.h> |
|
#include <zephyr/drivers/dma.h> |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
#define MASK(b_hi, b_lo) \ |
|
(((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL) << (b_lo)) |
|
#define SET_BIT(b, x) (((x) & 1) << (b)) |
|
#define SET_BITS(b_hi, b_lo, x) \ |
|
(((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo)) |
|
|
|
#define DW_MAX_CHAN 8 |
|
#define DW_CHAN_COUNT CONFIG_DMA_DW_CHANNEL_COUNT |
|
#define DW_CH_SIZE 0x58 |
|
#define DW_CHAN_OFFSET(chan) (DW_CH_SIZE * chan) |
|
#define DW_ADDR_MASK_32 BIT_MASK(32) |
|
#define DW_ADDR_RIGHT_SHIFT 32 |
|
|
|
#define DW_SAR(chan) \ |
|
(0x0000 + DW_CHAN_OFFSET(chan)) |
|
#define DW_DAR(chan) \ |
|
(0x0008 + DW_CHAN_OFFSET(chan)) |
|
#define DW_LLP(chan) \ |
|
(0x0010 + DW_CHAN_OFFSET(chan)) |
|
#define DW_CTRL_LOW(chan) \ |
|
(0x0018 + DW_CHAN_OFFSET(chan)) |
|
#define DW_CTRL_HIGH(chan) \ |
|
(0x001C + DW_CHAN_OFFSET(chan)) |
|
#define DW_CFG_LOW(chan) \ |
|
(0x0040 + DW_CHAN_OFFSET(chan)) |
|
#define DW_CFG_HIGH(chan) \ |
|
(0x0044 + DW_CHAN_OFFSET(chan)) |
|
#define DW_DSR(chan) \ |
|
(0x0050 + DW_CHAN_OFFSET(chan)) |
|
|
|
#ifdef CONFIG_DMA_64BIT |
|
#define DW_SAR_HI(chan) \ |
|
(0x0004 + DW_CHAN_OFFSET(chan)) |
|
#define DW_DAR_HI(chan) \ |
|
(0x000C + DW_CHAN_OFFSET(chan)) |
|
#endif |
|
|
|
/* registers */ |
|
#define DW_RAW_TFR 0x02C0 |
|
#define DW_RAW_BLOCK 0x02C8 |
|
#define DW_RAW_SRC_TRAN 0x02D0 |
|
#define DW_RAW_DST_TRAN 0x02D8 |
|
#define DW_RAW_ERR 0x02E0 |
|
#define DW_STATUS_TFR 0x02E8 |
|
#define DW_STATUS_BLOCK 0x02F0 |
|
#define DW_STATUS_SRC_TRAN 0x02F8 |
|
#define DW_STATUS_DST_TRAN 0x0300 |
|
#define DW_STATUS_ERR 0x0308 |
|
#define DW_MASK_TFR 0x0310 |
|
#define DW_MASK_BLOCK 0x0318 |
|
#define DW_MASK_SRC_TRAN 0x0320 |
|
#define DW_MASK_DST_TRAN 0x0328 |
|
#define DW_MASK_ERR 0x0330 |
|
#define DW_CLEAR_TFR 0x0338 |
|
#define DW_CLEAR_BLOCK 0x0340 |
|
#define DW_CLEAR_SRC_TRAN 0x0348 |
|
#define DW_CLEAR_DST_TRAN 0x0350 |
|
#define DW_CLEAR_ERR 0x0358 |
|
#define DW_INTR_STATUS 0x0360 |
|
#define DW_DMA_CFG 0x0398 |
|
#define DW_DMA_CHAN_EN 0x03A0 |
|
#define DW_FIFO_PART0_LO 0x400 |
|
#define DW_FIFO_PART0_HI 0x404 |
|
#define DW_FIFO_PART1_LO 0x408 |
|
#define DW_FIFO_PART1_HI 0x40C |
|
|
|
/* channel bits */ |
|
#define DW_CHAN_WRITE_EN_ALL MASK(2 * DW_MAX_CHAN - 1, DW_MAX_CHAN) |
|
#define DW_CHAN_WRITE_EN(chan) BIT((chan) + DW_MAX_CHAN) |
|
#define DW_CHAN_ALL MASK(DW_MAX_CHAN - 1, 0) |
|
#define DW_CHAN(chan) BIT(chan) |
|
#define DW_CHAN_MASK_ALL DW_CHAN_WRITE_EN_ALL |
|
#define DW_CHAN_MASK(chan) DW_CHAN_WRITE_EN(chan) |
|
#define DW_CHAN_UNMASK_ALL (DW_CHAN_WRITE_EN_ALL | DW_CHAN_ALL) |
|
#define DW_CHAN_UNMASK(chan) (DW_CHAN_WRITE_EN(chan) | DW_CHAN(chan)) |
|
|
|
/* CFG_LO */ |
|
#define DW_CFGL_RELOAD_DST BIT(31) |
|
#define DW_CFGL_RELOAD_SRC BIT(30) |
|
#define DW_CFGL_DRAIN BIT(10) /* For Intel GPDMA variant only */ |
|
#define DW_CFGL_SRC_SW_HS BIT(10) /* For Synopsys variant only */ |
|
#define DW_CFGL_DST_SW_HS BIT(11) /* For Synopsys variant only */ |
|
#define DW_CFGL_FIFO_EMPTY BIT(9) |
|
#define DW_CFGL_SUSPEND BIT(8) |
|
#define DW_CFGL_CTL_HI_UPD_EN BIT(5) |
|
|
|
/* CFG_HI */ |
|
#define DW_CFGH_DST_PER_EXT(x) SET_BITS(31, 30, x) |
|
#define DW_CFGH_SRC_PER_EXT(x) SET_BITS(29, 28, x) |
|
#define DW_CFGH_DST_PER(x) SET_BITS(7, 4, x) |
|
#define DW_CFGH_SRC_PER(x) SET_BITS(3, 0, x) |
|
#define DW_CFGH_DST(x) \ |
|
(DW_CFGH_DST_PER_EXT((x) >> 4) | DW_CFGH_DST_PER(x)) |
|
#define DW_CFGH_SRC(x) \ |
|
(DW_CFGH_SRC_PER_EXT((x) >> 4) | DW_CFGH_SRC_PER(x)) |
|
|
|
/* CTL_LO */ |
|
#define DW_CTLL_RELOAD_DST BIT(31) |
|
#define DW_CTLL_RELOAD_SRC BIT(30) |
|
#define DW_CTLL_LLP_S_EN BIT(28) |
|
#define DW_CTLL_LLP_D_EN BIT(27) |
|
#define DW_CTLL_SMS(x) SET_BIT(25, x) |
|
#define DW_CTLL_DMS(x) SET_BIT(23, x) |
|
#define DW_CTLL_FC_P2P SET_BITS(21, 20, 3) |
|
#define DW_CTLL_FC_P2M SET_BITS(21, 20, 2) |
|
#define DW_CTLL_FC_M2P SET_BITS(21, 20, 1) |
|
#define DW_CTLL_FC_M2M SET_BITS(21, 20, 0) |
|
#define DW_CTLL_D_SCAT_EN BIT(18) |
|
#define DW_CTLL_S_GATH_EN BIT(17) |
|
#define DW_CTLL_SRC_MSIZE(x) SET_BITS(16, 14, x) |
|
#define DW_CTLL_DST_MSIZE(x) SET_BITS(13, 11, x) |
|
#define DW_CTLL_SRC_FIX SET_BITS(10, 9, 2) |
|
#define DW_CTLL_SRC_DEC SET_BITS(10, 9, 1) |
|
#define DW_CTLL_SRC_INC SET_BITS(10, 9, 0) |
|
#define DW_CTLL_DST_FIX SET_BITS(8, 7, 2) |
|
#define DW_CTLL_DST_DEC SET_BITS(8, 7, 1) |
|
#define DW_CTLL_DST_INC SET_BITS(8, 7, 0) |
|
#define DW_CTLL_SRC_WIDTH(x) SET_BITS(6, 4, x) |
|
#define DW_CTLL_DST_WIDTH(x) SET_BITS(3, 1, x) |
|
#define DW_CTLL_INT_EN BIT(0) |
|
#define DW_CTLL_SRC_WIDTH_MASK MASK(6, 4) |
|
#define DW_CTLL_SRC_WIDTH_SHIFT 4 |
|
#define DW_CTLL_DST_WIDTH_MASK MASK(3, 1) |
|
#define DW_CTLL_DST_WIDTH_SHIFT 1 |
|
|
|
/* CTL_HI */ |
|
#define DW_CTLH_CLASS(x) SET_BITS(31, 29, x) |
|
#define DW_CTLH_WEIGHT(x) SET_BITS(28, 18, x) |
|
#define DW_CTLH_DONE(x) SET_BIT(17, x) |
|
#define DW_CTLH_BLOCK_TS_MASK MASK(16, 0) |
|
|
|
/* DSR */ |
|
#define DW_DSR_DSC(x) SET_BITS(31, 20, x) |
|
#define DW_DSR_DSI(x) SET_BITS(19, 0, x) |
|
|
|
/* FIFO_PART */ |
|
#define DW_FIFO_SIZE 0x80 |
|
#define DW_FIFO_UPD BIT(26) |
|
#define DW_FIFO_CHx(x) SET_BITS(25, 13, x) |
|
#define DW_FIFO_CHy(x) SET_BITS(12, 0, x) |
|
|
|
/* number of tries to wait for reset */ |
|
#define DW_DMA_CFG_TRIES 10000 |
|
|
|
/* channel drain timeout in microseconds */ |
|
#define DW_DMA_TIMEOUT 1333 |
|
|
|
/* min number of elems for config with irq disabled */ |
|
#define DW_DMA_CFG_NO_IRQ_MIN_ELEMS 3 |
|
|
|
#define DW_DMA_CHANNEL_REGISTER_OFFSET_END 0x50 |
|
#define DW_DMA_IP_REGISTER_OFFSET_END 0x418 |
|
#define DW_DMA_IP_REGISTER_OFFSET_START 0x2C0 |
|
|
|
/* linked list item address */ |
|
#define DW_DMA_LLI_ADDRESS(lli, dir) \ |
|
(((dir) == MEMORY_TO_PERIPHERAL) ? ((lli)->sar) : ((lli)->dar)) |
|
|
|
/* TODO: add FIFO sizes */ |
|
struct dw_chan_arbit_data { |
|
uint16_t class; |
|
uint16_t weight; |
|
}; |
|
|
|
struct dw_drv_plat_data { |
|
struct dw_chan_arbit_data chan[DW_CHAN_COUNT]; |
|
}; |
|
|
|
/* DMA descriptor used by HW */ |
|
struct dw_lli { |
|
#ifdef CONFIG_DMA_64BIT |
|
uint64_t sar; |
|
uint64_t dar; |
|
#else |
|
uint32_t sar; |
|
uint32_t dar; |
|
#endif |
|
uint32_t llp; |
|
uint32_t ctrl_lo; |
|
uint32_t ctrl_hi; |
|
uint32_t sstat; |
|
uint32_t dstat; |
|
|
|
/* align to 32 bytes to not cross cache line |
|
* in case of more than two items |
|
*/ |
|
uint32_t reserved; |
|
} __packed; |
|
|
|
/* pointer data for DW DMA buffer */ |
|
struct dw_dma_ptr_data { |
|
uint32_t current_ptr; |
|
uint32_t start_ptr; |
|
uint32_t end_ptr; |
|
uint32_t hw_ptr; |
|
uint32_t buffer_bytes; |
|
}; |
|
|
|
/* State tracking for each channel */ |
|
enum dw_dma_state { |
|
DW_DMA_IDLE, |
|
DW_DMA_PREPARED, |
|
DW_DMA_SUSPENDED, |
|
DW_DMA_ACTIVE, |
|
}; |
|
|
|
/* data for each DMA channel */ |
|
struct dw_dma_chan_data { |
|
uint32_t direction; |
|
enum dw_dma_state state; |
|
struct dw_lli *lli; /* allocated array of LLI's */ |
|
uint32_t lli_count; /* number of lli's in the allocation */ |
|
struct dw_lli *lli_current; /* current LLI being used */ |
|
uint32_t cfg_lo; |
|
uint32_t cfg_hi; |
|
struct dw_dma_ptr_data ptr_data; /* pointer data */ |
|
dma_callback_t dma_blkcallback; |
|
void *blkuser_data; |
|
dma_callback_t dma_tfrcallback; |
|
void *tfruser_data; |
|
}; |
|
|
|
/* use array to get burst_elems for specific slot number setting. |
|
* the relation between msize and burst_elems should be |
|
* 2 ^ msize = burst_elems |
|
*/ |
|
static const uint32_t burst_elems[] = {1, 2, 4, 8}; |
|
|
|
/* Device run time data */ |
|
struct dw_dma_dev_data { |
|
struct dma_context dma_ctx; |
|
struct dw_drv_plat_data *channel_data; |
|
struct dw_dma_chan_data chan[DW_CHAN_COUNT]; |
|
struct dw_lli lli_pool[DW_CHAN_COUNT][CONFIG_DMA_DW_LLI_POOL_SIZE] __aligned(64); |
|
|
|
ATOMIC_DEFINE(channels_atomic, DW_CHAN_COUNT); |
|
}; |
|
|
|
/* Device constant configuration parameters */ |
|
struct dw_dma_dev_cfg { |
|
uintptr_t base; |
|
void (*irq_config)(void); |
|
}; |
|
|
|
static ALWAYS_INLINE void dw_write(uintptr_t dma_base, uint32_t reg, uint32_t value) |
|
{ |
|
*((volatile uint32_t *)(dma_base + reg)) = value; |
|
} |
|
|
|
static ALWAYS_INLINE uint32_t dw_read(uintptr_t dma_base, uint32_t reg) |
|
{ |
|
return *((volatile uint32_t *)(dma_base + reg)); |
|
} |
|
|
|
int dw_dma_setup(const struct device *dev); |
|
|
|
int dw_dma_config(const struct device *dev, uint32_t channel, |
|
struct dma_config *cfg); |
|
|
|
int dw_dma_reload(const struct device *dev, uint32_t channel, |
|
uint32_t src, uint32_t dst, size_t size); |
|
|
|
int dw_dma_start(const struct device *dev, uint32_t channel); |
|
|
|
int dw_dma_stop(const struct device *dev, uint32_t channel); |
|
|
|
int dw_dma_suspend(const struct device *dev, uint32_t channel); |
|
|
|
int dw_dma_resume(const struct device *dev, uint32_t channel); |
|
|
|
void dw_dma_isr(const struct device *dev); |
|
|
|
int dw_dma_get_status(const struct device *dev, uint32_t channel, |
|
struct dma_status *stat); |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|
|
#endif /* ZEPHYR_DRIVERS_DMA_DMA_DW_COMMON_H_ */
|
|
|