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