From patchwork Tue Jul 20 06:38:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaWei Wang X-Patchwork-Id: 1507409 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GTTbL3svwz9sWc for ; Tue, 20 Jul 2021 16:39:42 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C4B6682C57; Tue, 20 Jul 2021 08:39:25 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=aspeedtech.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id F255082C47; Tue, 20 Jul 2021 08:39:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.2 Received: from twspam01.aspeedtech.com (twspam01.aspeedtech.com [211.20.114.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 80D3B82C26 for ; Tue, 20 Jul 2021 08:39:05 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=aspeedtech.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=chiawei_wang@aspeedtech.com Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 16K6M66U039585; Tue, 20 Jul 2021 14:22:06 +0800 (GMT-8) (envelope-from chiawei_wang@aspeedtech.com) Received: from ChiaWeiWang-PC.aspeed.com (192.168.2.66) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Tue, 20 Jul 2021 14:38:31 +0800 From: Chia-Wei Wang To: , , , CC: , Subject: [PATCH v3 03/14] crypto: aspeed: Add AST2600 HACE support Date: Tue, 20 Jul 2021 14:38:28 +0800 Message-ID: <20210720063839.1518-4-chiawei_wang@aspeedtech.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210720063839.1518-1-chiawei_wang@aspeedtech.com> References: <20210720063839.1518-1-chiawei_wang@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.2.66] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 16K6M66U039585 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean From: Joel Stanley Hash and Crypto Engine (HACE) is designed to accelerate the throughput of hash data digest, and symmetric-key encryption. Signed-off-by: Joel Stanley Signed-off-by: Chia-Wei Wang --- drivers/crypto/Kconfig | 2 + drivers/crypto/Makefile | 1 + drivers/crypto/aspeed/Kconfig | 12 ++ drivers/crypto/aspeed/Makefile | 1 + drivers/crypto/aspeed/aspeed_hace.c | 308 ++++++++++++++++++++++++++++ 5 files changed, 324 insertions(+) create mode 100644 drivers/crypto/aspeed/Kconfig create mode 100644 drivers/crypto/aspeed/Makefile create mode 100644 drivers/crypto/aspeed/aspeed_hace.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 1ea116be75..422d01403e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -2,4 +2,6 @@ menu "Hardware crypto devices" source drivers/crypto/fsl/Kconfig +source drivers/crypto/aspeed/Kconfig + endmenu diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index efbd1d3fca..0442067e5e 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o obj-y += rsa_mod_exp/ obj-y += fsl/ +obj-y += aspeed/ diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig new file mode 100644 index 0000000000..299efc223f --- /dev/null +++ b/drivers/crypto/aspeed/Kconfig @@ -0,0 +1,12 @@ +config ASPEED_HACE + bool "ASPEED Hash and Crypto Engine" + depends on ASPEED_AST2600 + imply SHA_HW_ACCEL + imply SHA_PROG_HW_ACCEL + imply CMD_HASH + help + Select this option to enable a driver for using the SHA engine in + the ASPEED BMC SoCs. + + Enabling this allows the use of SHA operations in hardware without requiring the + SHA software implementations. It also improves performance and saves code size. diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile new file mode 100644 index 0000000000..84e6bfe82a --- /dev/null +++ b/drivers/crypto/aspeed/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o diff --git a/drivers/crypto/aspeed/aspeed_hace.c b/drivers/crypto/aspeed/aspeed_hace.c new file mode 100644 index 0000000000..896e1f1a3b --- /dev/null +++ b/drivers/crypto/aspeed/aspeed_hace.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2021 IBM Corp. + * Copyright 2021 ASPEED Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* register offsets*/ +#define HACE_STS 0x1C +#define HACE_HASH_DATA_OVF BIT(23) +#define HACE_HASH_INT BIT(9) +#define HACE_HASH_BUSY BIT(0) +#define HACE_HASH_DATA 0x20 +#define HACE_HASH_DIGEST 0x24 +#define HACE_HASH_HMAC_KEY 0x28 +#define HACE_HASH_DATA_LEN 0x2C +#define HACE_SG_LAST BIT(31) +#define HACE_HASH_CMD 0x30 +#define HACE_SG_EN BIT(18) +#define HACE_ALGO_SHA384 (BIT(10) | BIT(6) | BIT(5)) +#define HACE_ALGO_SHA512 (BIT(6) | BIT(5)) +#define HACE_ALGO_SHA256 (BIT(6) | BIT(4)) +#define HACE_ALGO_SHA224 BIT(6) +#define HACE_ALGO_SHA1 BIT(5) +#define HACE_SHA_BE_EN BIT(3) +#define HACE_MD5_LE_EN BIT(2) + +#define HACE_MAX_SG 32 + +struct aspeed_sg { + u32 len; + u32 addr; +}; + +struct aspeed_hash_ctx { + u32 method; + u32 digest_size; + u32 len; + u32 count; + struct aspeed_sg list[HACE_MAX_SG]; /* Must be 8 byte aligned */ +}; + +struct aspeed_hace { + phys_addr_t base; + struct clk clk; + struct reset_ctl rst; +}; + +static int aspeed_hace_wait_completion(u32 reg, u32 flag, int timeout_us) +{ + u32 val; + + return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us); +} + +static int digest_object(const void *data, unsigned int length, void *digest, + u32 method) +{ + int rc; + u32 sts; + struct udevice *dev; + struct aspeed_hace *hace; + + if (!((u32)data & BIT(31))) { + debug("HACE src out of bounds: can only copy from SDRAM\n"); + return -EINVAL; + } + + if (!((u32)digest & BIT(31))) { + debug("HACE dst out of bounds: can only copy to SDRAM\n"); + return -EINVAL; + } + + if ((u32)digest & 0x7) { + debug("HACE dst alignment incorrect: %p\n", digest); + return -EINVAL; + } + + /* get HACE device as crypto code does not pass us device/driver state */ + rc = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(aspeed_hace), + &dev); + if (rc) { + debug("Can't get HACE device, rc=%d\n", rc); + return -ENODEV; + } + + hace = dev_get_priv(dev); + + sts = readl(hace->base + HACE_STS); + if (sts & HACE_HASH_BUSY) { + debug("HACE error: engine busy\n"); + return -EBUSY; + } + + /* Clear pending completion status */ + writel(HACE_HASH_INT, hace->base + HACE_STS); + writel((u32)data, hace->base + HACE_HASH_DATA); + writel((u32)digest, hace->base + HACE_HASH_DIGEST); + writel(length, hace->base + HACE_HASH_DATA_LEN); + writel(HACE_SHA_BE_EN | method, hace->base + HACE_HASH_CMD); + + /* SHA512 hashing appears to have a througput of about 12MB/s */ + rc = aspeed_hace_wait_completion(hace->base + HACE_STS, + HACE_HASH_INT, + 1000 + (length >> 3)); + + /* + * Reset HACE to work around unexpected hash input data + * buffer overflow caused by certain combinations of DMA + * base and length, even though they are valid. + */ + sts = readl(hace->base + HACE_STS); + if (sts & HACE_HASH_DATA_OVF) { + debug("HACE error: status=0x%08x, resetting\n", sts); + reset_assert(&hace->rst); + mdelay(5); + reset_deassert(&hace->rst); + } + + return rc; +} + +void hw_sha1(const unsigned char *pbuf, unsigned int buf_len, + unsigned char *pout, unsigned int chunk_size) +{ + int rc; + + rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA1); + if (rc) + debug("HACE failure: %d\n", rc); +} + +void hw_sha256(const unsigned char *pbuf, unsigned int buf_len, + unsigned char *pout, unsigned int chunk_size) +{ + int rc; + + rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA256); + if (rc) + debug("HACE failure: %d\n", rc); +} + +void hw_sha384(const unsigned char *pbuf, unsigned int buf_len, + unsigned char *pout, unsigned int chunk_size) +{ + int rc; + + rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA384); + if (rc) + debug("HACE failure: %d\n", rc); +} + +void hw_sha512(const unsigned char *pbuf, unsigned int buf_len, + unsigned char *pout, unsigned int chunk_size) +{ + int rc; + + rc = digest_object(pbuf, buf_len, pout, HACE_ALGO_SHA512); + if (rc) + debug("HACE failure: %d\n", rc); +} + +int hw_sha_init(struct hash_algo *algo, void **ctxp) +{ + struct aspeed_hash_ctx *ctx; + u32 method; + + if (!strcmp(algo->name, "sha1")) + method = HACE_ALGO_SHA1; + else if (!strcmp(algo->name, "sha256")) + method = HACE_ALGO_SHA256; + else if (!strcmp(algo->name, "sha384")) + method = HACE_ALGO_SHA384; + else if (!strcmp(algo->name, "sha512")) + method = HACE_ALGO_SHA512; + else + return -ENOTSUPP; + + ctx = memalign(8, sizeof(*ctx)); + if (!ctx) { + debug("HACE error: Cannot allocate memory for context\n"); + return -ENOMEM; + } + + memset(ctx, '\0', sizeof(*ctx)); + + if (((uintptr_t)ctx->list & 0x3) != 0) { + debug("HACE error: Invalid alignment for input data\n"); + return -EINVAL; + } + + ctx->method = method | HACE_SG_EN; + ctx->digest_size = algo->digest_size; + + *ctxp = ctx; + + return 0; +} + +int hw_sha_update(struct hash_algo *algo, void *hash_ctx, const void *buf, + unsigned int size, int is_last) +{ + struct aspeed_hash_ctx *ctx = hash_ctx; + struct aspeed_sg *sg = &ctx->list[ctx->count]; + + if (ctx->count >= ARRAY_SIZE(ctx->list)) { + debug("HACE error: Reached maximum number of hash segments\n"); + free(ctx); + return -EINVAL; + } + + sg->addr = (u32)buf; + sg->len = size; + + if (is_last) + sg->len |= HACE_SG_LAST; + + ctx->count++; + ctx->len += size; + + return 0; +} + +int hw_sha_finish(struct hash_algo *algo, void *hash_ctx, void *dest_buf, int size) +{ + struct aspeed_hash_ctx *ctx = hash_ctx; + int rc; + + if (size < ctx->digest_size) { + debug("HACE error: insufficient size on destination buffer\n"); + free(ctx); + return -EINVAL; + } + + rc = digest_object(ctx->list, ctx->len, dest_buf, ctx->method); + if (rc) + debug("HACE Scatter-Gather failure\n"); + + free(ctx); + + return rc; +} + +static int aspeed_hace_probe(struct udevice *dev) +{ + struct aspeed_hace *hace = dev_get_priv(dev); + int ret; + + ret = clk_get_by_index(dev, 0, &hace->clk); + if (ret < 0) { + debug("Can't get clock for %s: %d\n", dev->name, ret); + return ret; + } + + ret = reset_get_by_index(dev, 0, &hace->rst); + if (ret < 0) { + debug("Can't get reset for %s: %d\n", dev->name, ret); + return ret; + } + + ret = clk_enable(&hace->clk); + if (ret) { + debug("Failed to enable fsi clock (%d)\n", ret); + return ret; + } + + hace->base = devfdt_get_addr(dev); + + return ret; +} + +static int aspeed_hace_remove(struct udevice *dev) +{ + struct aspeed_hace *hace = dev_get_priv(dev); + + clk_disable(&hace->clk); + + return 0; +} + +static const struct udevice_id aspeed_hace_ids[] = { + { .compatible = "aspeed,ast2600-hace" }, + { } +}; + +U_BOOT_DRIVER(aspeed_hace) = { + .name = "aspeed_hace", + .id = UCLASS_MISC, + .of_match = aspeed_hace_ids, + .probe = aspeed_hace_probe, + .remove = aspeed_hace_remove, + .priv_auto = sizeof(struct aspeed_hace), + .flags = DM_FLAG_PRE_RELOC, +};