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