|  | /* | 
|  | * 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_ */ |