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