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