1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (C) Copyright ASPEED Technology Inc. 4 * Copyright 2021 IBM Corp. 5 */ 6 #include <common.h> 7 #include <clk.h> 8 9 #include <log.h> 10 #include <asm/io.h> 11 #include <malloc.h> 12 #include <hash.h> 13 14 #include <dm/device.h> 15 #include <dm/fdtaddr.h> 16 17 #include <linux/bitops.h> 18 #include <linux/delay.h> 19 #include <linux/kernel.h> 20 #include <linux/iopoll.h> 21 22 #define ASPEED_HACE_STS 0x1C 23 #define HACE_RSA_ISR BIT(13) 24 #define HACE_CRYPTO_ISR BIT(12) 25 #define HACE_HASH_ISR BIT(9) 26 #define HACE_RSA_BUSY BIT(2) 27 #define HACE_CRYPTO_BUSY BIT(1) 28 #define HACE_HASH_BUSY BIT(0) 29 #define ASPEED_HACE_HASH_SRC 0x20 30 #define ASPEED_HACE_HASH_DIGEST_BUFF 0x24 31 #define ASPEED_HACE_HASH_KEY_BUFF 0x28 32 #define ASPEED_HACE_HASH_DATA_LEN 0x2C 33 #define HACE_SG_LAST BIT(31) 34 #define ASPEED_HACE_HASH_CMD 0x30 35 #define HACE_SHA_BE_EN BIT(3) 36 #define HACE_MD5_LE_EN BIT(2) 37 #define HACE_ALGO_MD5 0 38 #define HACE_ALGO_SHA1 BIT(5) 39 #define HACE_ALGO_SHA224 BIT(6) 40 #define HACE_ALGO_SHA256 (BIT(4) | BIT(6)) 41 #define HACE_ALGO_SHA512 (BIT(5) | BIT(6)) 42 #define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10)) 43 #define HACE_SG_EN BIT(18) 44 45 #define ASPEED_MAX_SG 32 46 47 struct aspeed_sg { 48 u32 len; 49 u32 addr; 50 }; 51 52 struct aspeed_hash_ctx { 53 u32 method; 54 u32 digest_size; 55 u32 len; 56 u32 count; 57 struct aspeed_sg list[ASPEED_MAX_SG]; /* Must be 8 byte aligned */ 58 }; 59 60 struct aspeed_hace { 61 struct clk clk; 62 }; 63 64 static phys_addr_t base; 65 66 static int aspeed_hace_wait_completion(u32 reg, u32 flag, int timeout_us) 67 { 68 u32 val; 69 70 return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us); 71 } 72 73 static int digest_object(const void *src, unsigned int length, void *digest, 74 u32 method) 75 { 76 if (!((u32)src & BIT(31))) { 77 debug("HACE src out of bounds: can only copy from SDRAM\n"); 78 return -EINVAL; 79 } 80 81 if ((u32)digest & 0x7) { 82 debug("HACE dest alignment incorrect: %p\n", digest); 83 return -EINVAL; 84 } 85 86 if (readl(base + ASPEED_HACE_STS) & HACE_HASH_BUSY) { 87 debug("HACE error: engine busy\n"); 88 return -EBUSY; 89 } 90 91 /* Clear pending completion status */ 92 writel(HACE_HASH_ISR, base + ASPEED_HACE_STS); 93 94 writel((u32)src, base + ASPEED_HACE_HASH_SRC); 95 writel((u32)digest, base + ASPEED_HACE_HASH_DIGEST_BUFF); 96 writel(length, base + ASPEED_HACE_HASH_DATA_LEN); 97 writel(HACE_SHA_BE_EN | method, base + ASPEED_HACE_HASH_CMD); 98 99 /* SHA512 hashing appears to have a througput of about 12MB/s */ 100 return aspeed_hace_wait_completion(base + ASPEED_HACE_STS, 101 HACE_HASH_ISR, 102 1000 + (length >> 3)); 103 } 104 105 void hw_sha1(const unsigned char *pbuf, unsigned int buf_len, 106 unsigned char *pout, unsigned int chunk_size) 107 { 108 int rc; 109 110 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA1); 111 if (rc) 112 debug("HACE failure: %d\n", rc); 113 } 114 115 void hw_sha256(const unsigned char *pbuf, unsigned int buf_len, 116 unsigned char *pout, unsigned int chunk_size) 117 { 118 int rc; 119 120 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA256); 121 if (rc) 122 debug("HACE failure: %d\n", rc); 123 } 124 125 void hw_sha512(const unsigned char *pbuf, unsigned int buf_len, 126 unsigned char *pout, unsigned int chunk_size) 127 { 128 int rc; 129 130 rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA512); 131 if (rc) 132 debug("HACE failure: %d\n", rc); 133 } 134 135 #if IS_ENABLED(CONFIG_SHA_PROG_HW_ACCEL) 136 int hw_sha_init(struct hash_algo *algo, void **ctxp) 137 { 138 struct aspeed_hash_ctx *ctx; 139 u32 method; 140 141 if (!strcmp(algo->name, "sha1")) 142 method = HACE_ALGO_SHA1; 143 else if (!strcmp(algo->name, "sha256")) 144 method = HACE_ALGO_SHA256; 145 else if (!strcmp(algo->name, "sha512")) 146 method = HACE_ALGO_SHA512; 147 else 148 return -ENOTSUPP; 149 150 ctx = memalign(8, sizeof(*ctx)); 151 memset(ctx, '\0', sizeof(*ctx)); 152 153 if (!ctx) { 154 debug("HACE error: Cannot allocate memory for context\n"); 155 return -ENOMEM; 156 } 157 158 if (((uintptr_t)ctx->list & 0x3) != 0) { 159 printf("HACE error: Invalid alignment for input data\n"); 160 return -EINVAL; 161 } 162 163 ctx->method = method | HACE_SG_EN; 164 ctx->digest_size = algo->digest_size; 165 *ctxp = ctx; 166 167 return 0; 168 } 169 170 int hw_sha_update(struct hash_algo *algo, void *hash_ctx, const void *buf, 171 unsigned int size, int is_last) 172 { 173 struct aspeed_hash_ctx *ctx = hash_ctx; 174 struct aspeed_sg *sg = &ctx->list[ctx->count]; 175 176 if (ctx->count >= ARRAY_SIZE(ctx->list)) { 177 debug("HACE error: Reached maximum number of hash segments\n"); 178 free(ctx); 179 return -EINVAL; 180 } 181 182 sg->addr = (u32)buf; 183 sg->len = size; 184 if (is_last) 185 sg->len |= HACE_SG_LAST; 186 187 ctx->count++; 188 ctx->len += size; 189 190 return 0; 191 } 192 193 int hw_sha_finish(struct hash_algo *algo, void *hash_ctx, void *dest_buf, int size) 194 { 195 struct aspeed_hash_ctx *ctx = hash_ctx; 196 int rc; 197 198 if (size < ctx->digest_size) { 199 debug("HACE error: insufficient size on destination buffer\n"); 200 free(ctx); 201 return -EINVAL; 202 } 203 204 rc = digest_object(ctx->list, ctx->len, dest_buf, ctx->method); 205 if (rc) 206 debug("HACE Scatter-Gather failure\n"); 207 208 free(ctx); 209 210 return rc; 211 } 212 #endif 213 214 static int aspeed_hace_probe(struct udevice *dev) 215 { 216 struct aspeed_hace *hace = dev_get_priv(dev); 217 int ret; 218 219 ret = clk_get_by_index(dev, 0, &hace->clk); 220 if (ret < 0) { 221 debug("Can't get clock for %s: %d\n", dev->name, ret); 222 return ret; 223 } 224 225 ret = clk_enable(&hace->clk); 226 if (ret) { 227 debug("Failed to enable fsi clock (%d)\n", ret); 228 return ret; 229 } 230 231 /* As the crypto code does not pass us any driver state */ 232 base = devfdt_get_addr(dev); 233 234 return ret; 235 } 236 237 static int aspeed_hace_remove(struct udevice *dev) 238 { 239 struct aspeed_hace *hace = dev_get_priv(dev); 240 241 clk_disable(&hace->clk); 242 243 return 0; 244 } 245 246 static const struct udevice_id aspeed_hace_ids[] = { 247 { .compatible = "aspeed,ast2600-hace" }, 248 { } 249 }; 250 251 U_BOOT_DRIVER(aspeed_hace) = { 252 .name = "aspeed_hace", 253 .id = UCLASS_MISC, 254 .of_match = aspeed_hace_ids, 255 .probe = aspeed_hace_probe, 256 .remove = aspeed_hace_remove, 257 .priv_auto_alloc_size = sizeof(struct aspeed_hace), 258 .flags = DM_FLAG_PRE_RELOC, 259 }; 260