blob: 94089f1f0c115f5c89b3ffc5f543f4694dd3ba15 [file] [log] [blame]
/* 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 */