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