zephyr/drivers/dma/dma_dw_common.h
Anisetti Avinash Krishna 5925a4670b drivers: dma: dma_intel_lpss: Added intel LPSS DMA interface
Added intel LPSS DMA interface using dw common to support
usage of internal DMA in LPSS UART, SPI and I2C for
transfer and receive operations.

Signed-off-by: Anisetti Avinash Krishna <anisetti.avinash.krishna@intel.com>
2023-05-26 10:06:00 -04:00

297 lines
8.2 KiB
C

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