18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2016,2019 Advanced Micro Devices, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/kthread.h>
128c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/compiler.h>
158c2ecf20Sopenharmony_ci#include <linux/ccp.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "ccp-dev.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Allocate the requested number of contiguous LSB slots
208c2ecf20Sopenharmony_ci * from the LSB bitmap. Look in the private range for this
218c2ecf20Sopenharmony_ci * queue first; failing that, check the public area.
228c2ecf20Sopenharmony_ci * If no space is available, wait around.
238c2ecf20Sopenharmony_ci * Return: first slot number
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_cistatic u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct ccp_device *ccp;
288c2ecf20Sopenharmony_ci	int start;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* First look at the map for the queue */
318c2ecf20Sopenharmony_ci	if (cmd_q->lsb >= 0) {
328c2ecf20Sopenharmony_ci		start = (u32)bitmap_find_next_zero_area(cmd_q->lsbmap,
338c2ecf20Sopenharmony_ci							LSB_SIZE,
348c2ecf20Sopenharmony_ci							0, count, 0);
358c2ecf20Sopenharmony_ci		if (start < LSB_SIZE) {
368c2ecf20Sopenharmony_ci			bitmap_set(cmd_q->lsbmap, start, count);
378c2ecf20Sopenharmony_ci			return start + cmd_q->lsb * LSB_SIZE;
388c2ecf20Sopenharmony_ci		}
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* No joy; try to get an entry from the shared blocks */
428c2ecf20Sopenharmony_ci	ccp = cmd_q->ccp;
438c2ecf20Sopenharmony_ci	for (;;) {
448c2ecf20Sopenharmony_ci		mutex_lock(&ccp->sb_mutex);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci		start = (u32)bitmap_find_next_zero_area(ccp->lsbmap,
478c2ecf20Sopenharmony_ci							MAX_LSB_CNT * LSB_SIZE,
488c2ecf20Sopenharmony_ci							0,
498c2ecf20Sopenharmony_ci							count, 0);
508c2ecf20Sopenharmony_ci		if (start <= MAX_LSB_CNT * LSB_SIZE) {
518c2ecf20Sopenharmony_ci			bitmap_set(ccp->lsbmap, start, count);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci			mutex_unlock(&ccp->sb_mutex);
548c2ecf20Sopenharmony_ci			return start;
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		ccp->sb_avail = 0;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		mutex_unlock(&ccp->sb_mutex);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		/* Wait for KSB entries to become available */
628c2ecf20Sopenharmony_ci		if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail))
638c2ecf20Sopenharmony_ci			return 0;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* Free a number of LSB slots from the bitmap, starting at
688c2ecf20Sopenharmony_ci * the indicated starting slot number.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistatic void ccp_lsb_free(struct ccp_cmd_queue *cmd_q, unsigned int start,
718c2ecf20Sopenharmony_ci			 unsigned int count)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	if (!start)
748c2ecf20Sopenharmony_ci		return;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (cmd_q->lsb == start) {
778c2ecf20Sopenharmony_ci		/* An entry from the private LSB */
788c2ecf20Sopenharmony_ci		bitmap_clear(cmd_q->lsbmap, start, count);
798c2ecf20Sopenharmony_ci	} else {
808c2ecf20Sopenharmony_ci		/* From the shared LSBs */
818c2ecf20Sopenharmony_ci		struct ccp_device *ccp = cmd_q->ccp;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		mutex_lock(&ccp->sb_mutex);
848c2ecf20Sopenharmony_ci		bitmap_clear(ccp->lsbmap, start, count);
858c2ecf20Sopenharmony_ci		ccp->sb_avail = 1;
868c2ecf20Sopenharmony_ci		mutex_unlock(&ccp->sb_mutex);
878c2ecf20Sopenharmony_ci		wake_up_interruptible_all(&ccp->sb_queue);
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* CCP version 5: Union to define the function field (cmd_reg1/dword0) */
928c2ecf20Sopenharmony_ciunion ccp_function {
938c2ecf20Sopenharmony_ci	struct {
948c2ecf20Sopenharmony_ci		u16 size:7;
958c2ecf20Sopenharmony_ci		u16 encrypt:1;
968c2ecf20Sopenharmony_ci		u16 mode:5;
978c2ecf20Sopenharmony_ci		u16 type:2;
988c2ecf20Sopenharmony_ci	} aes;
998c2ecf20Sopenharmony_ci	struct {
1008c2ecf20Sopenharmony_ci		u16 size:7;
1018c2ecf20Sopenharmony_ci		u16 encrypt:1;
1028c2ecf20Sopenharmony_ci		u16 rsvd:5;
1038c2ecf20Sopenharmony_ci		u16 type:2;
1048c2ecf20Sopenharmony_ci	} aes_xts;
1058c2ecf20Sopenharmony_ci	struct {
1068c2ecf20Sopenharmony_ci		u16 size:7;
1078c2ecf20Sopenharmony_ci		u16 encrypt:1;
1088c2ecf20Sopenharmony_ci		u16 mode:5;
1098c2ecf20Sopenharmony_ci		u16 type:2;
1108c2ecf20Sopenharmony_ci	} des3;
1118c2ecf20Sopenharmony_ci	struct {
1128c2ecf20Sopenharmony_ci		u16 rsvd1:10;
1138c2ecf20Sopenharmony_ci		u16 type:4;
1148c2ecf20Sopenharmony_ci		u16 rsvd2:1;
1158c2ecf20Sopenharmony_ci	} sha;
1168c2ecf20Sopenharmony_ci	struct {
1178c2ecf20Sopenharmony_ci		u16 mode:3;
1188c2ecf20Sopenharmony_ci		u16 size:12;
1198c2ecf20Sopenharmony_ci	} rsa;
1208c2ecf20Sopenharmony_ci	struct {
1218c2ecf20Sopenharmony_ci		u16 byteswap:2;
1228c2ecf20Sopenharmony_ci		u16 bitwise:3;
1238c2ecf20Sopenharmony_ci		u16 reflect:2;
1248c2ecf20Sopenharmony_ci		u16 rsvd:8;
1258c2ecf20Sopenharmony_ci	} pt;
1268c2ecf20Sopenharmony_ci	struct  {
1278c2ecf20Sopenharmony_ci		u16 rsvd:13;
1288c2ecf20Sopenharmony_ci	} zlib;
1298c2ecf20Sopenharmony_ci	struct {
1308c2ecf20Sopenharmony_ci		u16 size:10;
1318c2ecf20Sopenharmony_ci		u16 type:2;
1328c2ecf20Sopenharmony_ci		u16 mode:3;
1338c2ecf20Sopenharmony_ci	} ecc;
1348c2ecf20Sopenharmony_ci	u16 raw;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define	CCP_AES_SIZE(p)		((p)->aes.size)
1388c2ecf20Sopenharmony_ci#define	CCP_AES_ENCRYPT(p)	((p)->aes.encrypt)
1398c2ecf20Sopenharmony_ci#define	CCP_AES_MODE(p)		((p)->aes.mode)
1408c2ecf20Sopenharmony_ci#define	CCP_AES_TYPE(p)		((p)->aes.type)
1418c2ecf20Sopenharmony_ci#define	CCP_XTS_SIZE(p)		((p)->aes_xts.size)
1428c2ecf20Sopenharmony_ci#define	CCP_XTS_TYPE(p)		((p)->aes_xts.type)
1438c2ecf20Sopenharmony_ci#define	CCP_XTS_ENCRYPT(p)	((p)->aes_xts.encrypt)
1448c2ecf20Sopenharmony_ci#define	CCP_DES3_SIZE(p)	((p)->des3.size)
1458c2ecf20Sopenharmony_ci#define	CCP_DES3_ENCRYPT(p)	((p)->des3.encrypt)
1468c2ecf20Sopenharmony_ci#define	CCP_DES3_MODE(p)	((p)->des3.mode)
1478c2ecf20Sopenharmony_ci#define	CCP_DES3_TYPE(p)	((p)->des3.type)
1488c2ecf20Sopenharmony_ci#define	CCP_SHA_TYPE(p)		((p)->sha.type)
1498c2ecf20Sopenharmony_ci#define	CCP_RSA_SIZE(p)		((p)->rsa.size)
1508c2ecf20Sopenharmony_ci#define	CCP_PT_BYTESWAP(p)	((p)->pt.byteswap)
1518c2ecf20Sopenharmony_ci#define	CCP_PT_BITWISE(p)	((p)->pt.bitwise)
1528c2ecf20Sopenharmony_ci#define	CCP_ECC_MODE(p)		((p)->ecc.mode)
1538c2ecf20Sopenharmony_ci#define	CCP_ECC_AFFINE(p)	((p)->ecc.one)
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Word 0 */
1568c2ecf20Sopenharmony_ci#define CCP5_CMD_DW0(p)		((p)->dw0)
1578c2ecf20Sopenharmony_ci#define CCP5_CMD_SOC(p)		(CCP5_CMD_DW0(p).soc)
1588c2ecf20Sopenharmony_ci#define CCP5_CMD_IOC(p)		(CCP5_CMD_DW0(p).ioc)
1598c2ecf20Sopenharmony_ci#define CCP5_CMD_INIT(p)	(CCP5_CMD_DW0(p).init)
1608c2ecf20Sopenharmony_ci#define CCP5_CMD_EOM(p)		(CCP5_CMD_DW0(p).eom)
1618c2ecf20Sopenharmony_ci#define CCP5_CMD_FUNCTION(p)	(CCP5_CMD_DW0(p).function)
1628c2ecf20Sopenharmony_ci#define CCP5_CMD_ENGINE(p)	(CCP5_CMD_DW0(p).engine)
1638c2ecf20Sopenharmony_ci#define CCP5_CMD_PROT(p)	(CCP5_CMD_DW0(p).prot)
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* Word 1 */
1668c2ecf20Sopenharmony_ci#define CCP5_CMD_DW1(p)		((p)->length)
1678c2ecf20Sopenharmony_ci#define CCP5_CMD_LEN(p)		(CCP5_CMD_DW1(p))
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/* Word 2 */
1708c2ecf20Sopenharmony_ci#define CCP5_CMD_DW2(p)		((p)->src_lo)
1718c2ecf20Sopenharmony_ci#define CCP5_CMD_SRC_LO(p)	(CCP5_CMD_DW2(p))
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* Word 3 */
1748c2ecf20Sopenharmony_ci#define CCP5_CMD_DW3(p)		((p)->dw3)
1758c2ecf20Sopenharmony_ci#define CCP5_CMD_SRC_MEM(p)	((p)->dw3.src_mem)
1768c2ecf20Sopenharmony_ci#define CCP5_CMD_SRC_HI(p)	((p)->dw3.src_hi)
1778c2ecf20Sopenharmony_ci#define CCP5_CMD_LSB_ID(p)	((p)->dw3.lsb_cxt_id)
1788c2ecf20Sopenharmony_ci#define CCP5_CMD_FIX_SRC(p)	((p)->dw3.fixed)
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/* Words 4/5 */
1818c2ecf20Sopenharmony_ci#define CCP5_CMD_DW4(p)		((p)->dw4)
1828c2ecf20Sopenharmony_ci#define CCP5_CMD_DST_LO(p)	(CCP5_CMD_DW4(p).dst_lo)
1838c2ecf20Sopenharmony_ci#define CCP5_CMD_DW5(p)		((p)->dw5.fields.dst_hi)
1848c2ecf20Sopenharmony_ci#define CCP5_CMD_DST_HI(p)	(CCP5_CMD_DW5(p))
1858c2ecf20Sopenharmony_ci#define CCP5_CMD_DST_MEM(p)	((p)->dw5.fields.dst_mem)
1868c2ecf20Sopenharmony_ci#define CCP5_CMD_FIX_DST(p)	((p)->dw5.fields.fixed)
1878c2ecf20Sopenharmony_ci#define CCP5_CMD_SHA_LO(p)	((p)->dw4.sha_len_lo)
1888c2ecf20Sopenharmony_ci#define CCP5_CMD_SHA_HI(p)	((p)->dw5.sha_len_hi)
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/* Word 6/7 */
1918c2ecf20Sopenharmony_ci#define CCP5_CMD_DW6(p)		((p)->key_lo)
1928c2ecf20Sopenharmony_ci#define CCP5_CMD_KEY_LO(p)	(CCP5_CMD_DW6(p))
1938c2ecf20Sopenharmony_ci#define CCP5_CMD_DW7(p)		((p)->dw7)
1948c2ecf20Sopenharmony_ci#define CCP5_CMD_KEY_HI(p)	((p)->dw7.key_hi)
1958c2ecf20Sopenharmony_ci#define CCP5_CMD_KEY_MEM(p)	((p)->dw7.key_mem)
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline u32 low_address(unsigned long addr)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	return (u64)addr & 0x0ffffffff;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic inline u32 high_address(unsigned long addr)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	return ((u64)addr >> 32) & 0x00000ffff;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic unsigned int ccp5_get_free_slots(struct ccp_cmd_queue *cmd_q)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	unsigned int head_idx, n;
2108c2ecf20Sopenharmony_ci	u32 head_lo, queue_start;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	queue_start = low_address(cmd_q->qdma_tail);
2138c2ecf20Sopenharmony_ci	head_lo = ioread32(cmd_q->reg_head_lo);
2148c2ecf20Sopenharmony_ci	head_idx = (head_lo - queue_start) / sizeof(struct ccp5_desc);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	n = head_idx + COMMANDS_PER_QUEUE - cmd_q->qidx - 1;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return n % COMMANDS_PER_QUEUE; /* Always one unused spot */
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int ccp5_do_cmd(struct ccp5_desc *desc,
2228c2ecf20Sopenharmony_ci		       struct ccp_cmd_queue *cmd_q)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	__le32 *mP;
2258c2ecf20Sopenharmony_ci	u32 *dP;
2268c2ecf20Sopenharmony_ci	u32 tail;
2278c2ecf20Sopenharmony_ci	int	i;
2288c2ecf20Sopenharmony_ci	int ret = 0;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	cmd_q->total_ops++;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (CCP5_CMD_SOC(desc)) {
2338c2ecf20Sopenharmony_ci		CCP5_CMD_IOC(desc) = 1;
2348c2ecf20Sopenharmony_ci		CCP5_CMD_SOC(desc) = 0;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci	mutex_lock(&cmd_q->q_mutex);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	mP = (__le32 *)&cmd_q->qbase[cmd_q->qidx];
2398c2ecf20Sopenharmony_ci	dP = (u32 *)desc;
2408c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
2418c2ecf20Sopenharmony_ci		mP[i] = cpu_to_le32(dP[i]); /* handle endianness */
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	cmd_q->qidx = (cmd_q->qidx + 1) % COMMANDS_PER_QUEUE;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* The data used by this command must be flushed to memory */
2468c2ecf20Sopenharmony_ci	wmb();
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* Write the new tail address back to the queue register */
2498c2ecf20Sopenharmony_ci	tail = low_address(cmd_q->qdma_tail + cmd_q->qidx * Q_DESC_SIZE);
2508c2ecf20Sopenharmony_ci	iowrite32(tail, cmd_q->reg_tail_lo);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Turn the queue back on using our cached control register */
2538c2ecf20Sopenharmony_ci	iowrite32(cmd_q->qcontrol | CMD5_Q_RUN, cmd_q->reg_control);
2548c2ecf20Sopenharmony_ci	mutex_unlock(&cmd_q->q_mutex);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (CCP5_CMD_IOC(desc)) {
2578c2ecf20Sopenharmony_ci		/* Wait for the job to complete */
2588c2ecf20Sopenharmony_ci		ret = wait_event_interruptible(cmd_q->int_queue,
2598c2ecf20Sopenharmony_ci					       cmd_q->int_rcvd);
2608c2ecf20Sopenharmony_ci		if (ret || cmd_q->cmd_error) {
2618c2ecf20Sopenharmony_ci			/* Log the error and flush the queue by
2628c2ecf20Sopenharmony_ci			 * moving the head pointer
2638c2ecf20Sopenharmony_ci			 */
2648c2ecf20Sopenharmony_ci			if (cmd_q->cmd_error)
2658c2ecf20Sopenharmony_ci				ccp_log_error(cmd_q->ccp,
2668c2ecf20Sopenharmony_ci					      cmd_q->cmd_error);
2678c2ecf20Sopenharmony_ci			iowrite32(tail, cmd_q->reg_head_lo);
2688c2ecf20Sopenharmony_ci			if (!ret)
2698c2ecf20Sopenharmony_ci				ret = -EIO;
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci		cmd_q->int_rcvd = 0;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return ret;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int ccp5_perform_aes(struct ccp_op *op)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
2808c2ecf20Sopenharmony_ci	union ccp_function function;
2818c2ecf20Sopenharmony_ci	u32 key_addr = op->sb_key * LSB_ITEM_SIZE;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	op->cmd_q->total_aes_ops++;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
2868c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_AES;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = op->soc;
2918c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
2928c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = op->init;
2938c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = op->eom;
2948c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	function.raw = 0;
2978c2ecf20Sopenharmony_ci	CCP_AES_ENCRYPT(&function) = op->u.aes.action;
2988c2ecf20Sopenharmony_ci	CCP_AES_MODE(&function) = op->u.aes.mode;
2998c2ecf20Sopenharmony_ci	CCP_AES_TYPE(&function) = op->u.aes.type;
3008c2ecf20Sopenharmony_ci	CCP_AES_SIZE(&function) = op->u.aes.size;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
3078c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
3088c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
3118c2ecf20Sopenharmony_ci	CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
3128c2ecf20Sopenharmony_ci	CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_LO(&desc) = lower_32_bits(key_addr);
3158c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_HI(&desc) = 0;
3168c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB;
3178c2ecf20Sopenharmony_ci	CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int ccp5_perform_xts_aes(struct ccp_op *op)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
3258c2ecf20Sopenharmony_ci	union ccp_function function;
3268c2ecf20Sopenharmony_ci	u32 key_addr = op->sb_key * LSB_ITEM_SIZE;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	op->cmd_q->total_xts_aes_ops++;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
3318c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_XTS_AES_128;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = op->soc;
3368c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
3378c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = op->init;
3388c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = op->eom;
3398c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	function.raw = 0;
3428c2ecf20Sopenharmony_ci	CCP_XTS_TYPE(&function) = op->u.xts.type;
3438c2ecf20Sopenharmony_ci	CCP_XTS_ENCRYPT(&function) = op->u.xts.action;
3448c2ecf20Sopenharmony_ci	CCP_XTS_SIZE(&function) = op->u.xts.unit_size;
3458c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
3508c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
3518c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
3548c2ecf20Sopenharmony_ci	CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
3558c2ecf20Sopenharmony_ci	CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_LO(&desc) = lower_32_bits(key_addr);
3588c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_HI(&desc) =  0;
3598c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB;
3608c2ecf20Sopenharmony_ci	CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int ccp5_perform_sha(struct ccp_op *op)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
3688c2ecf20Sopenharmony_ci	union ccp_function function;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	op->cmd_q->total_sha_ops++;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
3738c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_SHA;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = op->soc;
3788c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
3798c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = 1;
3808c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = op->eom;
3818c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	function.raw = 0;
3848c2ecf20Sopenharmony_ci	CCP_SHA_TYPE(&function) = op->u.sha.type;
3858c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
3908c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
3918c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (op->eom) {
3968c2ecf20Sopenharmony_ci		CCP5_CMD_SHA_LO(&desc) = lower_32_bits(op->u.sha.msg_bits);
3978c2ecf20Sopenharmony_ci		CCP5_CMD_SHA_HI(&desc) = upper_32_bits(op->u.sha.msg_bits);
3988c2ecf20Sopenharmony_ci	} else {
3998c2ecf20Sopenharmony_ci		CCP5_CMD_SHA_LO(&desc) = 0;
4008c2ecf20Sopenharmony_ci		CCP5_CMD_SHA_HI(&desc) = 0;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic int ccp5_perform_des3(struct ccp_op *op)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
4098c2ecf20Sopenharmony_ci	union ccp_function function;
4108c2ecf20Sopenharmony_ci	u32 key_addr = op->sb_key * LSB_ITEM_SIZE;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	op->cmd_q->total_3des_ops++;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
4158c2ecf20Sopenharmony_ci	memset(&desc, 0, sizeof(struct ccp5_desc));
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_DES3;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = op->soc;
4208c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
4218c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = op->init;
4228c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = op->eom;
4238c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	function.raw = 0;
4268c2ecf20Sopenharmony_ci	CCP_DES3_ENCRYPT(&function) = op->u.des3.action;
4278c2ecf20Sopenharmony_ci	CCP_DES3_MODE(&function) = op->u.des3.mode;
4288c2ecf20Sopenharmony_ci	CCP_DES3_TYPE(&function) = op->u.des3.type;
4298c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
4348c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
4358c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
4388c2ecf20Sopenharmony_ci	CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
4398c2ecf20Sopenharmony_ci	CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_LO(&desc) = lower_32_bits(key_addr);
4428c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_HI(&desc) = 0;
4438c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB;
4448c2ecf20Sopenharmony_ci	CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic int ccp5_perform_rsa(struct ccp_op *op)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
4528c2ecf20Sopenharmony_ci	union ccp_function function;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	op->cmd_q->total_rsa_ops++;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
4578c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_RSA;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = op->soc;
4628c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
4638c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = 0;
4648c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = 1;
4658c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	function.raw = 0;
4688c2ecf20Sopenharmony_ci	CCP_RSA_SIZE(&function) = (op->u.rsa.mod_size + 7) >> 3;
4698c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->u.rsa.input_len;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* Source is from external memory */
4748c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
4758c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
4768c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* Destination is in external memory */
4798c2ecf20Sopenharmony_ci	CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
4808c2ecf20Sopenharmony_ci	CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
4818c2ecf20Sopenharmony_ci	CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* Key (Exponent) is in external memory */
4848c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_LO(&desc) = ccp_addr_lo(&op->exp.u.dma);
4858c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_HI(&desc) = ccp_addr_hi(&op->exp.u.dma);
4868c2ecf20Sopenharmony_ci	CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int ccp5_perform_passthru(struct ccp_op *op)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
4948c2ecf20Sopenharmony_ci	union ccp_function function;
4958c2ecf20Sopenharmony_ci	struct ccp_dma_info *saddr = &op->src.u.dma;
4968c2ecf20Sopenharmony_ci	struct ccp_dma_info *daddr = &op->dst.u.dma;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	op->cmd_q->total_pt_ops++;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_PASSTHRU;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = 0;
5068c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
5078c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = 0;
5088c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = op->eom;
5098c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	function.raw = 0;
5128c2ecf20Sopenharmony_ci	CCP_PT_BYTESWAP(&function) = op->u.passthru.byte_swap;
5138c2ecf20Sopenharmony_ci	CCP_PT_BITWISE(&function) = op->u.passthru.bit_mod;
5148c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* Length of source data is always 256 bytes */
5178c2ecf20Sopenharmony_ci	if (op->src.type == CCP_MEMTYPE_SYSTEM)
5188c2ecf20Sopenharmony_ci		CCP5_CMD_LEN(&desc) = saddr->length;
5198c2ecf20Sopenharmony_ci	else
5208c2ecf20Sopenharmony_ci		CCP5_CMD_LEN(&desc) = daddr->length;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (op->src.type == CCP_MEMTYPE_SYSTEM) {
5238c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
5248c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
5258c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci		if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
5288c2ecf20Sopenharmony_ci			CCP5_CMD_LSB_ID(&desc) = op->sb_key;
5298c2ecf20Sopenharmony_ci	} else {
5308c2ecf20Sopenharmony_ci		u32 key_addr = op->src.u.sb * CCP_SB_BYTES;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_LO(&desc) = lower_32_bits(key_addr);
5338c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_HI(&desc) = 0;
5348c2ecf20Sopenharmony_ci		CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SB;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
5388c2ecf20Sopenharmony_ci		CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
5398c2ecf20Sopenharmony_ci		CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
5408c2ecf20Sopenharmony_ci		CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
5418c2ecf20Sopenharmony_ci	} else {
5428c2ecf20Sopenharmony_ci		u32 key_addr = op->dst.u.sb * CCP_SB_BYTES;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		CCP5_CMD_DST_LO(&desc) = lower_32_bits(key_addr);
5458c2ecf20Sopenharmony_ci		CCP5_CMD_DST_HI(&desc) = 0;
5468c2ecf20Sopenharmony_ci		CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SB;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic int ccp5_perform_ecc(struct ccp_op *op)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct ccp5_desc desc;
5558c2ecf20Sopenharmony_ci	union ccp_function function;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	op->cmd_q->total_ecc_ops++;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Zero out all the fields of the command desc */
5608c2ecf20Sopenharmony_ci	memset(&desc, 0, Q_DESC_SIZE);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_ECC;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	CCP5_CMD_SOC(&desc) = 0;
5658c2ecf20Sopenharmony_ci	CCP5_CMD_IOC(&desc) = 1;
5668c2ecf20Sopenharmony_ci	CCP5_CMD_INIT(&desc) = 0;
5678c2ecf20Sopenharmony_ci	CCP5_CMD_EOM(&desc) = 1;
5688c2ecf20Sopenharmony_ci	CCP5_CMD_PROT(&desc) = 0;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	function.raw = 0;
5718c2ecf20Sopenharmony_ci	function.ecc.mode = op->u.ecc.function;
5728c2ecf20Sopenharmony_ci	CCP5_CMD_FUNCTION(&desc) = function.raw;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
5778c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
5788c2ecf20Sopenharmony_ci	CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
5818c2ecf20Sopenharmony_ci	CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
5828c2ecf20Sopenharmony_ci	CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return ccp5_do_cmd(&desc, op->cmd_q);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic int ccp_find_lsb_regions(struct ccp_cmd_queue *cmd_q, u64 status)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	int q_mask = 1 << cmd_q->id;
5908c2ecf20Sopenharmony_ci	int queues = 0;
5918c2ecf20Sopenharmony_ci	int j;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* Build a bit mask to know which LSBs this queue has access to.
5948c2ecf20Sopenharmony_ci	 * Don't bother with segment 0 as it has special privileges.
5958c2ecf20Sopenharmony_ci	 */
5968c2ecf20Sopenharmony_ci	for (j = 1; j < MAX_LSB_CNT; j++) {
5978c2ecf20Sopenharmony_ci		if (status & q_mask)
5988c2ecf20Sopenharmony_ci			bitmap_set(cmd_q->lsbmask, j, 1);
5998c2ecf20Sopenharmony_ci		status >>= LSB_REGION_WIDTH;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci	queues = bitmap_weight(cmd_q->lsbmask, MAX_LSB_CNT);
6028c2ecf20Sopenharmony_ci	dev_dbg(cmd_q->ccp->dev, "Queue %d can access %d LSB regions\n",
6038c2ecf20Sopenharmony_ci		 cmd_q->id, queues);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return queues ? 0 : -EINVAL;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic int ccp_find_and_assign_lsb_to_q(struct ccp_device *ccp,
6098c2ecf20Sopenharmony_ci					int lsb_cnt, int n_lsbs,
6108c2ecf20Sopenharmony_ci					unsigned long *lsb_pub)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	DECLARE_BITMAP(qlsb, MAX_LSB_CNT);
6138c2ecf20Sopenharmony_ci	int bitno;
6148c2ecf20Sopenharmony_ci	int qlsb_wgt;
6158c2ecf20Sopenharmony_ci	int i;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* For each queue:
6188c2ecf20Sopenharmony_ci	 * If the count of potential LSBs available to a queue matches the
6198c2ecf20Sopenharmony_ci	 * ordinal given to us in lsb_cnt:
6208c2ecf20Sopenharmony_ci	 * Copy the mask of possible LSBs for this queue into "qlsb";
6218c2ecf20Sopenharmony_ci	 * For each bit in qlsb, see if the corresponding bit in the
6228c2ecf20Sopenharmony_ci	 * aggregation mask is set; if so, we have a match.
6238c2ecf20Sopenharmony_ci	 *     If we have a match, clear the bit in the aggregation to
6248c2ecf20Sopenharmony_ci	 *     mark it as no longer available.
6258c2ecf20Sopenharmony_ci	 *     If there is no match, clear the bit in qlsb and keep looking.
6268c2ecf20Sopenharmony_ci	 */
6278c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
6288c2ecf20Sopenharmony_ci		struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		qlsb_wgt = bitmap_weight(cmd_q->lsbmask, MAX_LSB_CNT);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		if (qlsb_wgt == lsb_cnt) {
6338c2ecf20Sopenharmony_ci			bitmap_copy(qlsb, cmd_q->lsbmask, MAX_LSB_CNT);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci			bitno = find_first_bit(qlsb, MAX_LSB_CNT);
6368c2ecf20Sopenharmony_ci			while (bitno < MAX_LSB_CNT) {
6378c2ecf20Sopenharmony_ci				if (test_bit(bitno, lsb_pub)) {
6388c2ecf20Sopenharmony_ci					/* We found an available LSB
6398c2ecf20Sopenharmony_ci					 * that this queue can access
6408c2ecf20Sopenharmony_ci					 */
6418c2ecf20Sopenharmony_ci					cmd_q->lsb = bitno;
6428c2ecf20Sopenharmony_ci					bitmap_clear(lsb_pub, bitno, 1);
6438c2ecf20Sopenharmony_ci					dev_dbg(ccp->dev,
6448c2ecf20Sopenharmony_ci						 "Queue %d gets LSB %d\n",
6458c2ecf20Sopenharmony_ci						 i, bitno);
6468c2ecf20Sopenharmony_ci					break;
6478c2ecf20Sopenharmony_ci				}
6488c2ecf20Sopenharmony_ci				bitmap_clear(qlsb, bitno, 1);
6498c2ecf20Sopenharmony_ci				bitno = find_first_bit(qlsb, MAX_LSB_CNT);
6508c2ecf20Sopenharmony_ci			}
6518c2ecf20Sopenharmony_ci			if (bitno >= MAX_LSB_CNT)
6528c2ecf20Sopenharmony_ci				return -EINVAL;
6538c2ecf20Sopenharmony_ci			n_lsbs--;
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	return n_lsbs;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci/* For each queue, from the most- to least-constrained:
6608c2ecf20Sopenharmony_ci * find an LSB that can be assigned to the queue. If there are N queues that
6618c2ecf20Sopenharmony_ci * can only use M LSBs, where N > M, fail; otherwise, every queue will get a
6628c2ecf20Sopenharmony_ci * dedicated LSB. Remaining LSB regions become a shared resource.
6638c2ecf20Sopenharmony_ci * If we have fewer LSBs than queues, all LSB regions become shared resources.
6648c2ecf20Sopenharmony_ci */
6658c2ecf20Sopenharmony_cistatic int ccp_assign_lsbs(struct ccp_device *ccp)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	DECLARE_BITMAP(lsb_pub, MAX_LSB_CNT);
6688c2ecf20Sopenharmony_ci	DECLARE_BITMAP(qlsb, MAX_LSB_CNT);
6698c2ecf20Sopenharmony_ci	int n_lsbs = 0;
6708c2ecf20Sopenharmony_ci	int bitno;
6718c2ecf20Sopenharmony_ci	int i, lsb_cnt;
6728c2ecf20Sopenharmony_ci	int rc = 0;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	bitmap_zero(lsb_pub, MAX_LSB_CNT);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/* Create an aggregate bitmap to get a total count of available LSBs */
6778c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
6788c2ecf20Sopenharmony_ci		bitmap_or(lsb_pub,
6798c2ecf20Sopenharmony_ci			  lsb_pub, ccp->cmd_q[i].lsbmask,
6808c2ecf20Sopenharmony_ci			  MAX_LSB_CNT);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	n_lsbs = bitmap_weight(lsb_pub, MAX_LSB_CNT);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (n_lsbs >= ccp->cmd_q_count) {
6858c2ecf20Sopenharmony_ci		/* We have enough LSBS to give every queue a private LSB.
6868c2ecf20Sopenharmony_ci		 * Brute force search to start with the queues that are more
6878c2ecf20Sopenharmony_ci		 * constrained in LSB choice. When an LSB is privately
6888c2ecf20Sopenharmony_ci		 * assigned, it is removed from the public mask.
6898c2ecf20Sopenharmony_ci		 * This is an ugly N squared algorithm with some optimization.
6908c2ecf20Sopenharmony_ci		 */
6918c2ecf20Sopenharmony_ci		for (lsb_cnt = 1;
6928c2ecf20Sopenharmony_ci		     n_lsbs && (lsb_cnt <= MAX_LSB_CNT);
6938c2ecf20Sopenharmony_ci		     lsb_cnt++) {
6948c2ecf20Sopenharmony_ci			rc = ccp_find_and_assign_lsb_to_q(ccp, lsb_cnt, n_lsbs,
6958c2ecf20Sopenharmony_ci							  lsb_pub);
6968c2ecf20Sopenharmony_ci			if (rc < 0)
6978c2ecf20Sopenharmony_ci				return -EINVAL;
6988c2ecf20Sopenharmony_ci			n_lsbs = rc;
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	rc = 0;
7038c2ecf20Sopenharmony_ci	/* What's left of the LSBs, according to the public mask, now become
7048c2ecf20Sopenharmony_ci	 * shared. Any zero bits in the lsb_pub mask represent an LSB region
7058c2ecf20Sopenharmony_ci	 * that can't be used as a shared resource, so mark the LSB slots for
7068c2ecf20Sopenharmony_ci	 * them as "in use".
7078c2ecf20Sopenharmony_ci	 */
7088c2ecf20Sopenharmony_ci	bitmap_copy(qlsb, lsb_pub, MAX_LSB_CNT);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT);
7118c2ecf20Sopenharmony_ci	while (bitno < MAX_LSB_CNT) {
7128c2ecf20Sopenharmony_ci		bitmap_set(ccp->lsbmap, bitno * LSB_SIZE, LSB_SIZE);
7138c2ecf20Sopenharmony_ci		bitmap_set(qlsb, bitno, 1);
7148c2ecf20Sopenharmony_ci		bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT);
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return rc;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic void ccp5_disable_queue_interrupts(struct ccp_device *ccp)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	unsigned int i;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
7258c2ecf20Sopenharmony_ci		iowrite32(0x0, ccp->cmd_q[i].reg_int_enable);
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic void ccp5_enable_queue_interrupts(struct ccp_device *ccp)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	unsigned int i;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
7338c2ecf20Sopenharmony_ci		iowrite32(SUPPORTED_INTERRUPTS, ccp->cmd_q[i].reg_int_enable);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic void ccp5_irq_bh(unsigned long data)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	struct ccp_device *ccp = (struct ccp_device *)data;
7398c2ecf20Sopenharmony_ci	u32 status;
7408c2ecf20Sopenharmony_ci	unsigned int i;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
7438c2ecf20Sopenharmony_ci		struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		status = ioread32(cmd_q->reg_interrupt_status);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		if (status) {
7488c2ecf20Sopenharmony_ci			cmd_q->int_status = status;
7498c2ecf20Sopenharmony_ci			cmd_q->q_status = ioread32(cmd_q->reg_status);
7508c2ecf20Sopenharmony_ci			cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci			/* On error, only save the first error value */
7538c2ecf20Sopenharmony_ci			if ((status & INT_ERROR) && !cmd_q->cmd_error)
7548c2ecf20Sopenharmony_ci				cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci			cmd_q->int_rcvd = 1;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci			/* Acknowledge the interrupt and wake the kthread */
7598c2ecf20Sopenharmony_ci			iowrite32(status, cmd_q->reg_interrupt_status);
7608c2ecf20Sopenharmony_ci			wake_up_interruptible(&cmd_q->int_queue);
7618c2ecf20Sopenharmony_ci		}
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci	ccp5_enable_queue_interrupts(ccp);
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic irqreturn_t ccp5_irq_handler(int irq, void *data)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct ccp_device *ccp = (struct ccp_device *)data;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	ccp5_disable_queue_interrupts(ccp);
7718c2ecf20Sopenharmony_ci	ccp->total_interrupts++;
7728c2ecf20Sopenharmony_ci	if (ccp->use_tasklet)
7738c2ecf20Sopenharmony_ci		tasklet_schedule(&ccp->irq_tasklet);
7748c2ecf20Sopenharmony_ci	else
7758c2ecf20Sopenharmony_ci		ccp5_irq_bh((unsigned long)ccp);
7768c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic int ccp5_init(struct ccp_device *ccp)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	struct device *dev = ccp->dev;
7828c2ecf20Sopenharmony_ci	struct ccp_cmd_queue *cmd_q;
7838c2ecf20Sopenharmony_ci	struct dma_pool *dma_pool;
7848c2ecf20Sopenharmony_ci	char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
7858c2ecf20Sopenharmony_ci	unsigned int qmr, i;
7868c2ecf20Sopenharmony_ci	u64 status;
7878c2ecf20Sopenharmony_ci	u32 status_lo, status_hi;
7888c2ecf20Sopenharmony_ci	int ret;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* Find available queues */
7918c2ecf20Sopenharmony_ci	qmr = ioread32(ccp->io_regs + Q_MASK_REG);
7928c2ecf20Sopenharmony_ci	/*
7938c2ecf20Sopenharmony_ci	 * Check for a access to the registers.  If this read returns
7948c2ecf20Sopenharmony_ci	 * 0xffffffff, it's likely that the system is running a broken
7958c2ecf20Sopenharmony_ci	 * BIOS which disallows access to the device. Stop here and fail
7968c2ecf20Sopenharmony_ci	 * the initialization (but not the load, as the PSP could get
7978c2ecf20Sopenharmony_ci	 * properly initialized).
7988c2ecf20Sopenharmony_ci	 */
7998c2ecf20Sopenharmony_ci	if (qmr == 0xffffffff) {
8008c2ecf20Sopenharmony_ci		dev_notice(dev, "ccp: unable to access the device: you might be running a broken BIOS.\n");
8018c2ecf20Sopenharmony_ci		return 1;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	for (i = 0; (i < MAX_HW_QUEUES) && (ccp->cmd_q_count < ccp->max_q_count); i++) {
8058c2ecf20Sopenharmony_ci		if (!(qmr & (1 << i)))
8068c2ecf20Sopenharmony_ci			continue;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		/* Allocate a dma pool for this queue */
8098c2ecf20Sopenharmony_ci		snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
8108c2ecf20Sopenharmony_ci			 ccp->name, i);
8118c2ecf20Sopenharmony_ci		dma_pool = dma_pool_create(dma_pool_name, dev,
8128c2ecf20Sopenharmony_ci					   CCP_DMAPOOL_MAX_SIZE,
8138c2ecf20Sopenharmony_ci					   CCP_DMAPOOL_ALIGN, 0);
8148c2ecf20Sopenharmony_ci		if (!dma_pool) {
8158c2ecf20Sopenharmony_ci			dev_err(dev, "unable to allocate dma pool\n");
8168c2ecf20Sopenharmony_ci			ret = -ENOMEM;
8178c2ecf20Sopenharmony_ci			goto e_pool;
8188c2ecf20Sopenharmony_ci		}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci		cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
8218c2ecf20Sopenharmony_ci		ccp->cmd_q_count++;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci		cmd_q->ccp = ccp;
8248c2ecf20Sopenharmony_ci		cmd_q->id = i;
8258c2ecf20Sopenharmony_ci		cmd_q->dma_pool = dma_pool;
8268c2ecf20Sopenharmony_ci		mutex_init(&cmd_q->q_mutex);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		/* Page alignment satisfies our needs for N <= 128 */
8298c2ecf20Sopenharmony_ci		BUILD_BUG_ON(COMMANDS_PER_QUEUE > 128);
8308c2ecf20Sopenharmony_ci		cmd_q->qsize = Q_SIZE(Q_DESC_SIZE);
8318c2ecf20Sopenharmony_ci		cmd_q->qbase = dmam_alloc_coherent(dev, cmd_q->qsize,
8328c2ecf20Sopenharmony_ci						   &cmd_q->qbase_dma,
8338c2ecf20Sopenharmony_ci						   GFP_KERNEL);
8348c2ecf20Sopenharmony_ci		if (!cmd_q->qbase) {
8358c2ecf20Sopenharmony_ci			dev_err(dev, "unable to allocate command queue\n");
8368c2ecf20Sopenharmony_ci			ret = -ENOMEM;
8378c2ecf20Sopenharmony_ci			goto e_pool;
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		cmd_q->qidx = 0;
8418c2ecf20Sopenharmony_ci		/* Preset some register values and masks that are queue
8428c2ecf20Sopenharmony_ci		 * number dependent
8438c2ecf20Sopenharmony_ci		 */
8448c2ecf20Sopenharmony_ci		cmd_q->reg_control = ccp->io_regs +
8458c2ecf20Sopenharmony_ci				     CMD5_Q_STATUS_INCR * (i + 1);
8468c2ecf20Sopenharmony_ci		cmd_q->reg_tail_lo = cmd_q->reg_control + CMD5_Q_TAIL_LO_BASE;
8478c2ecf20Sopenharmony_ci		cmd_q->reg_head_lo = cmd_q->reg_control + CMD5_Q_HEAD_LO_BASE;
8488c2ecf20Sopenharmony_ci		cmd_q->reg_int_enable = cmd_q->reg_control +
8498c2ecf20Sopenharmony_ci					CMD5_Q_INT_ENABLE_BASE;
8508c2ecf20Sopenharmony_ci		cmd_q->reg_interrupt_status = cmd_q->reg_control +
8518c2ecf20Sopenharmony_ci					      CMD5_Q_INTERRUPT_STATUS_BASE;
8528c2ecf20Sopenharmony_ci		cmd_q->reg_status = cmd_q->reg_control + CMD5_Q_STATUS_BASE;
8538c2ecf20Sopenharmony_ci		cmd_q->reg_int_status = cmd_q->reg_control +
8548c2ecf20Sopenharmony_ci					CMD5_Q_INT_STATUS_BASE;
8558c2ecf20Sopenharmony_ci		cmd_q->reg_dma_status = cmd_q->reg_control +
8568c2ecf20Sopenharmony_ci					CMD5_Q_DMA_STATUS_BASE;
8578c2ecf20Sopenharmony_ci		cmd_q->reg_dma_read_status = cmd_q->reg_control +
8588c2ecf20Sopenharmony_ci					     CMD5_Q_DMA_READ_STATUS_BASE;
8598c2ecf20Sopenharmony_ci		cmd_q->reg_dma_write_status = cmd_q->reg_control +
8608c2ecf20Sopenharmony_ci					      CMD5_Q_DMA_WRITE_STATUS_BASE;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		init_waitqueue_head(&cmd_q->int_queue);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		dev_dbg(dev, "queue #%u available\n", i);
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (ccp->cmd_q_count == 0) {
8688c2ecf20Sopenharmony_ci		dev_notice(dev, "no command queues available\n");
8698c2ecf20Sopenharmony_ci		ret = 1;
8708c2ecf20Sopenharmony_ci		goto e_pool;
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	/* Turn off the queues and disable interrupts until ready */
8748c2ecf20Sopenharmony_ci	ccp5_disable_queue_interrupts(ccp);
8758c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
8768c2ecf20Sopenharmony_ci		cmd_q = &ccp->cmd_q[i];
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		cmd_q->qcontrol = 0; /* Start with nothing */
8798c2ecf20Sopenharmony_ci		iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci		ioread32(cmd_q->reg_int_status);
8828c2ecf20Sopenharmony_ci		ioread32(cmd_q->reg_status);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		/* Clear the interrupt status */
8858c2ecf20Sopenharmony_ci		iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	dev_dbg(dev, "Requesting an IRQ...\n");
8898c2ecf20Sopenharmony_ci	/* Request an irq */
8908c2ecf20Sopenharmony_ci	ret = sp_request_ccp_irq(ccp->sp, ccp5_irq_handler, ccp->name, ccp);
8918c2ecf20Sopenharmony_ci	if (ret) {
8928c2ecf20Sopenharmony_ci		dev_err(dev, "unable to allocate an IRQ\n");
8938c2ecf20Sopenharmony_ci		goto e_pool;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci	/* Initialize the ISR tasklet */
8968c2ecf20Sopenharmony_ci	if (ccp->use_tasklet)
8978c2ecf20Sopenharmony_ci		tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh,
8988c2ecf20Sopenharmony_ci			     (unsigned long)ccp);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	dev_dbg(dev, "Loading LSB map...\n");
9018c2ecf20Sopenharmony_ci	/* Copy the private LSB mask to the public registers */
9028c2ecf20Sopenharmony_ci	status_lo = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET);
9038c2ecf20Sopenharmony_ci	status_hi = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_HI_OFFSET);
9048c2ecf20Sopenharmony_ci	iowrite32(status_lo, ccp->io_regs + LSB_PUBLIC_MASK_LO_OFFSET);
9058c2ecf20Sopenharmony_ci	iowrite32(status_hi, ccp->io_regs + LSB_PUBLIC_MASK_HI_OFFSET);
9068c2ecf20Sopenharmony_ci	status = ((u64)status_hi<<30) | (u64)status_lo;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	dev_dbg(dev, "Configuring virtual queues...\n");
9098c2ecf20Sopenharmony_ci	/* Configure size of each virtual queue accessible to host */
9108c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
9118c2ecf20Sopenharmony_ci		u32 dma_addr_lo;
9128c2ecf20Sopenharmony_ci		u32 dma_addr_hi;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		cmd_q = &ccp->cmd_q[i];
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		cmd_q->qcontrol &= ~(CMD5_Q_SIZE << CMD5_Q_SHIFT);
9178c2ecf20Sopenharmony_ci		cmd_q->qcontrol |= QUEUE_SIZE_VAL << CMD5_Q_SHIFT;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		cmd_q->qdma_tail = cmd_q->qbase_dma;
9208c2ecf20Sopenharmony_ci		dma_addr_lo = low_address(cmd_q->qdma_tail);
9218c2ecf20Sopenharmony_ci		iowrite32((u32)dma_addr_lo, cmd_q->reg_tail_lo);
9228c2ecf20Sopenharmony_ci		iowrite32((u32)dma_addr_lo, cmd_q->reg_head_lo);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci		dma_addr_hi = high_address(cmd_q->qdma_tail);
9258c2ecf20Sopenharmony_ci		cmd_q->qcontrol |= (dma_addr_hi << 16);
9268c2ecf20Sopenharmony_ci		iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		/* Find the LSB regions accessible to the queue */
9298c2ecf20Sopenharmony_ci		ccp_find_lsb_regions(cmd_q, status);
9308c2ecf20Sopenharmony_ci		cmd_q->lsb = -1; /* Unassigned value */
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	dev_dbg(dev, "Assigning LSBs...\n");
9348c2ecf20Sopenharmony_ci	ret = ccp_assign_lsbs(ccp);
9358c2ecf20Sopenharmony_ci	if (ret) {
9368c2ecf20Sopenharmony_ci		dev_err(dev, "Unable to assign LSBs (%d)\n", ret);
9378c2ecf20Sopenharmony_ci		goto e_irq;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	/* Optimization: pre-allocate LSB slots for each queue */
9418c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
9428c2ecf20Sopenharmony_ci		ccp->cmd_q[i].sb_key = ccp_lsb_alloc(&ccp->cmd_q[i], 2);
9438c2ecf20Sopenharmony_ci		ccp->cmd_q[i].sb_ctx = ccp_lsb_alloc(&ccp->cmd_q[i], 2);
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	dev_dbg(dev, "Starting threads...\n");
9478c2ecf20Sopenharmony_ci	/* Create a kthread for each queue */
9488c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
9498c2ecf20Sopenharmony_ci		struct task_struct *kthread;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		cmd_q = &ccp->cmd_q[i];
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci		kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
9548c2ecf20Sopenharmony_ci					 "%s-q%u", ccp->name, cmd_q->id);
9558c2ecf20Sopenharmony_ci		if (IS_ERR(kthread)) {
9568c2ecf20Sopenharmony_ci			dev_err(dev, "error creating queue thread (%ld)\n",
9578c2ecf20Sopenharmony_ci				PTR_ERR(kthread));
9588c2ecf20Sopenharmony_ci			ret = PTR_ERR(kthread);
9598c2ecf20Sopenharmony_ci			goto e_kthread;
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		cmd_q->kthread = kthread;
9638c2ecf20Sopenharmony_ci		wake_up_process(kthread);
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	dev_dbg(dev, "Enabling interrupts...\n");
9678c2ecf20Sopenharmony_ci	ccp5_enable_queue_interrupts(ccp);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	dev_dbg(dev, "Registering device...\n");
9708c2ecf20Sopenharmony_ci	/* Put this on the unit list to make it available */
9718c2ecf20Sopenharmony_ci	ccp_add_device(ccp);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	ret = ccp_register_rng(ccp);
9748c2ecf20Sopenharmony_ci	if (ret)
9758c2ecf20Sopenharmony_ci		goto e_kthread;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	/* Register the DMA engine support */
9788c2ecf20Sopenharmony_ci	ret = ccp_dmaengine_register(ccp);
9798c2ecf20Sopenharmony_ci	if (ret)
9808c2ecf20Sopenharmony_ci		goto e_hwrng;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_CCP_DEBUGFS
9838c2ecf20Sopenharmony_ci	/* Set up debugfs entries */
9848c2ecf20Sopenharmony_ci	ccp5_debugfs_setup(ccp);
9858c2ecf20Sopenharmony_ci#endif
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	return 0;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cie_hwrng:
9908c2ecf20Sopenharmony_ci	ccp_unregister_rng(ccp);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cie_kthread:
9938c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
9948c2ecf20Sopenharmony_ci		if (ccp->cmd_q[i].kthread)
9958c2ecf20Sopenharmony_ci			kthread_stop(ccp->cmd_q[i].kthread);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cie_irq:
9988c2ecf20Sopenharmony_ci	sp_free_ccp_irq(ccp->sp, ccp);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cie_pool:
10018c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
10028c2ecf20Sopenharmony_ci		dma_pool_destroy(ccp->cmd_q[i].dma_pool);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	return ret;
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic void ccp5_destroy(struct ccp_device *ccp)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct ccp_cmd_queue *cmd_q;
10108c2ecf20Sopenharmony_ci	struct ccp_cmd *cmd;
10118c2ecf20Sopenharmony_ci	unsigned int i;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	/* Unregister the DMA engine */
10148c2ecf20Sopenharmony_ci	ccp_dmaengine_unregister(ccp);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	/* Unregister the RNG */
10178c2ecf20Sopenharmony_ci	ccp_unregister_rng(ccp);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	/* Remove this device from the list of available units first */
10208c2ecf20Sopenharmony_ci	ccp_del_device(ccp);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_CCP_DEBUGFS
10238c2ecf20Sopenharmony_ci	/* We're in the process of tearing down the entire driver;
10248c2ecf20Sopenharmony_ci	 * when all the devices are gone clean up debugfs
10258c2ecf20Sopenharmony_ci	 */
10268c2ecf20Sopenharmony_ci	if (ccp_present())
10278c2ecf20Sopenharmony_ci		ccp5_debugfs_destroy();
10288c2ecf20Sopenharmony_ci#endif
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	/* Disable and clear interrupts */
10318c2ecf20Sopenharmony_ci	ccp5_disable_queue_interrupts(ccp);
10328c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++) {
10338c2ecf20Sopenharmony_ci		cmd_q = &ccp->cmd_q[i];
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci		/* Turn off the run bit */
10368c2ecf20Sopenharmony_ci		iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		/* Clear the interrupt status */
10398c2ecf20Sopenharmony_ci		iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
10408c2ecf20Sopenharmony_ci		ioread32(cmd_q->reg_int_status);
10418c2ecf20Sopenharmony_ci		ioread32(cmd_q->reg_status);
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	/* Stop the queue kthreads */
10458c2ecf20Sopenharmony_ci	for (i = 0; i < ccp->cmd_q_count; i++)
10468c2ecf20Sopenharmony_ci		if (ccp->cmd_q[i].kthread)
10478c2ecf20Sopenharmony_ci			kthread_stop(ccp->cmd_q[i].kthread);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	sp_free_ccp_irq(ccp->sp, ccp);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* Flush the cmd and backlog queue */
10528c2ecf20Sopenharmony_ci	while (!list_empty(&ccp->cmd)) {
10538c2ecf20Sopenharmony_ci		/* Invoke the callback directly with an error code */
10548c2ecf20Sopenharmony_ci		cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
10558c2ecf20Sopenharmony_ci		list_del(&cmd->entry);
10568c2ecf20Sopenharmony_ci		cmd->callback(cmd->data, -ENODEV);
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci	while (!list_empty(&ccp->backlog)) {
10598c2ecf20Sopenharmony_ci		/* Invoke the callback directly with an error code */
10608c2ecf20Sopenharmony_ci		cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
10618c2ecf20Sopenharmony_ci		list_del(&cmd->entry);
10628c2ecf20Sopenharmony_ci		cmd->callback(cmd->data, -ENODEV);
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic void ccp5_config(struct ccp_device *ccp)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	/* Public side */
10698c2ecf20Sopenharmony_ci	iowrite32(0x0, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET);
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic void ccp5other_config(struct ccp_device *ccp)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	int i;
10758c2ecf20Sopenharmony_ci	u32 rnd;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	/* We own all of the queues on the NTB CCP */
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	iowrite32(0x00012D57, ccp->io_regs + CMD5_TRNG_CTL_OFFSET);
10808c2ecf20Sopenharmony_ci	iowrite32(0x00000003, ccp->io_regs + CMD5_CONFIG_0_OFFSET);
10818c2ecf20Sopenharmony_ci	for (i = 0; i < 12; i++) {
10828c2ecf20Sopenharmony_ci		rnd = ioread32(ccp->io_regs + TRNG_OUT_REG);
10838c2ecf20Sopenharmony_ci		iowrite32(rnd, ccp->io_regs + CMD5_AES_MASK_OFFSET);
10848c2ecf20Sopenharmony_ci	}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	iowrite32(0x0000001F, ccp->io_regs + CMD5_QUEUE_MASK_OFFSET);
10878c2ecf20Sopenharmony_ci	iowrite32(0x00005B6D, ccp->io_regs + CMD5_QUEUE_PRIO_OFFSET);
10888c2ecf20Sopenharmony_ci	iowrite32(0x00000000, ccp->io_regs + CMD5_CMD_TIMEOUT_OFFSET);
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	iowrite32(0x3FFFFFFF, ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET);
10918c2ecf20Sopenharmony_ci	iowrite32(0x000003FF, ccp->io_regs + LSB_PRIVATE_MASK_HI_OFFSET);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	iowrite32(0x00108823, ccp->io_regs + CMD5_CLK_GATE_CTL_OFFSET);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	ccp5_config(ccp);
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci/* Version 5 adds some function, but is essentially the same as v5 */
10998c2ecf20Sopenharmony_cistatic const struct ccp_actions ccp5_actions = {
11008c2ecf20Sopenharmony_ci	.aes = ccp5_perform_aes,
11018c2ecf20Sopenharmony_ci	.xts_aes = ccp5_perform_xts_aes,
11028c2ecf20Sopenharmony_ci	.sha = ccp5_perform_sha,
11038c2ecf20Sopenharmony_ci	.des3 = ccp5_perform_des3,
11048c2ecf20Sopenharmony_ci	.rsa = ccp5_perform_rsa,
11058c2ecf20Sopenharmony_ci	.passthru = ccp5_perform_passthru,
11068c2ecf20Sopenharmony_ci	.ecc = ccp5_perform_ecc,
11078c2ecf20Sopenharmony_ci	.sballoc = ccp_lsb_alloc,
11088c2ecf20Sopenharmony_ci	.sbfree = ccp_lsb_free,
11098c2ecf20Sopenharmony_ci	.init = ccp5_init,
11108c2ecf20Sopenharmony_ci	.destroy = ccp5_destroy,
11118c2ecf20Sopenharmony_ci	.get_free_slots = ccp5_get_free_slots,
11128c2ecf20Sopenharmony_ci};
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ciconst struct ccp_vdata ccpv5a = {
11158c2ecf20Sopenharmony_ci	.version = CCP_VERSION(5, 0),
11168c2ecf20Sopenharmony_ci	.setup = ccp5_config,
11178c2ecf20Sopenharmony_ci	.perform = &ccp5_actions,
11188c2ecf20Sopenharmony_ci	.offset = 0x0,
11198c2ecf20Sopenharmony_ci	.rsamax = CCP5_RSA_MAX_WIDTH,
11208c2ecf20Sopenharmony_ci};
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ciconst struct ccp_vdata ccpv5b = {
11238c2ecf20Sopenharmony_ci	.version = CCP_VERSION(5, 0),
11248c2ecf20Sopenharmony_ci	.dma_chan_attr = DMA_PRIVATE,
11258c2ecf20Sopenharmony_ci	.setup = ccp5other_config,
11268c2ecf20Sopenharmony_ci	.perform = &ccp5_actions,
11278c2ecf20Sopenharmony_ci	.offset = 0x0,
11288c2ecf20Sopenharmony_ci	.rsamax = CCP5_RSA_MAX_WIDTH,
11298c2ecf20Sopenharmony_ci};
1130