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 aligned\n"); 109 return -EINVAL; 110 } 111 112 /* Must flush dcache before crypto DMA fetch data region */ 113 aligned_input = round_down((ulong)input, CONFIG_SYS_CACHELINE_SIZE); 114 aligned_len = round_up(len + ((ulong)input - aligned_input), 115 CONFIG_SYS_CACHELINE_SIZE); 116 flush_cache(aligned_input, aligned_len); 117 118 /* Wait last complete */ 119 do {} while (readl(®->crypto_ctrl) & HASH_START); 120 121 /* Hash Done Interrupt */ 122 writel(HASH_DONE_INT, ®->crypto_intsts); 123 124 /* Set data base and length */ 125 writel((u32)(ulong)input, ®->crypto_hrdmas); 126 writel((len + 3) >> 2, ®->crypto_hrdmal); 127 128 /* Write 1 to start. When finishes, the core will clear it */ 129 rk_setreg(®->crypto_ctrl, HASH_START); 130 131 return 0; 132 } 133 134 static int rockchip_crypto_sha_final(struct udevice *dev, 135 sha_context *ctx, u8 *output) 136 { 137 struct rockchip_crypto_priv *priv = dev_get_priv(dev); 138 struct rk_crypto_reg *reg = priv->reg; 139 u32 *buf = (u32 *)output; 140 u32 nbits; 141 int i; 142 143 if (priv->length != ctx->length) { 144 printf("Crypto-v1: data total length(0x%08x) != init length(0x%08x)!\n", 145 priv->length, ctx->length); 146 return -EIO; 147 } 148 149 /* Wait last complete */ 150 do {} while (readl(®->crypto_ctrl) & HASH_START); 151 152 /* It is high when finish, and it will not be low until it restart */ 153 do {} while (!readl(®->crypto_hash_sts)); 154 155 /* Read hash data, per-data 32-bit */ 156 nbits = crypto_algo_nbits(ctx->algo); 157 for (i = 0; i < BITS2WORD(nbits); i++) 158 buf[i] = readl(®->crypto_hash_dout[i]); 159 160 return 0; 161 } 162 163 static int rockchip_crypto_rsa_verify(struct udevice *dev, rsa_key *ctx, 164 u8 *sign, u8 *output) 165 { 166 struct rockchip_crypto_priv *priv = dev_get_priv(dev); 167 struct rk_crypto_reg *reg = priv->reg; 168 u32 nbits, *buf = (u32 *)output; 169 int i, value; 170 171 if (!ctx) 172 return -EINVAL; 173 174 if (ctx->algo == CRYPTO_RSA512) 175 value = PKA_BLOCK_SIZE_512; 176 else if (ctx->algo == CRYPTO_RSA1024) 177 value = PKA_BLOCK_SIZE_1024; 178 else if (ctx->algo == CRYPTO_RSA2048) 179 value = PKA_BLOCK_SIZE_2048; 180 else 181 return -EINVAL; 182 183 /* Specify the nbits of N in PKA calculation */ 184 writel(value, ®->crypto_pka_ctrl); 185 186 /* Flush SHA and RSA */ 187 rk_setreg(®->crypto_ctrl, PKA_HASH_CTRL); 188 writel(0xffffffff, ®->crypto_intsts); 189 do {} while (readl(®->crypto_ctrl) & PKA_CTRL); 190 191 /* Clean PKA done interrupt */ 192 writel(PKA_DONE_INT, ®->crypto_intsts); 193 194 /* Set m/n/e/c */ 195 nbits = crypto_algo_nbits(ctx->algo); 196 memcpy((void *)®->crypto_pka_m, (void *)sign, BITS2BYTE(nbits)); 197 memcpy((void *)®->crypto_pka_n, (void *)ctx->n, BITS2BYTE(nbits)); 198 memcpy((void *)®->crypto_pka_e, (void *)ctx->e, BITS2BYTE(nbits)); 199 memcpy((void *)®->crypto_pka_c, (void *)ctx->c, BITS2BYTE(nbits)); 200 do {} while (readl(®->crypto_ctrl) & PKA_START); 201 202 /* Start PKA */ 203 rk_setreg(®->crypto_ctrl, PKA_START); 204 205 /* Wait PKA done */ 206 do {} while (readl(®->crypto_ctrl) & PKA_START); 207 208 /* Read hash data, per-data 32-bit */ 209 for (i = 0; i < BITS2WORD(nbits); i++) 210 buf[i] = readl(®->crypto_pka_m[i]); 211 212 return 0; 213 } 214 215 static const struct dm_crypto_ops rockchip_crypto_ops = { 216 .capability = rockchip_crypto_capability, 217 .sha_init = rockchip_crypto_sha_init, 218 .sha_update = rockchip_crypto_sha_update, 219 .sha_final = rockchip_crypto_sha_final, 220 .rsa_verify = rockchip_crypto_rsa_verify, 221 }; 222 223 /* 224 * Only use "clocks" to parse crypto clock id and use rockchip_get_clk(). 225 * Because we always add crypto node in U-Boot dts, when kernel dtb enabled : 226 * 227 * 1. There is cru phandle mismatch between U-Boot and kernel dtb; 228 * 2. CONFIG_OF_SPL_REMOVE_PROPS removes clock property; 229 */ 230 static int rockchip_crypto_ofdata_to_platdata(struct udevice *dev) 231 { 232 struct rockchip_crypto_priv *priv = dev_get_priv(dev); 233 int len; 234 235 if (!dev_read_prop(dev, "clocks", &len)) { 236 printf("Crypto-v1: can't find \"clocks\" property\n"); 237 return -EINVAL; 238 } 239 240 priv->clocks = malloc(len); 241 if (!priv->clocks) 242 return -ENOMEM; 243 244 priv->nclocks = len / sizeof(u32); 245 if (dev_read_u32_array(dev, "clocks", (u32 *)priv->clocks, 246 priv->nclocks)) { 247 printf("Crypto-v1: can't read \"clocks\" property\n"); 248 return -EINVAL; 249 } 250 251 priv->reg = dev_read_addr_ptr(dev); 252 priv->frequency = dev_read_u32_default(dev, "clock-frequency", 253 CRYPTO_V1_DEFAULT_RATE); 254 255 return 0; 256 } 257 258 static int rockchip_crypto_probe(struct udevice *dev) 259 { 260 struct rockchip_crypto_priv *priv = dev_get_priv(dev); 261 u32 *clocks; 262 int i, ret; 263 264 ret = rockchip_get_clk(&priv->clk.dev); 265 if (ret) { 266 printf("Crypto-v1: failed to get clk device, ret=%d\n", ret); 267 return ret; 268 } 269 270 clocks = (u32 *)priv->clocks; 271 for (i = 1; i < priv->nclocks; i += 2) { 272 priv->clk.id = clocks[i]; 273 ret = clk_set_rate(&priv->clk, priv->frequency); 274 if (ret < 0) { 275 printf("Crypto-v1: failed to set clk(%ld): ret=%d\n", 276 priv->clk.id, ret); 277 return ret; 278 } 279 } 280 281 return 0; 282 } 283 284 static const struct udevice_id rockchip_crypto_ids[] = { 285 { .compatible = "rockchip,rk3399-crypto" }, 286 { .compatible = "rockchip,rk3368-crypto" }, 287 { .compatible = "rockchip,rk3328-crypto" }, 288 { .compatible = "rockchip,rk3288-crypto" }, 289 { .compatible = "rockchip,rk322x-crypto" }, 290 { .compatible = "rockchip,rk312x-crypto" }, 291 { } 292 }; 293 294 U_BOOT_DRIVER(rockchip_crypto_v1) = { 295 .name = "rockchip_crypto_v1", 296 .id = UCLASS_CRYPTO, 297 .of_match = rockchip_crypto_ids, 298 .ops = &rockchip_crypto_ops, 299 .probe = rockchip_crypto_probe, 300 .ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata, 301 .priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv), 302 }; 303