| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * DMA header for AMD Queue-based DMA Subsystem |
| * |
| * Copyright (C) 2023-2024, Advanced Micro Devices, Inc. |
| */ |
| |
| #ifndef __QDMA_H |
| #define __QDMA_H |
| |
| #include <linux/bitfield.h> |
| #include <linux/dmaengine.h> |
| #include <linux/kernel.h> |
| #include <linux/platform_device.h> |
| #include <linux/regmap.h> |
| |
| #include "../../virt-dma.h" |
| |
| #define DISABLE 0 |
| #define ENABLE 1 |
| |
| #define QDMA_MIN_IRQ 3 |
| #define QDMA_INTR_NAME_MAX_LEN 30 |
| #define QDMA_INTR_PREFIX "amd-qdma" |
| |
| #define QDMA_IDENTIFIER 0x1FD3 |
| #define QDMA_DEFAULT_RING_SIZE (BIT(10) + 1) |
| #define QDMA_DEFAULT_RING_ID 0 |
| #define QDMA_POLL_INTRVL_US 10 /* 10us */ |
| #define QDMA_POLL_TIMEOUT_US (500 * 1000) /* 500ms */ |
| #define QDMA_DMAP_REG_STRIDE 16 |
| #define QDMA_CTXT_REGMAP_LEN 8 /* 8 regs */ |
| #define QDMA_MM_DESC_SIZE 32 /* Bytes */ |
| #define QDMA_MM_DESC_LEN_BITS 28 |
| #define QDMA_MM_DESC_MAX_LEN (BIT(QDMA_MM_DESC_LEN_BITS) - 1) |
| #define QDMA_MIN_DMA_ALLOC_SIZE 4096 |
| #define QDMA_INTR_RING_SIZE BIT(13) |
| #define QDMA_INTR_RING_IDX_MASK GENMASK(9, 0) |
| #define QDMA_INTR_RING_BASE(_addr) ((_addr) >> 12) |
| |
| #define QDMA_IDENTIFIER_REGOFF 0x0 |
| #define QDMA_IDENTIFIER_MASK GENMASK(31, 16) |
| #define QDMA_QUEUE_ARM_BIT BIT(16) |
| |
| #define qdma_err(qdev, fmt, args...) \ |
| dev_err(&(qdev)->pdev->dev, fmt, ##args) |
| |
| #define qdma_dbg(qdev, fmt, args...) \ |
| dev_dbg(&(qdev)->pdev->dev, fmt, ##args) |
| |
| #define qdma_info(qdev, fmt, args...) \ |
| dev_info(&(qdev)->pdev->dev, fmt, ##args) |
| |
| enum qdma_reg_fields { |
| QDMA_REGF_IRQ_ENABLE, |
| QDMA_REGF_WBK_ENABLE, |
| QDMA_REGF_WBI_CHECK, |
| QDMA_REGF_IRQ_ARM, |
| QDMA_REGF_IRQ_VEC, |
| QDMA_REGF_IRQ_AGG, |
| QDMA_REGF_WBI_INTVL_ENABLE, |
| QDMA_REGF_MRKR_DISABLE, |
| QDMA_REGF_QUEUE_ENABLE, |
| QDMA_REGF_QUEUE_MODE, |
| QDMA_REGF_DESC_BASE, |
| QDMA_REGF_DESC_SIZE, |
| QDMA_REGF_RING_ID, |
| QDMA_REGF_CMD_INDX, |
| QDMA_REGF_CMD_CMD, |
| QDMA_REGF_CMD_TYPE, |
| QDMA_REGF_CMD_BUSY, |
| QDMA_REGF_QUEUE_COUNT, |
| QDMA_REGF_QUEUE_MAX, |
| QDMA_REGF_QUEUE_BASE, |
| QDMA_REGF_FUNCTION_ID, |
| QDMA_REGF_INTR_AGG_BASE, |
| QDMA_REGF_INTR_VECTOR, |
| QDMA_REGF_INTR_SIZE, |
| QDMA_REGF_INTR_VALID, |
| QDMA_REGF_INTR_COLOR, |
| QDMA_REGF_INTR_FUNCTION_ID, |
| QDMA_REGF_ERR_INT_FUNC, |
| QDMA_REGF_ERR_INT_VEC, |
| QDMA_REGF_ERR_INT_ARM, |
| QDMA_REGF_MAX |
| }; |
| |
| enum qdma_regs { |
| QDMA_REGO_CTXT_DATA, |
| QDMA_REGO_CTXT_CMD, |
| QDMA_REGO_CTXT_MASK, |
| QDMA_REGO_MM_H2C_CTRL, |
| QDMA_REGO_MM_C2H_CTRL, |
| QDMA_REGO_QUEUE_COUNT, |
| QDMA_REGO_RING_SIZE, |
| QDMA_REGO_H2C_PIDX, |
| QDMA_REGO_C2H_PIDX, |
| QDMA_REGO_INTR_CIDX, |
| QDMA_REGO_FUNC_ID, |
| QDMA_REGO_ERR_INT, |
| QDMA_REGO_ERR_STAT, |
| QDMA_REGO_MAX |
| }; |
| |
| struct qdma_reg_field { |
| u16 lsb; /* Least significant bit of field */ |
| u16 msb; /* Most significant bit of field */ |
| }; |
| |
| struct qdma_reg { |
| u32 off; |
| u32 count; |
| }; |
| |
| #define QDMA_REGF(_msb, _lsb) { \ |
| .lsb = (_lsb), \ |
| .msb = (_msb), \ |
| } |
| |
| #define QDMA_REGO(_off, _count) { \ |
| .off = (_off), \ |
| .count = (_count), \ |
| } |
| |
| enum qdma_desc_size { |
| QDMA_DESC_SIZE_8B, |
| QDMA_DESC_SIZE_16B, |
| QDMA_DESC_SIZE_32B, |
| QDMA_DESC_SIZE_64B, |
| }; |
| |
| enum qdma_queue_op_mode { |
| QDMA_QUEUE_OP_STREAM, |
| QDMA_QUEUE_OP_MM, |
| }; |
| |
| enum qdma_ctxt_type { |
| QDMA_CTXT_DESC_SW_C2H, |
| QDMA_CTXT_DESC_SW_H2C, |
| QDMA_CTXT_DESC_HW_C2H, |
| QDMA_CTXT_DESC_HW_H2C, |
| QDMA_CTXT_DESC_CR_C2H, |
| QDMA_CTXT_DESC_CR_H2C, |
| QDMA_CTXT_WRB, |
| QDMA_CTXT_PFTCH, |
| QDMA_CTXT_INTR_COAL, |
| QDMA_CTXT_RSVD, |
| QDMA_CTXT_HOST_PROFILE, |
| QDMA_CTXT_TIMER, |
| QDMA_CTXT_FMAP, |
| QDMA_CTXT_FNC_STS, |
| }; |
| |
| enum qdma_ctxt_cmd { |
| QDMA_CTXT_CLEAR, |
| QDMA_CTXT_WRITE, |
| QDMA_CTXT_READ, |
| QDMA_CTXT_INVALIDATE, |
| QDMA_CTXT_MAX |
| }; |
| |
| struct qdma_ctxt_sw_desc { |
| u64 desc_base; |
| u16 vec; |
| }; |
| |
| struct qdma_ctxt_intr { |
| u64 agg_base; |
| u16 vec; |
| u32 size; |
| bool valid; |
| bool color; |
| }; |
| |
| struct qdma_ctxt_fmap { |
| u16 qbase; |
| u16 qmax; |
| }; |
| |
| struct qdma_device; |
| |
| struct qdma_mm_desc { |
| __le64 src_addr; |
| __le32 len; |
| __le32 reserved1; |
| __le64 dst_addr; |
| __le64 reserved2; |
| } __packed; |
| |
| struct qdma_mm_vdesc { |
| struct virt_dma_desc vdesc; |
| struct qdma_queue *queue; |
| struct scatterlist *sgl; |
| u64 sg_off; |
| u32 sg_len; |
| u64 dev_addr; |
| u32 pidx; |
| u32 pending_descs; |
| struct dma_slave_config cfg; |
| }; |
| |
| #define QDMA_VDESC_QUEUED(vdesc) (!(vdesc)->sg_len) |
| |
| struct qdma_queue { |
| struct qdma_device *qdev; |
| struct virt_dma_chan vchan; |
| enum dma_transfer_direction dir; |
| struct dma_slave_config cfg; |
| struct qdma_mm_desc *desc_base; |
| struct qdma_mm_vdesc *submitted_vdesc; |
| struct qdma_mm_vdesc *issued_vdesc; |
| dma_addr_t dma_desc_base; |
| u32 pidx_reg; |
| u32 cidx_reg; |
| u32 ring_size; |
| u32 idx_mask; |
| u16 qid; |
| u32 pidx; |
| u32 cidx; |
| }; |
| |
| struct qdma_intr_ring { |
| struct qdma_device *qdev; |
| __le64 *base; |
| dma_addr_t dev_base; |
| char msix_name[QDMA_INTR_NAME_MAX_LEN]; |
| u32 msix_vector; |
| u16 msix_id; |
| u32 ring_size; |
| u16 ridx; |
| u16 cidx; |
| u8 color; |
| }; |
| |
| #define QDMA_INTR_MASK_PIDX GENMASK_ULL(15, 0) |
| #define QDMA_INTR_MASK_CIDX GENMASK_ULL(31, 16) |
| #define QDMA_INTR_MASK_DESC_COLOR GENMASK_ULL(32, 32) |
| #define QDMA_INTR_MASK_STATE GENMASK_ULL(34, 33) |
| #define QDMA_INTR_MASK_ERROR GENMASK_ULL(36, 35) |
| #define QDMA_INTR_MASK_TYPE GENMASK_ULL(38, 38) |
| #define QDMA_INTR_MASK_QID GENMASK_ULL(62, 39) |
| #define QDMA_INTR_MASK_COLOR GENMASK_ULL(63, 63) |
| |
| struct qdma_device { |
| struct platform_device *pdev; |
| struct dma_device dma_dev; |
| struct regmap *regmap; |
| struct mutex ctxt_lock; /* protect ctxt registers */ |
| const struct qdma_reg_field *rfields; |
| const struct qdma_reg *roffs; |
| struct qdma_queue *h2c_queues; |
| struct qdma_queue *c2h_queues; |
| struct qdma_intr_ring *qintr_rings; |
| u32 qintr_ring_num; |
| u32 qintr_ring_idx; |
| u32 chan_num; |
| u32 queue_irq_start; |
| u32 queue_irq_num; |
| u32 err_irq_idx; |
| u32 fid; |
| }; |
| |
| extern const struct qdma_reg qdma_regos_default[QDMA_REGO_MAX]; |
| extern const struct qdma_reg_field qdma_regfs_default[QDMA_REGF_MAX]; |
| |
| #endif /* __QDMA_H */ |