162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD Passthru DMA device driver
462306a36Sopenharmony_ci * -- Based on the CCP driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2016,2021 Advanced Micro Devices, Inc.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Sanjay R Mehta <sanju.mehta@amd.com>
962306a36Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com>
1062306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifndef __PT_DEV_H__
1462306a36Sopenharmony_ci#define __PT_DEV_H__
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/device.h>
1762306a36Sopenharmony_ci#include <linux/dmaengine.h>
1862306a36Sopenharmony_ci#include <linux/pci.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <linux/mutex.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/wait.h>
2362306a36Sopenharmony_ci#include <linux/dmapool.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "../virt-dma.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define MAX_PT_NAME_LEN			16
2862306a36Sopenharmony_ci#define MAX_DMAPOOL_NAME_LEN		32
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define MAX_HW_QUEUES			1
3162306a36Sopenharmony_ci#define MAX_CMD_QLEN			100
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define PT_ENGINE_PASSTHRU		5
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* Register Mappings */
3662306a36Sopenharmony_ci#define IRQ_MASK_REG			0x040
3762306a36Sopenharmony_ci#define IRQ_STATUS_REG			0x200
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define CMD_Q_ERROR(__qs)		((__qs) & 0x0000003f)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define CMD_QUEUE_PRIO_OFFSET		0x00
4262306a36Sopenharmony_ci#define CMD_REQID_CONFIG_OFFSET		0x04
4362306a36Sopenharmony_ci#define CMD_TIMEOUT_OFFSET		0x08
4462306a36Sopenharmony_ci#define CMD_PT_VERSION			0x10
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define CMD_Q_CONTROL_BASE		0x0000
4762306a36Sopenharmony_ci#define CMD_Q_TAIL_LO_BASE		0x0004
4862306a36Sopenharmony_ci#define CMD_Q_HEAD_LO_BASE		0x0008
4962306a36Sopenharmony_ci#define CMD_Q_INT_ENABLE_BASE		0x000C
5062306a36Sopenharmony_ci#define CMD_Q_INTERRUPT_STATUS_BASE	0x0010
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define CMD_Q_STATUS_BASE		0x0100
5362306a36Sopenharmony_ci#define CMD_Q_INT_STATUS_BASE		0x0104
5462306a36Sopenharmony_ci#define CMD_Q_DMA_STATUS_BASE		0x0108
5562306a36Sopenharmony_ci#define CMD_Q_DMA_READ_STATUS_BASE	0x010C
5662306a36Sopenharmony_ci#define CMD_Q_DMA_WRITE_STATUS_BASE	0x0110
5762306a36Sopenharmony_ci#define CMD_Q_ABORT_BASE		0x0114
5862306a36Sopenharmony_ci#define CMD_Q_AX_CACHE_BASE		0x0118
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define CMD_CONFIG_OFFSET		0x1120
6162306a36Sopenharmony_ci#define CMD_CLK_GATE_CTL_OFFSET		0x6004
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define CMD_DESC_DW0_VAL		0x500012
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Address offset for virtual queue registers */
6662306a36Sopenharmony_ci#define CMD_Q_STATUS_INCR		0x1000
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Bit masks */
6962306a36Sopenharmony_ci#define CMD_CONFIG_REQID		0
7062306a36Sopenharmony_ci#define CMD_TIMEOUT_DISABLE		0
7162306a36Sopenharmony_ci#define CMD_CLK_DYN_GATING_DIS		0
7262306a36Sopenharmony_ci#define CMD_CLK_SW_GATE_MODE		0
7362306a36Sopenharmony_ci#define CMD_CLK_GATE_CTL		0
7462306a36Sopenharmony_ci#define CMD_QUEUE_PRIO			GENMASK(2, 1)
7562306a36Sopenharmony_ci#define CMD_CONFIG_VHB_EN		BIT(0)
7662306a36Sopenharmony_ci#define CMD_CLK_DYN_GATING_EN		BIT(0)
7762306a36Sopenharmony_ci#define CMD_CLK_HW_GATE_MODE		BIT(0)
7862306a36Sopenharmony_ci#define CMD_CLK_GATE_ON_DELAY		BIT(12)
7962306a36Sopenharmony_ci#define CMD_CLK_GATE_OFF_DELAY		BIT(12)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define CMD_CLK_GATE_CONFIG		(CMD_CLK_GATE_CTL | \
8262306a36Sopenharmony_ci					CMD_CLK_HW_GATE_MODE | \
8362306a36Sopenharmony_ci					CMD_CLK_GATE_ON_DELAY | \
8462306a36Sopenharmony_ci					CMD_CLK_DYN_GATING_EN | \
8562306a36Sopenharmony_ci					CMD_CLK_GATE_OFF_DELAY)
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define CMD_Q_LEN			32
8862306a36Sopenharmony_ci#define CMD_Q_RUN			BIT(0)
8962306a36Sopenharmony_ci#define CMD_Q_HALT			BIT(1)
9062306a36Sopenharmony_ci#define CMD_Q_MEM_LOCATION		BIT(2)
9162306a36Sopenharmony_ci#define CMD_Q_SIZE_MASK			GENMASK(4, 0)
9262306a36Sopenharmony_ci#define CMD_Q_SIZE			GENMASK(7, 3)
9362306a36Sopenharmony_ci#define CMD_Q_SHIFT			GENMASK(1, 0)
9462306a36Sopenharmony_ci#define QUEUE_SIZE_VAL			((ffs(CMD_Q_LEN) - 2) & \
9562306a36Sopenharmony_ci								  CMD_Q_SIZE_MASK)
9662306a36Sopenharmony_ci#define Q_PTR_MASK			(2 << (QUEUE_SIZE_VAL + 5) - 1)
9762306a36Sopenharmony_ci#define Q_DESC_SIZE			sizeof(struct ptdma_desc)
9862306a36Sopenharmony_ci#define Q_SIZE(n)			(CMD_Q_LEN * (n))
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define INT_COMPLETION			BIT(0)
10162306a36Sopenharmony_ci#define INT_ERROR			BIT(1)
10262306a36Sopenharmony_ci#define INT_QUEUE_STOPPED		BIT(2)
10362306a36Sopenharmony_ci#define INT_EMPTY_QUEUE			BIT(3)
10462306a36Sopenharmony_ci#define SUPPORTED_INTERRUPTS		(INT_COMPLETION | INT_ERROR)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/****** Local Storage Block ******/
10762306a36Sopenharmony_ci#define LSB_START			0
10862306a36Sopenharmony_ci#define LSB_END				127
10962306a36Sopenharmony_ci#define LSB_COUNT			(LSB_END - LSB_START + 1)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define PT_DMAPOOL_MAX_SIZE		64
11262306a36Sopenharmony_ci#define PT_DMAPOOL_ALIGN		BIT(5)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define PT_PASSTHRU_BLOCKSIZE		512
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistruct pt_device;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct pt_tasklet_data {
11962306a36Sopenharmony_ci	struct completion completion;
12062306a36Sopenharmony_ci	struct pt_cmd *cmd;
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci * struct pt_passthru_engine - pass-through operation
12562306a36Sopenharmony_ci *   without performing DMA mapping
12662306a36Sopenharmony_ci * @mask: mask to be applied to data
12762306a36Sopenharmony_ci * @mask_len: length in bytes of mask
12862306a36Sopenharmony_ci * @src_dma: data to be used for this operation
12962306a36Sopenharmony_ci * @dst_dma: data produced by this operation
13062306a36Sopenharmony_ci * @src_len: length in bytes of data used for this operation
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * Variables required to be set when calling pt_enqueue_cmd():
13362306a36Sopenharmony_ci *   - bit_mod, byte_swap, src, dst, src_len
13462306a36Sopenharmony_ci *   - mask, mask_len if bit_mod is not PT_PASSTHRU_BITWISE_NOOP
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistruct pt_passthru_engine {
13762306a36Sopenharmony_ci	dma_addr_t mask;
13862306a36Sopenharmony_ci	u32 mask_len;		/* In bytes */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	dma_addr_t src_dma, dst_dma;
14162306a36Sopenharmony_ci	u64 src_len;		/* In bytes */
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci * struct pt_cmd - PTDMA operation request
14662306a36Sopenharmony_ci * @entry: list element
14762306a36Sopenharmony_ci * @work: work element used for callbacks
14862306a36Sopenharmony_ci * @pt: PT device to be run on
14962306a36Sopenharmony_ci * @ret: operation return code
15062306a36Sopenharmony_ci * @flags: cmd processing flags
15162306a36Sopenharmony_ci * @engine: PTDMA operation to perform (passthru)
15262306a36Sopenharmony_ci * @engine_error: PT engine return code
15362306a36Sopenharmony_ci * @passthru: engine specific structures, refer to specific engine struct below
15462306a36Sopenharmony_ci * @callback: operation completion callback function
15562306a36Sopenharmony_ci * @data: parameter value to be supplied to the callback function
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * Variables required to be set when calling pt_enqueue_cmd():
15862306a36Sopenharmony_ci *   - engine, callback
15962306a36Sopenharmony_ci *   - See the operation structures below for what is required for each
16062306a36Sopenharmony_ci *     operation.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_cistruct pt_cmd {
16362306a36Sopenharmony_ci	struct list_head entry;
16462306a36Sopenharmony_ci	struct work_struct work;
16562306a36Sopenharmony_ci	struct pt_device *pt;
16662306a36Sopenharmony_ci	int ret;
16762306a36Sopenharmony_ci	u32 engine;
16862306a36Sopenharmony_ci	u32 engine_error;
16962306a36Sopenharmony_ci	struct pt_passthru_engine passthru;
17062306a36Sopenharmony_ci	/* Completion callback support */
17162306a36Sopenharmony_ci	void (*pt_cmd_callback)(void *data, int err);
17262306a36Sopenharmony_ci	void *data;
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistruct pt_dma_desc {
17662306a36Sopenharmony_ci	struct virt_dma_desc vd;
17762306a36Sopenharmony_ci	struct pt_device *pt;
17862306a36Sopenharmony_ci	enum dma_status status;
17962306a36Sopenharmony_ci	size_t len;
18062306a36Sopenharmony_ci	bool issued_to_hw;
18162306a36Sopenharmony_ci	struct pt_cmd pt_cmd;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct pt_dma_chan {
18562306a36Sopenharmony_ci	struct virt_dma_chan vc;
18662306a36Sopenharmony_ci	struct pt_device *pt;
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistruct pt_cmd_queue {
19062306a36Sopenharmony_ci	struct pt_device *pt;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Queue dma pool */
19362306a36Sopenharmony_ci	struct dma_pool *dma_pool;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* Queue base address (not neccessarily aligned)*/
19662306a36Sopenharmony_ci	struct ptdma_desc *qbase;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Aligned queue start address (per requirement) */
19962306a36Sopenharmony_ci	spinlock_t q_lock ____cacheline_aligned;
20062306a36Sopenharmony_ci	unsigned int qidx;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	unsigned int qsize;
20362306a36Sopenharmony_ci	dma_addr_t qbase_dma;
20462306a36Sopenharmony_ci	dma_addr_t qdma_tail;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	unsigned int active;
20762306a36Sopenharmony_ci	unsigned int suspended;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Interrupt flag */
21062306a36Sopenharmony_ci	bool int_en;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* Register addresses for queue */
21362306a36Sopenharmony_ci	void __iomem *reg_control;
21462306a36Sopenharmony_ci	u32 qcontrol; /* Cached control register */
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* Status values from job */
21762306a36Sopenharmony_ci	u32 int_status;
21862306a36Sopenharmony_ci	u32 q_status;
21962306a36Sopenharmony_ci	u32 q_int_status;
22062306a36Sopenharmony_ci	u32 cmd_error;
22162306a36Sopenharmony_ci	/* Queue Statistics */
22262306a36Sopenharmony_ci	unsigned long total_pt_ops;
22362306a36Sopenharmony_ci} ____cacheline_aligned;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistruct pt_device {
22662306a36Sopenharmony_ci	struct list_head entry;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	unsigned int ord;
22962306a36Sopenharmony_ci	char name[MAX_PT_NAME_LEN];
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	struct device *dev;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Bus specific device information */
23462306a36Sopenharmony_ci	struct pt_msix *pt_msix;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	struct pt_dev_vdata *dev_vdata;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	unsigned int pt_irq;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* I/O area used for device communication */
24162306a36Sopenharmony_ci	void __iomem *io_regs;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	spinlock_t cmd_lock ____cacheline_aligned;
24462306a36Sopenharmony_ci	unsigned int cmd_count;
24562306a36Sopenharmony_ci	struct list_head cmd;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/*
24862306a36Sopenharmony_ci	 * The command queue. This represent the queue available on the
24962306a36Sopenharmony_ci	 * PTDMA that are available for processing cmds
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	struct pt_cmd_queue cmd_q;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Support for the DMA Engine capabilities */
25462306a36Sopenharmony_ci	struct dma_device dma_dev;
25562306a36Sopenharmony_ci	struct pt_dma_chan *pt_dma_chan;
25662306a36Sopenharmony_ci	struct kmem_cache *dma_cmd_cache;
25762306a36Sopenharmony_ci	struct kmem_cache *dma_desc_cache;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	wait_queue_head_t lsb_queue;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* Device Statistics */
26262306a36Sopenharmony_ci	unsigned long total_interrupts;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	struct pt_tasklet_data tdata;
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * descriptor for PTDMA commands
26962306a36Sopenharmony_ci * 8 32-bit words:
27062306a36Sopenharmony_ci * word 0: function; engine; control bits
27162306a36Sopenharmony_ci * word 1: length of source data
27262306a36Sopenharmony_ci * word 2: low 32 bits of source pointer
27362306a36Sopenharmony_ci * word 3: upper 16 bits of source pointer; source memory type
27462306a36Sopenharmony_ci * word 4: low 32 bits of destination pointer
27562306a36Sopenharmony_ci * word 5: upper 16 bits of destination pointer; destination memory type
27662306a36Sopenharmony_ci * word 6: reserved 32 bits
27762306a36Sopenharmony_ci * word 7: reserved 32 bits
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci#define DWORD0_SOC	BIT(0)
28162306a36Sopenharmony_ci#define DWORD0_IOC	BIT(1)
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistruct dword3 {
28462306a36Sopenharmony_ci	unsigned int  src_hi:16;
28562306a36Sopenharmony_ci	unsigned int  src_mem:2;
28662306a36Sopenharmony_ci	unsigned int  lsb_cxt_id:8;
28762306a36Sopenharmony_ci	unsigned int  rsvd1:5;
28862306a36Sopenharmony_ci	unsigned int  fixed:1;
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistruct dword5 {
29262306a36Sopenharmony_ci	unsigned int  dst_hi:16;
29362306a36Sopenharmony_ci	unsigned int  dst_mem:2;
29462306a36Sopenharmony_ci	unsigned int  rsvd1:13;
29562306a36Sopenharmony_ci	unsigned int  fixed:1;
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistruct ptdma_desc {
29962306a36Sopenharmony_ci	u32 dw0;
30062306a36Sopenharmony_ci	u32 length;
30162306a36Sopenharmony_ci	u32 src_lo;
30262306a36Sopenharmony_ci	struct dword3 dw3;
30362306a36Sopenharmony_ci	u32 dst_lo;
30462306a36Sopenharmony_ci	struct dword5 dw5;
30562306a36Sopenharmony_ci	__le32 rsvd1;
30662306a36Sopenharmony_ci	__le32 rsvd2;
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/* Structure to hold PT device data */
31062306a36Sopenharmony_cistruct pt_dev_vdata {
31162306a36Sopenharmony_ci	const unsigned int bar;
31262306a36Sopenharmony_ci};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciint pt_dmaengine_register(struct pt_device *pt);
31562306a36Sopenharmony_civoid pt_dmaengine_unregister(struct pt_device *pt);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_civoid ptdma_debugfs_setup(struct pt_device *pt);
31862306a36Sopenharmony_ciint pt_core_init(struct pt_device *pt);
31962306a36Sopenharmony_civoid pt_core_destroy(struct pt_device *pt);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint pt_core_perform_passthru(struct pt_cmd_queue *cmd_q,
32262306a36Sopenharmony_ci			     struct pt_passthru_engine *pt_engine);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_civoid pt_check_status_trans(struct pt_device *pt, struct pt_cmd_queue *cmd_q);
32562306a36Sopenharmony_civoid pt_start_queue(struct pt_cmd_queue *cmd_q);
32662306a36Sopenharmony_civoid pt_stop_queue(struct pt_cmd_queue *cmd_q);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic inline void pt_core_disable_queue_interrupts(struct pt_device *pt)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	iowrite32(0, pt->cmd_q.reg_control + 0x000C);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic inline void pt_core_enable_queue_interrupts(struct pt_device *pt)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	iowrite32(SUPPORTED_INTERRUPTS, pt->cmd_q.reg_control + 0x000C);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci#endif
338