xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/rkce_core.c (revision 8f7f431fc3314b4d44fc6ab0ecd2b6ae4ecaa9b9)
100565589SLin Jinhan // SPDX-License-Identifier: GPL-2.0
200565589SLin Jinhan /*
300565589SLin Jinhan  * Crypto acceleration support for Rockchip crypto engine
400565589SLin Jinhan  *
500565589SLin Jinhan  * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
600565589SLin Jinhan  *
700565589SLin Jinhan  * Author: Lin Jinhan <troy.lin@rock-chips.com>
800565589SLin Jinhan  *
900565589SLin Jinhan  */
1000565589SLin Jinhan 
1100565589SLin Jinhan #include <linux/bug.h>
1200565589SLin Jinhan #include <linux/delay.h>
1300565589SLin Jinhan #include <linux/string.h>
1400565589SLin Jinhan 
1500565589SLin Jinhan #include "rockchip/rkce_core.h"
1600565589SLin Jinhan #include "rockchip/rkce_debug.h"
1700565589SLin Jinhan #include "rockchip/rkce_error.h"
1800565589SLin Jinhan #include "rockchip/rkce_reg.h"
1900565589SLin Jinhan 
2000565589SLin Jinhan struct rkce_chn_info {
2100565589SLin Jinhan 	void		*td_virt;
2200565589SLin Jinhan 	uint32_t	int_st;
2300565589SLin Jinhan 	uint32_t	td_id;
2400565589SLin Jinhan 	int		result;
2500565589SLin Jinhan 
2600565589SLin Jinhan 	request_cb_func cb_func;
2700565589SLin Jinhan };
2800565589SLin Jinhan 
2900565589SLin Jinhan struct rkce_hardware {
3000565589SLin Jinhan 	struct RKCE_REG		*rkce_reg;
3100565589SLin Jinhan 
3200565589SLin Jinhan 	struct rkce_chn_info	chn[RKCE_TD_TYPE_MAX];
3300565589SLin Jinhan };
3400565589SLin Jinhan 
3500565589SLin Jinhan #define RST_TIMEOUT_MS		100
3600565589SLin Jinhan #define TD_PUSH_TIMEOUT_MS	3000
3700565589SLin Jinhan 
3800565589SLin Jinhan #define IP_VERSION_MASK		(0xfU >> 28)
3900565589SLin Jinhan #define IP_VERSION_RKCE		(0x1U >> 28)
4000565589SLin Jinhan #define GET_IP_VERSION(ver)	((ver) & IP_VERSION_MASK)
4100565589SLin Jinhan 
4200565589SLin Jinhan #define IS_SYMM_TD(td_type)	((td_type) == RKCE_TD_TYPE_SYMM || \
4300565589SLin Jinhan 				 (td_type) == RKCE_TD_TYPE_SYMM_HASH_IN || \
4400565589SLin Jinhan 				 (td_type) == RKCE_TD_TYPE_SYMM_HASH_OUT)
4500565589SLin Jinhan 
4600565589SLin Jinhan #define IS_HASH_TD(td_type)	((td_type) == RKCE_TD_TYPE_HASH)
4700565589SLin Jinhan 
4800565589SLin Jinhan #define GET_RKCE_REG(hardware) (((struct rkce_hardware *)(hardware))->rkce_reg)
4900565589SLin Jinhan #define CHECK_RKCE_INITED(hardware)   WARN_ON_ONCE(!(hardware) || \
5000565589SLin Jinhan 					   !(((struct rkce_hardware *)(hardware))->rkce_reg))
5100565589SLin Jinhan #define POLL_TIMEOUT(condition, timeout_ms) ({                        \
5200565589SLin Jinhan 			int timeout = timeout_ms;                     \
5300565589SLin Jinhan 			while ((condition) && timeout--) {           \
5400565589SLin Jinhan 				udelay(1000);             \
5500565589SLin Jinhan 			}                                             \
5600565589SLin Jinhan 			if (timeout < 0)                              \
5700565589SLin Jinhan 				rk_err("%s timeout!\n", #condition);  \
5800565589SLin Jinhan 			(timeout < 0) ? -RKCE_TIMEOUT : 0;            \
5900565589SLin Jinhan 		})
6000565589SLin Jinhan 
6100565589SLin Jinhan static const uint32_t cipher_mode2bit_mask[] = {
6200565589SLin Jinhan 	[RKCE_SYMM_MODE_ECB]       = RKCE_AES_VER_ECB_FLAG_MASK,
6300565589SLin Jinhan 	[RKCE_SYMM_MODE_CBC]       = RKCE_AES_VER_CBC_FLAG_MASK,
6400565589SLin Jinhan 	[RKCE_SYMM_MODE_CFB]       = RKCE_AES_VER_CFB_FLAG_MASK,
6500565589SLin Jinhan 	[RKCE_SYMM_MODE_OFB]       = RKCE_AES_VER_OFB_FLAG_MASK,
6600565589SLin Jinhan 	[RKCE_SYMM_MODE_CTR]       = RKCE_AES_VER_CTR_FLAG_MASK,
6700565589SLin Jinhan 	[RKCE_SYMM_MODE_XTS]       = RKCE_AES_VER_XTS_FLAG_MASK,
6800565589SLin Jinhan 	[RKCE_SYMM_MODE_CTS]       = RKCE_AES_VER_CTS_FLAG_MASK,
6900565589SLin Jinhan 	[RKCE_SYMM_MODE_CCM]       = RKCE_AES_VER_CCM_FLAG_MASK,
7000565589SLin Jinhan 	[RKCE_SYMM_MODE_GCM]       = RKCE_AES_VER_GCM_FLAG_MASK,
7100565589SLin Jinhan 	[RKCE_SYMM_MODE_CMAC]      = RKCE_AES_VER_CMAC_FLAG_MASK,
7200565589SLin Jinhan 	[RKCE_SYMM_MODE_CBC_MAC]   = RKCE_AES_VER_CBC_MAC_FLAG_MASK,
7300565589SLin Jinhan };
7400565589SLin Jinhan 
7500565589SLin Jinhan static const uint32_t hash_algo2bit_mask[] = {
7600565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA1]       = RKCE_HASH_VER_SHA1_FLAG_MASK,
7700565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA224]     = RKCE_HASH_VER_SHA224_FLAG_MASK,
7800565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA256]     = RKCE_HASH_VER_SHA256_FLAG_MASK,
7900565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA384]     = RKCE_HASH_VER_SHA384_FLAG_MASK,
8000565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA512]     = RKCE_HASH_VER_SHA512_FLAG_MASK,
8100565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA512_224] = RKCE_HASH_VER_SHA512_224_FLAG_MASK,
8200565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA512_256] = RKCE_HASH_VER_SHA512_256_FLAG_MASK,
8300565589SLin Jinhan 	[RKCE_HASH_ALGO_MD5]        = RKCE_HASH_VER_MD5_FLAG_MASK,
8400565589SLin Jinhan 	[RKCE_HASH_ALGO_SM3]        = RKCE_HASH_VER_SM3_FLAG_MASK,
8500565589SLin Jinhan };
8600565589SLin Jinhan 
8700565589SLin Jinhan static const uint32_t hmac_algo2bit_mask[] = {
8800565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA1]       = RKCE_HMAC_VER_SHA1_FLAG_MASK,
8900565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA256]     = RKCE_HMAC_VER_SHA256_FLAG_MASK,
9000565589SLin Jinhan 	[RKCE_HASH_ALGO_SHA512]     = RKCE_HMAC_VER_SHA512_FLAG_MASK,
9100565589SLin Jinhan 	[RKCE_HASH_ALGO_MD5]        = RKCE_HMAC_VER_MD5_FLAG_MASK,
9200565589SLin Jinhan 	[RKCE_HASH_ALGO_SM3]        = RKCE_HMAC_VER_SM3_FLAG_MASK,
9300565589SLin Jinhan };
9400565589SLin Jinhan 
rk_is_cipher_support(struct RKCE_REG * rkce_reg,uint32_t algo,uint32_t mode,uint32_t key_len)9500565589SLin Jinhan static bool rk_is_cipher_support(struct RKCE_REG *rkce_reg,
9600565589SLin Jinhan 				 uint32_t algo, uint32_t mode, uint32_t key_len)
9700565589SLin Jinhan {
9800565589SLin Jinhan 	uint32_t version = 0;
9900565589SLin Jinhan 	uint32_t mask = 0;
10000565589SLin Jinhan 	bool key_len_valid = true;
10100565589SLin Jinhan 
10200565589SLin Jinhan 	switch (algo) {
10300565589SLin Jinhan 	case RKCE_SYMM_ALGO_DES:
10400565589SLin Jinhan 	case RKCE_SYMM_ALGO_TDES:
10500565589SLin Jinhan 		version = rkce_reg->DES_VER;
10600565589SLin Jinhan 
10700565589SLin Jinhan 		if (key_len == RKCE_DES_BLOCK_SIZE)
10800565589SLin Jinhan 			key_len_valid = true;
10900565589SLin Jinhan 		else if (key_len == 2 * RKCE_DES_BLOCK_SIZE ||
11000565589SLin Jinhan 			 key_len == 3 * RKCE_DES_BLOCK_SIZE)
11100565589SLin Jinhan 			key_len_valid = version & RKCE_DES_VER_TDES_FLAG_MASK;
11200565589SLin Jinhan 		else
11300565589SLin Jinhan 			key_len_valid = false;
11400565589SLin Jinhan 		break;
11500565589SLin Jinhan 	case RKCE_SYMM_ALGO_AES:
11600565589SLin Jinhan 		version = rkce_reg->AES_VER;
11700565589SLin Jinhan 
11800565589SLin Jinhan 		if (key_len == RKCE_AES_KEYSIZE_128)
11900565589SLin Jinhan 			key_len_valid = version & RKCE_AES_VER_AES128_FLAG_MASK;
12000565589SLin Jinhan 		else if (key_len == RKCE_AES_KEYSIZE_192)
12100565589SLin Jinhan 			key_len_valid = version & RKCE_AES_VER_AES192_FLAG_MASK;
12200565589SLin Jinhan 		else if (key_len == RKCE_KEY_AES_256)
12300565589SLin Jinhan 			key_len_valid = version & RKCE_AES_VER_AES256_FLAG_MASK;
12400565589SLin Jinhan 		else
12500565589SLin Jinhan 			key_len_valid = false;
12600565589SLin Jinhan 		break;
12700565589SLin Jinhan 	case RKCE_SYMM_ALGO_SM4:
12800565589SLin Jinhan 		version = rkce_reg->SM4_VER;
12900565589SLin Jinhan 
13000565589SLin Jinhan 		key_len_valid = (key_len == RKCE_SM4_KEYSIZE) ? true : false;
13100565589SLin Jinhan 		break;
13200565589SLin Jinhan 	default:
13300565589SLin Jinhan 		return false;
13400565589SLin Jinhan 	}
13500565589SLin Jinhan 
13600565589SLin Jinhan 	mask = cipher_mode2bit_mask[mode];
13700565589SLin Jinhan 
13800565589SLin Jinhan 	if (key_len == 0)
13900565589SLin Jinhan 		key_len_valid = true;
14000565589SLin Jinhan 
14100565589SLin Jinhan 	return (version & mask) && key_len_valid;
14200565589SLin Jinhan }
14300565589SLin Jinhan 
rk_is_hash_support(struct RKCE_REG * rkce_reg,uint32_t algo,uint32_t type)14400565589SLin Jinhan static bool rk_is_hash_support(struct RKCE_REG *rkce_reg, uint32_t algo, uint32_t type)
14500565589SLin Jinhan {
14600565589SLin Jinhan 	uint32_t version = 0;
14700565589SLin Jinhan 	uint32_t mask = 0;
14800565589SLin Jinhan 
14900565589SLin Jinhan 	if (type == RKCE_ALGO_TYPE_HMAC) {
15000565589SLin Jinhan 		version = rkce_reg->HMAC_VER;
15100565589SLin Jinhan 		mask    = hmac_algo2bit_mask[algo];
15200565589SLin Jinhan 	} else if (type == RKCE_ALGO_TYPE_HASH) {
15300565589SLin Jinhan 		version = rkce_reg->HASH_VER;
15400565589SLin Jinhan 		mask    = hash_algo2bit_mask[algo];
15500565589SLin Jinhan 	} else {
15600565589SLin Jinhan 		return false;
15700565589SLin Jinhan 	}
15800565589SLin Jinhan 
15900565589SLin Jinhan 	return version & mask;
16000565589SLin Jinhan }
16100565589SLin Jinhan 
rk_is_asym_support(struct RKCE_REG * rkce_reg,uint32_t algo)16200565589SLin Jinhan static bool rk_is_asym_support(struct RKCE_REG *rkce_reg, uint32_t algo)
16300565589SLin Jinhan {
16400565589SLin Jinhan 	switch (algo) {
16500565589SLin Jinhan 	case RKCE_ASYM_ALGO_RSA:
16600565589SLin Jinhan 		return !!rkce_reg->PKA_VER;
16700565589SLin Jinhan 	case RKCE_ASYM_ALGO_ECC_P192:
16800565589SLin Jinhan 	case RKCE_ASYM_ALGO_ECC_P224:
16900565589SLin Jinhan 	case RKCE_ASYM_ALGO_ECC_P256:
17000565589SLin Jinhan 	case RKCE_ASYM_ALGO_SM2:
17100565589SLin Jinhan 		return !!rkce_reg->ECC_MAX_CURVE_WIDE;
17200565589SLin Jinhan 	default:
17300565589SLin Jinhan 		return false;
17400565589SLin Jinhan 	}
17500565589SLin Jinhan }
17600565589SLin Jinhan 
rkce_hw_algo_valid(void * rkce_hw,uint32_t type,uint32_t algo,uint32_t mode)17700565589SLin Jinhan bool rkce_hw_algo_valid(void *rkce_hw, uint32_t type, uint32_t algo, uint32_t mode)
17800565589SLin Jinhan {
17900565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
18000565589SLin Jinhan 
18100565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
18200565589SLin Jinhan 
18300565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
18400565589SLin Jinhan 
18500565589SLin Jinhan 	if (type == RKCE_ALGO_TYPE_CIPHER || type == RKCE_ALGO_TYPE_AEAD) {
18600565589SLin Jinhan 		rk_debug("CIPHER");
18700565589SLin Jinhan 		return rk_is_cipher_support(rkce_reg, algo, mode, 0);
18800565589SLin Jinhan 	} else if (type == RKCE_ALGO_TYPE_HASH || type == RKCE_ALGO_TYPE_HMAC) {
18900565589SLin Jinhan 		rk_debug("HASH/HMAC");
19000565589SLin Jinhan 		return rk_is_hash_support(rkce_reg, algo, type);
19100565589SLin Jinhan 	} else if (type == RKCE_ALGO_TYPE_ASYM) {
19200565589SLin Jinhan 		rk_debug("ASYM");
19300565589SLin Jinhan 		return rk_is_asym_support(rkce_reg, algo);
19400565589SLin Jinhan 	} else {
19500565589SLin Jinhan 		return false;
19600565589SLin Jinhan 	}
19700565589SLin Jinhan }
19800565589SLin Jinhan 
rkce_get_td_type(void * td)19900565589SLin Jinhan uint32_t rkce_get_td_type(void *td)
20000565589SLin Jinhan {
20100565589SLin Jinhan 	if (!td)
20200565589SLin Jinhan 		return ~((uint32_t)0);
20300565589SLin Jinhan 
20400565589SLin Jinhan 	return ((struct rkce_symm_td *)td)->ctrl.td_type;
20500565589SLin Jinhan }
20600565589SLin Jinhan 
rkce_soft_reset(void * rkce_hw,uint32_t reset_sel)20700565589SLin Jinhan int rkce_soft_reset(void *rkce_hw, uint32_t reset_sel)
20800565589SLin Jinhan {
20900565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
21000565589SLin Jinhan 	uint32_t value = 0;
21100565589SLin Jinhan 
21200565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
21300565589SLin Jinhan 
21400565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
21500565589SLin Jinhan 
21600565589SLin Jinhan 	if (reset_sel & RKCE_RESET_SYMM)
21700565589SLin Jinhan 		value |= RKCE_RST_CTL_SW_SYMM_RESET_SHIFT;
21800565589SLin Jinhan 
21900565589SLin Jinhan 	if (reset_sel & RKCE_RESET_HASH)
22000565589SLin Jinhan 		value |= RKCE_RST_CTL_SW_HASH_RESET_SHIFT;
22100565589SLin Jinhan 
22200565589SLin Jinhan 	if (reset_sel & RKCE_RESET_PKA)
22300565589SLin Jinhan 		value |= RKCE_RST_CTL_SW_PKA_RESET_SHIFT;
22400565589SLin Jinhan 
22500565589SLin Jinhan 	rkce_reg->RST_CTL = value | RKCE_WRITE_MASK_ALL;
22600565589SLin Jinhan 
22700565589SLin Jinhan 	return POLL_TIMEOUT(rkce_reg->RST_CTL, RST_TIMEOUT_MS);
22800565589SLin Jinhan }
22900565589SLin Jinhan 
rkce_check_version(struct RKCE_REG * rkce_reg)23000565589SLin Jinhan static int rkce_check_version(struct RKCE_REG *rkce_reg)
23100565589SLin Jinhan {
23200565589SLin Jinhan 	rk_debug("rkce_reg->CE_VER = %08x\n", rkce_reg->CE_VER);
23300565589SLin Jinhan 
23400565589SLin Jinhan 	if (GET_IP_VERSION(rkce_reg->CE_VER) != IP_VERSION_RKCE) {
23500565589SLin Jinhan 		rk_err("IP version is %08x not a RKCE module.\n", rkce_reg->CE_VER);
23600565589SLin Jinhan 		return -RKCE_FAULT;
23700565589SLin Jinhan 	}
23800565589SLin Jinhan 
23900565589SLin Jinhan 	return RKCE_SUCCESS;
24000565589SLin Jinhan }
24100565589SLin Jinhan 
rkce_init(void * rkce_hw)24200565589SLin Jinhan static int rkce_init(void *rkce_hw)
24300565589SLin Jinhan {
24400565589SLin Jinhan 	struct RKCE_REG *rkce_reg = GET_RKCE_REG(rkce_hw);
24500565589SLin Jinhan 	uint32_t value = 0;
24600565589SLin Jinhan 	int ret;
24700565589SLin Jinhan 
248fc67ecfeSLin Jinhan 	ret = rkce_check_version(rkce_reg);
24900565589SLin Jinhan 	if (ret)
25000565589SLin Jinhan 		goto exit;
25100565589SLin Jinhan 
25200565589SLin Jinhan 	rkce_soft_reset(rkce_hw, RKCE_RESET_SYMM | RKCE_RESET_HASH | RKCE_RESET_PKA);
25300565589SLin Jinhan 
25400565589SLin Jinhan 	/* clear symm interrupt register */
25500565589SLin Jinhan 	rkce_reg->SYMM_INT_EN = 0;
25600565589SLin Jinhan 	value = rkce_reg->SYMM_INT_ST;
25700565589SLin Jinhan 	rkce_reg->SYMM_INT_ST = value;
25800565589SLin Jinhan 
25900565589SLin Jinhan 	ret = POLL_TIMEOUT(rkce_reg->SYMM_INT_ST, RST_TIMEOUT_MS);
26000565589SLin Jinhan 	if (ret)
26100565589SLin Jinhan 		goto exit;
26200565589SLin Jinhan 
26300565589SLin Jinhan 	/* clear hash interrupt register */
26400565589SLin Jinhan 	rkce_reg->HASH_INT_EN = 0;
26500565589SLin Jinhan 	value = rkce_reg->HASH_INT_ST;
26600565589SLin Jinhan 	rkce_reg->HASH_INT_ST = value;
26700565589SLin Jinhan 
26800565589SLin Jinhan 	ret = POLL_TIMEOUT(rkce_reg->HASH_INT_ST, RST_TIMEOUT_MS);
26900565589SLin Jinhan 	if (ret)
27000565589SLin Jinhan 		goto exit;
27100565589SLin Jinhan 
27200565589SLin Jinhan 	if (rkce_reg->SYMM_CONTEXT_SIZE != RKCE_TD_SYMM_CTX_SIZE) {
27300565589SLin Jinhan 		rk_err("rkce symm context size (%u) != %u\n",
27400565589SLin Jinhan 		       rkce_reg->SYMM_CONTEXT_SIZE, RKCE_TD_SYMM_CTX_SIZE);
27500565589SLin Jinhan 		return -RKCE_INVAL;
27600565589SLin Jinhan 	}
27700565589SLin Jinhan 
27800565589SLin Jinhan 	if (rkce_reg->HASH_CONTEXT_SIZE != RKCE_TD_HASH_CTX_SIZE) {
27900565589SLin Jinhan 		rk_err("rkce hash context size (%u) != %u\n",
28000565589SLin Jinhan 		       rkce_reg->HASH_CONTEXT_SIZE, RKCE_TD_HASH_CTX_SIZE);
28100565589SLin Jinhan 		return -RKCE_INVAL;
28200565589SLin Jinhan 	}
28300565589SLin Jinhan 
28400565589SLin Jinhan exit:
28500565589SLin Jinhan 	return ret;
28600565589SLin Jinhan }
28700565589SLin Jinhan 
rkce_hardware_alloc(void __iomem * reg_base)28800565589SLin Jinhan void *rkce_hardware_alloc(void __iomem *reg_base)
28900565589SLin Jinhan {
29000565589SLin Jinhan 	struct rkce_hardware *hardware;
29100565589SLin Jinhan 
29200565589SLin Jinhan 	rk_debug("reg_base = %p", reg_base);
29300565589SLin Jinhan 
29400565589SLin Jinhan 	if (!reg_base)
29500565589SLin Jinhan 		return NULL;
29600565589SLin Jinhan 
29700565589SLin Jinhan 	hardware = malloc(sizeof(*hardware));
29800565589SLin Jinhan 	if (!hardware)
29900565589SLin Jinhan 		return NULL;
30000565589SLin Jinhan 
30100565589SLin Jinhan 	hardware->rkce_reg = reg_base;
30200565589SLin Jinhan 
30300565589SLin Jinhan 	if (rkce_init(hardware) != 0) {
30400565589SLin Jinhan 		free(hardware);
30500565589SLin Jinhan 		return NULL;
30600565589SLin Jinhan 	}
30700565589SLin Jinhan 
30800565589SLin Jinhan 	rk_debug("hardware = %p", hardware);
30900565589SLin Jinhan 
31000565589SLin Jinhan 	return hardware;
31100565589SLin Jinhan }
31200565589SLin Jinhan 
rkce_hardware_free(void * rkce_hw)31300565589SLin Jinhan void rkce_hardware_free(void *rkce_hw)
31400565589SLin Jinhan {
31500565589SLin Jinhan 	if (!rkce_hw)
31600565589SLin Jinhan 		return;
31700565589SLin Jinhan 
31800565589SLin Jinhan 	free(rkce_hw);
31900565589SLin Jinhan }
32000565589SLin Jinhan 
rkce_dump_reginfo(void * rkce_hw)32100565589SLin Jinhan void rkce_dump_reginfo(void *rkce_hw)
32200565589SLin Jinhan {
32300565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
32400565589SLin Jinhan 
32500565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
32600565589SLin Jinhan 
32700565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
32800565589SLin Jinhan 
32900565589SLin Jinhan 	rk_info("\n============================== reg info ===========================\n");
33000565589SLin Jinhan 	rk_info("FIFO_ST           = %08x\n", rkce_reg->FIFO_ST);
33100565589SLin Jinhan 	rk_info("\n");
33200565589SLin Jinhan 	rk_info("SYMM_INT_EN       = %08x\n", rkce_reg->SYMM_INT_EN);
33300565589SLin Jinhan 	rk_info("SYMM_INT_ST       = %08x\n", rkce_reg->SYMM_INT_ST);
33400565589SLin Jinhan 	rk_info("SYMM_TD_ST        = %08x\n", rkce_reg->SYMM_TD_ST);
33500565589SLin Jinhan 	rk_info("SYMM_TD_ID        = %08x\n", rkce_reg->SYMM_TD_ID);
33600565589SLin Jinhan 	rk_info("SYMM_ST_DBG       = %08x\n", rkce_reg->SYMM_ST_DBG);
33700565589SLin Jinhan 	rk_info("SYMM_TD_ADDR_DBG  = %08x\n", rkce_reg->SYMM_TD_ADDR_DBG);
33800565589SLin Jinhan 	rk_info("SYMM_TD_GRANT_DBG = %08x\n", rkce_reg->SYMM_TD_GRANT_DBG);
33900565589SLin Jinhan 	rk_info("\n");
34000565589SLin Jinhan 	rk_info("HASH_INT_EN       = %08x\n", rkce_reg->HASH_INT_EN);
34100565589SLin Jinhan 	rk_info("HASH_INT_ST       = %08x\n", rkce_reg->HASH_INT_ST);
34200565589SLin Jinhan 	rk_info("HASH_TD_ST        = %08x\n", rkce_reg->HASH_TD_ST);
34300565589SLin Jinhan 	rk_info("HASH_TD_ID        = %08x\n", rkce_reg->HASH_TD_ID);
34400565589SLin Jinhan 	rk_info("HASH_ST_DBG       = %08x\n", rkce_reg->HASH_ST_DBG);
34500565589SLin Jinhan 	rk_info("HASH_TD_ADDR_DBG  = %08x\n", rkce_reg->HASH_TD_ADDR_DBG);
34600565589SLin Jinhan 	rk_info("HASH_TD_GRANT_DBG = %08x\n", rkce_reg->HASH_TD_GRANT_DBG);
34700565589SLin Jinhan 	rk_info("===================================================================\n");
34800565589SLin Jinhan }
34900565589SLin Jinhan 
rkce_push_td(void * rkce_hw,void * td)35000565589SLin Jinhan int rkce_push_td(void *rkce_hw, void *td)
35100565589SLin Jinhan {
35200565589SLin Jinhan 	int ret = RKCE_SUCCESS;
35300565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
35400565589SLin Jinhan 	uint32_t td_type;
35500565589SLin Jinhan 	struct rkce_hardware *hardware = rkce_hw;
35600565589SLin Jinhan 
35700565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
35800565589SLin Jinhan 
35900565589SLin Jinhan 	if (!td)
36000565589SLin Jinhan 		return -RKCE_INVAL;
36100565589SLin Jinhan 
36200565589SLin Jinhan 	td_type  = rkce_get_td_type(td);
36300565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
36400565589SLin Jinhan 
36500565589SLin Jinhan 	rkce_dump_td(td);
36600565589SLin Jinhan 
36700565589SLin Jinhan 	if (IS_SYMM_TD(td_type)) {
36800565589SLin Jinhan 		rk_debug("rkce symm push td virt(%p), phys(%lx)\n",
36900565589SLin Jinhan 			 td, rkce_cma_virt2phys(td));
37000565589SLin Jinhan 
37100565589SLin Jinhan 		WRITE_ONCE(rkce_reg->SYMM_INT_EN, 0x3f);
37200565589SLin Jinhan 
37300565589SLin Jinhan 		/* wait symm fifo valid */
37400565589SLin Jinhan 		ret = POLL_TIMEOUT(rkce_reg->TD_LOAD_CTRL & RKCE_TD_LOAD_CTRL_SYMM_TLR_MASK,
37500565589SLin Jinhan 				   TD_PUSH_TIMEOUT_MS);
37600565589SLin Jinhan 		if (ret)
37700565589SLin Jinhan 			goto exit;
37800565589SLin Jinhan 
37900565589SLin Jinhan 		/* set task desc address */
38000565589SLin Jinhan 		rkce_reg->TD_ADDR = rkce_cma_virt2phys(td);
38100565589SLin Jinhan 		hardware->chn[RKCE_TD_TYPE_SYMM].td_virt = td;
38200565589SLin Jinhan 
38300565589SLin Jinhan 		/* tell rkce to load task desc address as symm td */
38400565589SLin Jinhan 		rkce_reg->TD_LOAD_CTRL = 0xffff0000 | RKCE_TD_LOAD_CTRL_SYMM_TLR_MASK;
38500565589SLin Jinhan 	} else if (IS_HASH_TD(td_type)) {
38600565589SLin Jinhan 		rk_debug("rkce hash push td virt(%p), phys(%lx)\n",
38700565589SLin Jinhan 			 td, rkce_cma_virt2phys(td));
38800565589SLin Jinhan 
38900565589SLin Jinhan 		WRITE_ONCE(rkce_reg->HASH_INT_EN, 0x3f);
39000565589SLin Jinhan 
39100565589SLin Jinhan 		/* wait hash fifo valid */
39200565589SLin Jinhan 		ret = POLL_TIMEOUT(rkce_reg->TD_LOAD_CTRL & RKCE_TD_LOAD_CTRL_HASH_TLR_MASK,
39300565589SLin Jinhan 				   TD_PUSH_TIMEOUT_MS);
39400565589SLin Jinhan 		if (ret)
39500565589SLin Jinhan 			goto exit;
39600565589SLin Jinhan 
39700565589SLin Jinhan 		/* set task desc address */
39800565589SLin Jinhan 		rkce_reg->TD_ADDR = rkce_cma_virt2phys(td);
39900565589SLin Jinhan 		hardware->chn[RKCE_TD_TYPE_HASH].td_virt = td;
40000565589SLin Jinhan 
40100565589SLin Jinhan 		/* tell rkce to load task desc address as hash td */
40200565589SLin Jinhan 		rkce_reg->TD_LOAD_CTRL = 0xffff0000 | RKCE_TD_LOAD_CTRL_HASH_TLR_MASK;
40300565589SLin Jinhan 	} else {
40400565589SLin Jinhan 		return -RKCE_INVAL;
40500565589SLin Jinhan 	}
40600565589SLin Jinhan 
40700565589SLin Jinhan exit:
40800565589SLin Jinhan 	return ret;
40900565589SLin Jinhan }
41000565589SLin Jinhan 
rkce_push_td_sync(void * rkce_hw,void * td,uint32_t timeout_ms)41100565589SLin Jinhan int rkce_push_td_sync(void *rkce_hw, void *td, uint32_t timeout_ms)
41200565589SLin Jinhan {
41300565589SLin Jinhan 	int ret = RKCE_SUCCESS;
41400565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
41500565589SLin Jinhan 	uint32_t td_type;
41600565589SLin Jinhan 	uint32_t value, mask;
41700565589SLin Jinhan 
41800565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
41900565589SLin Jinhan 
42000565589SLin Jinhan 	if (!td)
42100565589SLin Jinhan 		return -RKCE_INVAL;
42200565589SLin Jinhan 
42300565589SLin Jinhan 	td_type  = rkce_get_td_type(td);
42400565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
42500565589SLin Jinhan 
42600565589SLin Jinhan 	rkce_dump_td(td);
42700565589SLin Jinhan 
42800565589SLin Jinhan 	if (IS_SYMM_TD(td_type)) {
42900565589SLin Jinhan 		rk_debug("rkce symm push td virt(%p), phys(%lx)\n",
43000565589SLin Jinhan 			 td, rkce_cma_virt2phys(td));
43100565589SLin Jinhan 
43200565589SLin Jinhan 		WRITE_ONCE(rkce_reg->SYMM_INT_EN, 0x00);
43300565589SLin Jinhan 
43400565589SLin Jinhan 		/* wait symm fifo valid */
43500565589SLin Jinhan 		ret = POLL_TIMEOUT(rkce_reg->TD_LOAD_CTRL & RKCE_TD_LOAD_CTRL_SYMM_TLR_MASK,
43600565589SLin Jinhan 				   timeout_ms);
43700565589SLin Jinhan 		if (ret)
43800565589SLin Jinhan 			goto exit;
43900565589SLin Jinhan 
44000565589SLin Jinhan 		/* set task desc address */
44100565589SLin Jinhan 		rkce_reg->TD_ADDR = rkce_cma_virt2phys(td);
44200565589SLin Jinhan 
44300565589SLin Jinhan 		/* tell rkce to load task desc address as symm td */
44400565589SLin Jinhan 		rkce_reg->TD_LOAD_CTRL = 0xffff0000 | RKCE_TD_LOAD_CTRL_SYMM_TLR_MASK;
44500565589SLin Jinhan 
44600565589SLin Jinhan 		/* wait symm done */
44700565589SLin Jinhan 		ret = POLL_TIMEOUT(!(rkce_reg->SYMM_INT_ST), timeout_ms);
44800565589SLin Jinhan 		mask  = RKCE_SYMM_INT_ST_TD_DONE_MASK;
44900565589SLin Jinhan 		value = READ_ONCE(rkce_reg->SYMM_INT_ST);
45000565589SLin Jinhan 		WRITE_ONCE(rkce_reg->SYMM_INT_ST, value);
45100565589SLin Jinhan 		rk_debug("symm ret = %d, value = %08x, IN_ST = %08x\n",
45200565589SLin Jinhan 			 ret, value, READ_ONCE(rkce_reg->SYMM_INT_ST));
45300565589SLin Jinhan 	} else if (IS_HASH_TD(td_type)) {
45400565589SLin Jinhan 		rk_debug("rkce hash push td virt(%p), phys(%lx)\n",
45500565589SLin Jinhan 			 td, rkce_cma_virt2phys(td));
45600565589SLin Jinhan 
45700565589SLin Jinhan 		WRITE_ONCE(rkce_reg->HASH_INT_EN, 0x00);
45800565589SLin Jinhan 
45900565589SLin Jinhan 		/* wait hash fifo valid */
46000565589SLin Jinhan 		ret = POLL_TIMEOUT(rkce_reg->TD_LOAD_CTRL & RKCE_TD_LOAD_CTRL_HASH_TLR_MASK,
46100565589SLin Jinhan 				   timeout_ms);
46200565589SLin Jinhan 		if (ret)
46300565589SLin Jinhan 			goto exit;
46400565589SLin Jinhan 
46500565589SLin Jinhan 		/* set task desc address */
46600565589SLin Jinhan 		rkce_reg->TD_ADDR = rkce_cma_virt2phys(td);
46700565589SLin Jinhan 
46800565589SLin Jinhan 		/* tell rkce to load task desc address as hash td */
46900565589SLin Jinhan 		rkce_reg->TD_LOAD_CTRL = 0xffff0000 | RKCE_TD_LOAD_CTRL_HASH_TLR_MASK;
47000565589SLin Jinhan 
47100565589SLin Jinhan 		/* wait hash done */
47200565589SLin Jinhan 		ret = POLL_TIMEOUT(!(rkce_reg->HASH_INT_ST), timeout_ms);
47300565589SLin Jinhan 		mask  = RKCE_HASH_INT_ST_TD_DONE_MASK;
47400565589SLin Jinhan 		value = READ_ONCE(rkce_reg->HASH_INT_ST);
47500565589SLin Jinhan 		WRITE_ONCE(rkce_reg->HASH_INT_ST, value);
47600565589SLin Jinhan 		rk_debug("hash ret = %d, value = %08x, INT_ST = %08x\n",
47700565589SLin Jinhan 			 ret, value, READ_ONCE(rkce_reg->HASH_INT_ST));
47800565589SLin Jinhan 	} else {
47900565589SLin Jinhan 		rk_debug("unknown td_type = %u\n", td_type);
48000565589SLin Jinhan 		return -RKCE_INVAL;
48100565589SLin Jinhan 	}
48200565589SLin Jinhan 
48300565589SLin Jinhan 	if (ret)
48400565589SLin Jinhan 		goto exit;
48500565589SLin Jinhan 
48600565589SLin Jinhan 	ret = (value == mask) ? 0 : -RKCE_FAULT;
48700565589SLin Jinhan exit:
48800565589SLin Jinhan 	return ret;
48900565589SLin Jinhan }
49000565589SLin Jinhan 
rkce_init_symm_td(struct rkce_symm_td * td,struct rkce_symm_td_buf * buf)49100565589SLin Jinhan int rkce_init_symm_td(struct rkce_symm_td *td, struct rkce_symm_td_buf *buf)
49200565589SLin Jinhan {
49300565589SLin Jinhan 	if (!td ||
49400565589SLin Jinhan 	    !buf ||
49500565589SLin Jinhan 	    !rkce_cma_virt2phys(td) ||
49600565589SLin Jinhan 	    !rkce_cma_virt2phys(buf)) {
49700565589SLin Jinhan 		rk_debug("td = %p buf = %p", td, buf);
49800565589SLin Jinhan 		return -RKCE_INVAL;
49900565589SLin Jinhan 	}
50000565589SLin Jinhan 
50100565589SLin Jinhan 	memset(td, 0x00, sizeof(*td));
50200565589SLin Jinhan 
50300565589SLin Jinhan 	td->ctrl.td_type  = RKCE_TD_TYPE_SYMM;
50400565589SLin Jinhan 	td->task_id       = rkce_cma_virt2phys(buf);
50500565589SLin Jinhan 	td->key_addr      = rkce_cma_virt2phys(buf->key1);
50600565589SLin Jinhan 	td->iv_addr       = rkce_cma_virt2phys(buf->iv);
50700565589SLin Jinhan 	td->gcm_len_addr  = rkce_cma_virt2phys(&buf->gcm_len);
50800565589SLin Jinhan 	td->tag_addr      = rkce_cma_virt2phys(buf->tag);
50900565589SLin Jinhan 	td->symm_ctx_addr = rkce_cma_virt2phys(buf->ctx);
51000565589SLin Jinhan 
51100565589SLin Jinhan 	return RKCE_SUCCESS;
51200565589SLin Jinhan }
51300565589SLin Jinhan 
rkce_init_hash_td(struct rkce_hash_td * td,struct rkce_hash_td_buf * buf)51400565589SLin Jinhan int rkce_init_hash_td(struct rkce_hash_td *td, struct rkce_hash_td_buf *buf)
51500565589SLin Jinhan {
51600565589SLin Jinhan 	if (!td ||
51700565589SLin Jinhan 	    !buf ||
51800565589SLin Jinhan 	    !rkce_cma_virt2phys(td) ||
51900565589SLin Jinhan 	    !rkce_cma_virt2phys(buf)) {
52000565589SLin Jinhan 		rk_debug("td = %p buf = %p", td, buf);
52100565589SLin Jinhan 		return -RKCE_INVAL;
52200565589SLin Jinhan 	}
52300565589SLin Jinhan 
52400565589SLin Jinhan 	memset(td, 0x00, sizeof(*td));
52500565589SLin Jinhan 
52600565589SLin Jinhan 	td->ctrl.td_type  = RKCE_TD_TYPE_HASH;
52700565589SLin Jinhan 	td->task_id       = rkce_cma_virt2phys(buf);
52800565589SLin Jinhan 	td->key_addr      = rkce_cma_virt2phys(buf->key);
52900565589SLin Jinhan 	td->hash_addr     = rkce_cma_virt2phys(buf->hash);
53000565589SLin Jinhan 	td->hash_ctx_addr = rkce_cma_virt2phys(buf->ctx);
53100565589SLin Jinhan 
53200565589SLin Jinhan 	return RKCE_SUCCESS;
53300565589SLin Jinhan }
53400565589SLin Jinhan 
rkce_irq_callback_set(void * rkce_hw,enum rkce_td_type td_type,request_cb_func cb_func)53500565589SLin Jinhan int rkce_irq_callback_set(void *rkce_hw, enum rkce_td_type td_type, request_cb_func cb_func)
53600565589SLin Jinhan {
53700565589SLin Jinhan 	struct rkce_hardware *hardware = rkce_hw;
53800565589SLin Jinhan 
53900565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
54000565589SLin Jinhan 
54100565589SLin Jinhan 	if (!cb_func)
54200565589SLin Jinhan 		return -RKCE_INVAL;
54300565589SLin Jinhan 
54400565589SLin Jinhan 	if (td_type == RKCE_TD_TYPE_SYMM)
54500565589SLin Jinhan 		hardware->chn[RKCE_TD_TYPE_SYMM].cb_func = cb_func;
54600565589SLin Jinhan 	else if (td_type == RKCE_TD_TYPE_HASH)
54700565589SLin Jinhan 		hardware->chn[RKCE_TD_TYPE_HASH].cb_func = cb_func;
54800565589SLin Jinhan 	else
54900565589SLin Jinhan 		return -RKCE_INVAL;
55000565589SLin Jinhan 
55100565589SLin Jinhan 	return RKCE_SUCCESS;
55200565589SLin Jinhan }
55300565589SLin Jinhan 
rkce_irq_handler(void * rkce_hw)55400565589SLin Jinhan void rkce_irq_handler(void *rkce_hw)
55500565589SLin Jinhan {
55600565589SLin Jinhan 	struct rkce_chn_info *cur_chn;
55700565589SLin Jinhan 	struct RKCE_REG *rkce_reg;
55800565589SLin Jinhan 	struct rkce_hardware *hardware = rkce_hw;
55900565589SLin Jinhan 
56000565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
56100565589SLin Jinhan 
56200565589SLin Jinhan 	rkce_reg = GET_RKCE_REG(rkce_hw);
56300565589SLin Jinhan 
56400565589SLin Jinhan 	if (rkce_reg->SYMM_INT_ST) {
56500565589SLin Jinhan 		cur_chn = &hardware->chn[RKCE_TD_TYPE_SYMM];
56600565589SLin Jinhan 		cur_chn->int_st =  READ_ONCE(rkce_reg->SYMM_INT_ST);
56700565589SLin Jinhan 		cur_chn->td_id  = rkce_reg->SYMM_TD_ID;
56800565589SLin Jinhan 
56900565589SLin Jinhan 		/* clear symm int */
57000565589SLin Jinhan 		WRITE_ONCE(rkce_reg->SYMM_INT_ST, cur_chn->int_st);
57100565589SLin Jinhan 
57200565589SLin Jinhan 		cur_chn->result = (cur_chn->int_st == RKCE_SYMM_INT_ST_TD_DONE_MASK) ?
57300565589SLin Jinhan 				  RKCE_SUCCESS : cur_chn->int_st;
57400565589SLin Jinhan 	}
57500565589SLin Jinhan 
57600565589SLin Jinhan 	if (rkce_reg->HASH_INT_ST) {
57700565589SLin Jinhan 		cur_chn = &hardware->chn[RKCE_TD_TYPE_HASH];
57800565589SLin Jinhan 		cur_chn->int_st = READ_ONCE(rkce_reg->HASH_INT_ST);
57900565589SLin Jinhan 		cur_chn->td_id  = rkce_reg->HASH_TD_ID;
58000565589SLin Jinhan 
58100565589SLin Jinhan 		/* clear hash int */
58200565589SLin Jinhan 		WRITE_ONCE(rkce_reg->HASH_INT_ST, cur_chn->int_st);
58300565589SLin Jinhan 
58400565589SLin Jinhan 		cur_chn->result = (cur_chn->int_st == RKCE_HASH_INT_ST_TD_DONE_MASK) ?
58500565589SLin Jinhan 				  RKCE_SUCCESS : cur_chn->int_st;
58600565589SLin Jinhan 	}
58700565589SLin Jinhan }
58800565589SLin Jinhan 
rkce_irq_thread(void * rkce_hw)58900565589SLin Jinhan void rkce_irq_thread(void *rkce_hw)
59000565589SLin Jinhan {
59100565589SLin Jinhan 	uint32_t i;
59200565589SLin Jinhan 	bool is_fault = false;
59300565589SLin Jinhan 	struct rkce_hardware *hardware = rkce_hw;
59400565589SLin Jinhan 
59500565589SLin Jinhan 	CHECK_RKCE_INITED(rkce_hw);
59600565589SLin Jinhan 
59700565589SLin Jinhan 	for (i = 0; i < ARRAY_SIZE(hardware->chn); i++) {
59800565589SLin Jinhan 		struct rkce_chn_info *cur_chn = &hardware->chn[i];
59900565589SLin Jinhan 
60000565589SLin Jinhan 		if (cur_chn->result) {
60100565589SLin Jinhan 			is_fault = true;
60200565589SLin Jinhan 			rk_err("td_type = %u, wrong SISR = %08x, td_id = %08x, td_virt = %p\n",
60300565589SLin Jinhan 			       i, cur_chn->int_st, cur_chn->td_id, cur_chn->td_virt);
60400565589SLin Jinhan 		}
60500565589SLin Jinhan 
60600565589SLin Jinhan 		if (cur_chn->int_st == 0 || !(cur_chn->cb_func))
60700565589SLin Jinhan 			continue;
60800565589SLin Jinhan 
60900565589SLin Jinhan 		rk_debug("##################### finalize td %p, result = %d\n",
61000565589SLin Jinhan 			 cur_chn->td_virt, cur_chn->result);
61100565589SLin Jinhan 
61200565589SLin Jinhan 		if (cur_chn->cb_func && cur_chn->td_virt)
61300565589SLin Jinhan 			cur_chn->cb_func(cur_chn->result, cur_chn->td_id, cur_chn->td_virt);
61400565589SLin Jinhan 
61500565589SLin Jinhan 		cur_chn->result  = 0;
61600565589SLin Jinhan 		cur_chn->int_st  = 0;
61700565589SLin Jinhan 		cur_chn->td_id   = 0;
61800565589SLin Jinhan 		cur_chn->td_virt = NULL;
61900565589SLin Jinhan 	}
62000565589SLin Jinhan 
62100565589SLin Jinhan 	if (is_fault)
62200565589SLin Jinhan 		rkce_dump_reginfo(hardware);
62300565589SLin Jinhan }
624*8f7f431fSTroy Lin 
rkce_get_keytable_addr(void * rkce_hw)625*8f7f431fSTroy Lin uint32_t rkce_get_keytable_addr(void *rkce_hw)
626*8f7f431fSTroy Lin {
627*8f7f431fSTroy Lin 	struct RKCE_REG *rkce_reg;
628*8f7f431fSTroy Lin 
629*8f7f431fSTroy Lin 	CHECK_RKCE_INITED(rkce_hw);
630*8f7f431fSTroy Lin 
631*8f7f431fSTroy Lin 	rkce_reg = GET_RKCE_REG(rkce_hw);
632*8f7f431fSTroy Lin 
633*8f7f431fSTroy Lin 	return rkce_reg->KL_TO_CE_PADDR + CRYPTO_CH0_KEY_0;
634*8f7f431fSTroy Lin }
635