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