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