1a3d00835SJoseph Chen // SPDX-License-Identifier: GPL-2.0 2a3d00835SJoseph Chen /* 3a3d00835SJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4a3d00835SJoseph Chen */ 5a3d00835SJoseph Chen 6a3d00835SJoseph Chen #include <common.h> 7a3d00835SJoseph Chen #include <clk.h> 8a3d00835SJoseph Chen #include <crypto.h> 9a3d00835SJoseph Chen #include <dm.h> 10a3d00835SJoseph Chen #include <rockchip/crypto_v1.h> 11a3d00835SJoseph Chen #include <asm/io.h> 12a3d00835SJoseph Chen #include <asm/arch/hardware.h> 13a3d00835SJoseph Chen #include <asm/arch/clock.h> 14a3d00835SJoseph Chen 15a3d00835SJoseph Chen #define CRYPTO_V1_DEFAULT_RATE 100000000 16a3d00835SJoseph Chen 17a3d00835SJoseph Chen struct rockchip_crypto_priv { 18a3d00835SJoseph Chen struct rk_crypto_reg *reg; 19a3d00835SJoseph Chen struct clk clk; 20a3d00835SJoseph Chen u32 frequency; 21a3d00835SJoseph Chen char *clocks; 22a3d00835SJoseph Chen u32 nclocks; 23a3d00835SJoseph Chen u32 length; 24a3d00835SJoseph Chen }; 25a3d00835SJoseph Chen 26a3d00835SJoseph Chen static u32 rockchip_crypto_capability(struct udevice *dev) 27a3d00835SJoseph Chen { 28a3d00835SJoseph Chen return CRYPTO_MD5 | 29a3d00835SJoseph Chen CRYPTO_SHA1 | 30a3d00835SJoseph Chen CRYPTO_SHA256 | 31a3d00835SJoseph Chen CRYPTO_RSA512 | 32a3d00835SJoseph Chen CRYPTO_RSA1024 | 33a3d00835SJoseph Chen CRYPTO_RSA2048; 34a3d00835SJoseph Chen } 35a3d00835SJoseph Chen 36a3d00835SJoseph Chen static int rockchip_crypto_sha_init(struct udevice *dev, sha_context *ctx) 37a3d00835SJoseph Chen { 38a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 39a3d00835SJoseph Chen struct rk_crypto_reg *reg = priv->reg; 40a3d00835SJoseph Chen u32 val; 41a3d00835SJoseph Chen 42*f9ebf7a1SJoseph Chen if (!ctx) 43a3d00835SJoseph Chen return -EINVAL; 44a3d00835SJoseph Chen 45*f9ebf7a1SJoseph Chen if (!ctx->length) { 46*f9ebf7a1SJoseph Chen printf("%s: Err: crypto v1 request total data " 47*f9ebf7a1SJoseph Chen "length when sha init\n", __func__); 48*f9ebf7a1SJoseph Chen return -EINVAL; 49*f9ebf7a1SJoseph Chen } 50*f9ebf7a1SJoseph Chen 51a3d00835SJoseph Chen priv->length = 0; 52a3d00835SJoseph Chen writel(ctx->length, ®->crypto_hash_msg_len); 53a3d00835SJoseph Chen if (ctx->algo == CRYPTO_SHA256) { 54a3d00835SJoseph Chen /* Set SHA256 mode and out byte swap */ 55a3d00835SJoseph Chen writel(HASH_SWAP_DO | ENGINE_SELECTION_SHA256, 56a3d00835SJoseph Chen ®->crypto_hash_ctrl); 57a3d00835SJoseph Chen 58a3d00835SJoseph Chen val = readl(®->crypto_conf); 59a3d00835SJoseph Chen val &= ~BYTESWAP_HRFIFO; 60a3d00835SJoseph Chen writel(val, ®->crypto_conf); 61a3d00835SJoseph Chen } else if (ctx->algo == CRYPTO_SHA1) { 62a3d00835SJoseph Chen /* Set SHA160 input byte swap */ 63a3d00835SJoseph Chen val = readl(®->crypto_conf); 64a3d00835SJoseph Chen val |= BYTESWAP_HRFIFO; 65a3d00835SJoseph Chen writel(val, ®->crypto_conf); 66a3d00835SJoseph Chen 67a3d00835SJoseph Chen /* Set SHA160 mode and out byte swap */ 68a3d00835SJoseph Chen writel(HASH_SWAP_DO, ®->crypto_hash_ctrl); 69a3d00835SJoseph Chen } else if (ctx->algo == CRYPTO_MD5) { 70a3d00835SJoseph Chen /* Set MD5 input byte swap */ 71a3d00835SJoseph Chen val = readl(®->crypto_conf); 72a3d00835SJoseph Chen val |= BYTESWAP_HRFIFO; 73a3d00835SJoseph Chen writel(val, ®->crypto_conf); 74a3d00835SJoseph Chen 75a3d00835SJoseph Chen /* Set MD5 mode and out byte swap */ 76a3d00835SJoseph Chen writel(HASH_SWAP_DO | ENGINE_SELECTION_MD5, 77a3d00835SJoseph Chen ®->crypto_hash_ctrl); 78a3d00835SJoseph Chen } else { 79a3d00835SJoseph Chen return -EINVAL; 80a3d00835SJoseph Chen } 81a3d00835SJoseph Chen 82a3d00835SJoseph Chen rk_setreg(®->crypto_ctrl, HASH_FLUSH); 83a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & HASH_FLUSH); 84a3d00835SJoseph Chen 85a3d00835SJoseph Chen /* SHA256 needs input byte swap */ 86a3d00835SJoseph Chen if (ctx->algo == CRYPTO_SHA256) { 87a3d00835SJoseph Chen val = readl(®->crypto_conf); 88a3d00835SJoseph Chen val |= BYTESWAP_HRFIFO; 89a3d00835SJoseph Chen writel(val, ®->crypto_conf); 90a3d00835SJoseph Chen } 91a3d00835SJoseph Chen 92a3d00835SJoseph Chen return 0; 93a3d00835SJoseph Chen } 94a3d00835SJoseph Chen 95a3d00835SJoseph Chen static int rockchip_crypto_sha_update(struct udevice *dev, 96a3d00835SJoseph Chen u32 *input, u32 len) 97a3d00835SJoseph Chen { 98a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 99a3d00835SJoseph Chen struct rk_crypto_reg *reg = priv->reg; 100a3d00835SJoseph Chen 101a3d00835SJoseph Chen if (!len) 102a3d00835SJoseph Chen return -EINVAL; 103a3d00835SJoseph Chen 104a3d00835SJoseph Chen priv->length += len; 105a3d00835SJoseph Chen 106a3d00835SJoseph Chen /* Must flush dcache before crypto DMA fetch data region */ 107a3d00835SJoseph Chen flush_cache((unsigned long)input, len); 108a3d00835SJoseph Chen 109a3d00835SJoseph Chen /* Wait last complete */ 110a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & HASH_START); 111a3d00835SJoseph Chen 112a3d00835SJoseph Chen /* Hash Done Interrupt */ 113a3d00835SJoseph Chen writel(HASH_DONE_INT, ®->crypto_intsts); 114a3d00835SJoseph Chen 115a3d00835SJoseph Chen /* Set data base and length */ 116a3d00835SJoseph Chen writel((u32)(ulong)input, ®->crypto_hrdmas); 117a3d00835SJoseph Chen writel((len + 3) >> 2, ®->crypto_hrdmal); 118a3d00835SJoseph Chen 119a3d00835SJoseph Chen /* Write 1 to start. When finishes, the core will clear it */ 120a3d00835SJoseph Chen rk_setreg(®->crypto_ctrl, HASH_START); 121a3d00835SJoseph Chen 122a3d00835SJoseph Chen return 0; 123a3d00835SJoseph Chen } 124a3d00835SJoseph Chen 125a3d00835SJoseph Chen static int rockchip_crypto_sha_final(struct udevice *dev, 126a3d00835SJoseph Chen sha_context *ctx, u8 *output) 127a3d00835SJoseph Chen { 128a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 129a3d00835SJoseph Chen struct rk_crypto_reg *reg = priv->reg; 130a3d00835SJoseph Chen u32 *buf = (u32 *)output; 131a3d00835SJoseph Chen u32 nbits; 132a3d00835SJoseph Chen int i; 133a3d00835SJoseph Chen 134a3d00835SJoseph Chen if (priv->length != ctx->length) { 135a3d00835SJoseph Chen printf("%s: Err: update total length(0x%x) is not equal " 136a3d00835SJoseph Chen "to init total length(0x%x)!\n", 137a3d00835SJoseph Chen __func__, priv->length, ctx->length); 138a3d00835SJoseph Chen return -EIO; 139a3d00835SJoseph Chen } 140a3d00835SJoseph Chen 141a3d00835SJoseph Chen /* Wait last complete */ 142a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & HASH_START); 143a3d00835SJoseph Chen 144a3d00835SJoseph Chen /* It is high when finish, and it will not be low until it restart */ 145a3d00835SJoseph Chen do {} while (!readl(®->crypto_hash_sts)); 146a3d00835SJoseph Chen 147a3d00835SJoseph Chen /* Read hash data, per-data 32-bit */ 148a3d00835SJoseph Chen nbits = crypto_algo_nbits(ctx->algo); 149*f9ebf7a1SJoseph Chen for (i = 0; i < BITS2WORD(nbits); i++) 150a3d00835SJoseph Chen buf[i] = readl(®->crypto_hash_dout[i]); 151a3d00835SJoseph Chen 152a3d00835SJoseph Chen return 0; 153a3d00835SJoseph Chen } 154a3d00835SJoseph Chen 155a3d00835SJoseph Chen static int rockchip_crypto_rsa_verify(struct udevice *dev, rsa_key *ctx, 156a3d00835SJoseph Chen u8 *sign, u8 *output) 157a3d00835SJoseph Chen { 158a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 159a3d00835SJoseph Chen struct rk_crypto_reg *reg = priv->reg; 160a3d00835SJoseph Chen u32 nbits, *buf = (u32 *)output; 161a3d00835SJoseph Chen int i, value; 162a3d00835SJoseph Chen 163a3d00835SJoseph Chen if (!ctx) 164a3d00835SJoseph Chen return -EINVAL; 165a3d00835SJoseph Chen 166a3d00835SJoseph Chen if (ctx->algo == CRYPTO_RSA512) 167a3d00835SJoseph Chen value = PKA_BLOCK_SIZE_512; 168a3d00835SJoseph Chen else if (ctx->algo == CRYPTO_RSA1024) 169a3d00835SJoseph Chen value = PKA_BLOCK_SIZE_1024; 170a3d00835SJoseph Chen else if (ctx->algo == CRYPTO_RSA2048) 171a3d00835SJoseph Chen value = PKA_BLOCK_SIZE_2048; 172a3d00835SJoseph Chen else 173a3d00835SJoseph Chen return -EINVAL; 174a3d00835SJoseph Chen 175a3d00835SJoseph Chen /* Specify the nbits of N in PKA calculation */ 176a3d00835SJoseph Chen writel(value, ®->crypto_pka_ctrl); 177a3d00835SJoseph Chen 178a3d00835SJoseph Chen /* Flush SHA and RSA */ 179a3d00835SJoseph Chen rk_setreg(®->crypto_ctrl, PKA_HASH_CTRL); 180a3d00835SJoseph Chen writel(0xffffffff, ®->crypto_intsts); 181a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & PKA_CTRL); 182a3d00835SJoseph Chen 183a3d00835SJoseph Chen /* Clean PKA done interrupt */ 184a3d00835SJoseph Chen writel(PKA_DONE_INT, ®->crypto_intsts); 185a3d00835SJoseph Chen 186a3d00835SJoseph Chen /* Set m/n/e/c */ 187a3d00835SJoseph Chen nbits = crypto_algo_nbits(ctx->algo); 188a3d00835SJoseph Chen memcpy((void *)®->crypto_pka_m, (void *)sign, BITS2BYTE(nbits)); 189a3d00835SJoseph Chen memcpy((void *)®->crypto_pka_n, (void *)ctx->n, BITS2BYTE(nbits)); 190a3d00835SJoseph Chen memcpy((void *)®->crypto_pka_e, (void *)ctx->e, BITS2BYTE(nbits)); 191a3d00835SJoseph Chen memcpy((void *)®->crypto_pka_c, (void *)ctx->c, BITS2BYTE(nbits)); 192a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & PKA_START); 193a3d00835SJoseph Chen 194a3d00835SJoseph Chen /* Start PKA */ 195a3d00835SJoseph Chen rk_setreg(®->crypto_ctrl, PKA_START); 196a3d00835SJoseph Chen 197a3d00835SJoseph Chen /* Wait PKA done */ 198a3d00835SJoseph Chen do {} while (readl(®->crypto_ctrl) & PKA_START); 199a3d00835SJoseph Chen 200a3d00835SJoseph Chen /* Read hash data, per-data 32-bit */ 201a3d00835SJoseph Chen for (i = 0; i < BITS2WORD(nbits); i++) 202a3d00835SJoseph Chen buf[i] = readl(®->crypto_pka_m[i]); 203a3d00835SJoseph Chen 204a3d00835SJoseph Chen return 0; 205a3d00835SJoseph Chen } 206a3d00835SJoseph Chen 207a3d00835SJoseph Chen static const struct dm_crypto_ops rockchip_crypto_ops = { 208a3d00835SJoseph Chen .capability = rockchip_crypto_capability, 209a3d00835SJoseph Chen .sha_init = rockchip_crypto_sha_init, 210a3d00835SJoseph Chen .sha_update = rockchip_crypto_sha_update, 211a3d00835SJoseph Chen .sha_final = rockchip_crypto_sha_final, 212a3d00835SJoseph Chen .rsa_verify = rockchip_crypto_rsa_verify, 213a3d00835SJoseph Chen }; 214a3d00835SJoseph Chen 215a3d00835SJoseph Chen /* 216a3d00835SJoseph Chen * Only use "clocks" to parse crypto clock id and use rockchip_get_clk(). 217a3d00835SJoseph Chen * Because we always add crypto node in U-Boot dts, when kernel dtb enabled : 218a3d00835SJoseph Chen * 219a3d00835SJoseph Chen * 1. There is cru phandle mismatch between U-Boot and kernel dtb; 220a3d00835SJoseph Chen * 2. CONFIG_OF_SPL_REMOVE_PROPS removes clock property; 221a3d00835SJoseph Chen */ 222a3d00835SJoseph Chen static int rockchip_crypto_ofdata_to_platdata(struct udevice *dev) 223a3d00835SJoseph Chen { 224a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 225a3d00835SJoseph Chen int len; 226a3d00835SJoseph Chen 227a3d00835SJoseph Chen if (!dev_read_prop(dev, "clocks", &len)) { 228a3d00835SJoseph Chen printf("Can't find \"clocks\" property\n"); 229a3d00835SJoseph Chen return -EINVAL; 230a3d00835SJoseph Chen } 231a3d00835SJoseph Chen 232a3d00835SJoseph Chen priv->clocks = malloc(len); 233a3d00835SJoseph Chen if (!priv->clocks) 234a3d00835SJoseph Chen return -ENOMEM; 235a3d00835SJoseph Chen 236a3d00835SJoseph Chen priv->nclocks = len / sizeof(u32); 237a3d00835SJoseph Chen if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks, 238a3d00835SJoseph Chen priv->nclocks)) { 239a3d00835SJoseph Chen printf("Can't read \"clocks\" property\n"); 240a3d00835SJoseph Chen return -EINVAL; 241a3d00835SJoseph Chen } 242a3d00835SJoseph Chen 243a3d00835SJoseph Chen priv->reg = dev_read_addr_ptr(dev); 244a3d00835SJoseph Chen priv->frequency = dev_read_u32_default(dev, "clock-frequency", 245a3d00835SJoseph Chen CRYPTO_V1_DEFAULT_RATE); 246a3d00835SJoseph Chen 247a3d00835SJoseph Chen return 0; 248a3d00835SJoseph Chen } 249a3d00835SJoseph Chen 250a3d00835SJoseph Chen static int rockchip_crypto_probe(struct udevice *dev) 251a3d00835SJoseph Chen { 252a3d00835SJoseph Chen struct rockchip_crypto_priv *priv = dev_get_priv(dev); 253a3d00835SJoseph Chen u32 *clocks; 254a3d00835SJoseph Chen int i, ret; 255a3d00835SJoseph Chen 256a3d00835SJoseph Chen ret = rockchip_get_clk(&priv->clk.dev); 257a3d00835SJoseph Chen if (ret) { 258a3d00835SJoseph Chen printf("Failed to get clk device, ret=%d\n", ret); 259a3d00835SJoseph Chen return ret; 260a3d00835SJoseph Chen } 261a3d00835SJoseph Chen 262a3d00835SJoseph Chen clocks = (u32 *)priv->clocks; 263a3d00835SJoseph Chen for (i = 1; i < priv->nclocks; i += 2) { 264a3d00835SJoseph Chen priv->clk.id = clocks[i]; 265a3d00835SJoseph Chen ret = clk_set_rate(&priv->clk, priv->frequency); 266a3d00835SJoseph Chen if (ret < 0) { 267a3d00835SJoseph Chen printf("%s: Failed to set clk(%ld): ret=%d\n", 268a3d00835SJoseph Chen __func__, priv->clk.id, ret); 269a3d00835SJoseph Chen return ret; 270a3d00835SJoseph Chen } 271a3d00835SJoseph Chen } 272a3d00835SJoseph Chen 273a3d00835SJoseph Chen return 0; 274a3d00835SJoseph Chen } 275a3d00835SJoseph Chen 276a3d00835SJoseph Chen static const struct udevice_id rockchip_crypto_ids[] = { 277a3d00835SJoseph Chen { .compatible = "rockchip,rk3399-crypto" }, 278a3d00835SJoseph Chen { .compatible = "rockchip,rk3368-crypto" }, 279a3d00835SJoseph Chen { .compatible = "rockchip,rk3328-crypto" }, 280a3d00835SJoseph Chen { .compatible = "rockchip,rk3288-crypto" }, 281a3d00835SJoseph Chen { .compatible = "rockchip,rk322x-crypto" }, 282a3d00835SJoseph Chen { .compatible = "rockchip,rk312x-crypto" }, 283a3d00835SJoseph Chen { } 284a3d00835SJoseph Chen }; 285a3d00835SJoseph Chen 286a3d00835SJoseph Chen U_BOOT_DRIVER(rockchip_crypto_v1) = { 287a3d00835SJoseph Chen .name = "rockchip_crypto_v1", 288a3d00835SJoseph Chen .id = UCLASS_CRYPTO, 289a3d00835SJoseph Chen .of_match = rockchip_crypto_ids, 290a3d00835SJoseph Chen .ops = &rockchip_crypto_ops, 291a3d00835SJoseph Chen .probe = rockchip_crypto_probe, 292a3d00835SJoseph Chen .ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata, 293a3d00835SJoseph Chen .priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv), 294a3d00835SJoseph Chen }; 295