From 891831762011f7379dc865cebe91238d7bf48ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AD=90=E6=87=BF?= Date: Mon, 14 Oct 2024 11:11:23 +0800 Subject: [PATCH] drivers: k230: add security drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 黄子懿 --- arch/riscv/boot/dts/canaan/k230.dtsi | 47 + arch/riscv/configs/k230_defconfig | 1 + drivers/char/hw_random/Kconfig | 11 + drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/k230-rng.c | 95 ++ drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/canaan/Kconfig | 35 + drivers/crypto/canaan/Makefile | 12 + drivers/crypto/canaan/kendryte-aes.c | 1361 +++++++++++++++++++++++++ drivers/crypto/canaan/kendryte-aes.h | 281 +++++ drivers/crypto/canaan/kendryte-hash.c | 613 +++++++++++ drivers/crypto/canaan/kendryte-hash.h | 183 ++++ drivers/crypto/canaan/kendryte-rsa.c | 839 +++++++++++++++ drivers/crypto/canaan/kendryte-rsa.h | 122 +++ drivers/nvmem/Kconfig | 10 + drivers/nvmem/Makefile | 2 + drivers/nvmem/kendryte_k230_otp.c | 163 +++ drivers/thermal/Kconfig | 11 + drivers/thermal/Makefile | 1 + drivers/thermal/canaan_thermal.c | 125 +++ 21 files changed, 3915 insertions(+) create mode 100644 drivers/char/hw_random/k230-rng.c create mode 100644 drivers/crypto/canaan/Kconfig create mode 100644 drivers/crypto/canaan/Makefile create mode 100644 drivers/crypto/canaan/kendryte-aes.c create mode 100644 drivers/crypto/canaan/kendryte-aes.h create mode 100644 drivers/crypto/canaan/kendryte-hash.c create mode 100644 drivers/crypto/canaan/kendryte-hash.h create mode 100644 drivers/crypto/canaan/kendryte-rsa.c create mode 100644 drivers/crypto/canaan/kendryte-rsa.h create mode 100644 drivers/nvmem/kendryte_k230_otp.c create mode 100644 drivers/thermal/canaan_thermal.c diff --git a/arch/riscv/boot/dts/canaan/k230.dtsi b/arch/riscv/boot/dts/canaan/k230.dtsi index 0f5b37f4f1057..1bab9bc5e2b40 100644 --- a/arch/riscv/boot/dts/canaan/k230.dtsi +++ b/arch/riscv/boot/dts/canaan/k230.dtsi @@ -630,6 +630,53 @@ reg = <0x0 0x80400c00 0x0 0x00000400>; interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; }; + + tsensor: tsensor@91107000 { + status = "okay"; + compatible = "canaan,k230-tsensor"; + reg = <0x0 0x91107000 0x0 0x800>; + hardlock = <2>; + }; + + security: security { + status = "okay"; + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + aes: aes@91210200 { + status = "okay"; + compatible = "canaan,k230-crypto"; + reg = <0x0 0x91210200 0x0 0x0100>; + hardlock = <7>; + }; + + hash: hash@91210800 { + status = "okay"; + compatible = "canaan,k230-hash"; + reg = <0x0 0x91210800 0x0 0x0100>; + hardlock = <6>; + }; + + rsa: rsa@91211000 { + status = "okay"; + compatible = "canaan,k230-rsa"; + reg = <0x0 0x91211000 0x0 0x1000>; + }; + + trng: trng@91213000 { + status = "okay"; + compatible = "canaan,k230-rng"; + reg = <0x0 0x91213000 0x0 0x2AC>; + }; + + otp: otp@91213500 { + status = "okay"; + compatible = "canaan,k230-otp"; + reg = <0x0 0x91213500 0x0 0x300>; + }; + }; }; }; #include "k230_clock_provider.dtsi" diff --git a/arch/riscv/configs/k230_defconfig b/arch/riscv/configs/k230_defconfig index 5154cb7feb819..f1f8dd01408b7 100644 --- a/arch/riscv/configs/k230_defconfig +++ b/arch/riscv/configs/k230_defconfig @@ -163,6 +163,7 @@ CONFIG_GPIO_K230=y CONFIG_SENSORS_MR75203=m CONFIG_SENSORS_PWM_FAN=m CONFIG_CPU_THERMAL=y +CONFIG_THERMAL=y CONFIG_THERMAL_EMULATION=y CONFIG_WATCHDOG=y CONFIG_SUNXI_WATCHDOG=y diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 8de74dcfa18cf..b35ead8a65d77 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -573,6 +573,17 @@ config HW_RANDOM_JH7110 To compile this driver as a module, choose M here. The module will be called jh7110-trng. +config HW_RANDOM_K230 + tristate "Canaan K230 True Random Number Generator support" + depends on HW_RANDOM || ARCH_RV64I + default ARCH_CANAAN + help + This driver provides support for the True Random Number + Generator available in K230 SOC. + + To compile this driver as a module, choose M here: the module + will be called k230-rng. + endif # HW_RANDOM config UML_RANDOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 32549a1186dc5..ae4afdc23d98f 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o obj-$(CONFIG_HW_RANDOM_CN10K) += cn10k-rng.o obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o +obj-$(CONFIG_HW_RANDOM_K230) += k230-rng.o diff --git a/drivers/char/hw_random/k230-rng.c b/drivers/char/hw_random/k230-rng.c new file mode 100644 index 0000000000000..8dd19fee0bd7d --- /dev/null +++ b/drivers/char/hw_random/k230-rng.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PUF_REG_TRNG_OFFSET 0x2a0 + +struct k230_rng { + void __iomem *base; + struct hwrng rng; + struct device *dev; +}; + +#define to_k230_rng(p) container_of(p, struct k230_rng, rng) + + +static int k230_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct k230_rng *k230rng = to_k230_rng(rng); + int retval = 0; + + while (max >= sizeof(u32)) { + *(u32 *)buf = readl(k230rng->base + PUF_REG_TRNG_OFFSET); + + retval += sizeof(u32); + buf += sizeof(u32); + max -= sizeof(u32); + } + + return retval; +} + +static int k230_rng_probe(struct platform_device *pdev) +{ + struct k230_rng *rng; + struct resource *res; + int ret; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng) + return -ENOMEM; + + rng->dev = &pdev->dev; + platform_set_drvdata(pdev, rng); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rng->base)) + return PTR_ERR(rng->base); + + rng->rng.name = pdev->name; + rng->rng.read = k230_rng_read; + + ret = devm_hwrng_register(&pdev->dev, &rng->rng); + if (ret) { + dev_err(&pdev->dev, "failed to register hwrng\n"); + return ret; + } + + dev_info(&pdev->dev, "K230 TRNG driver register!\n"); + + return 0; +} + +static const struct of_device_id k230_rng_dt_ids[] = { + { .compatible = "canaan,k230-rng" }, + { } +}; +MODULE_DEVICE_TABLE(of, k230_rng_dt_ids); + +static struct platform_driver k230_rng_driver = { + .probe = k230_rng_probe, + .driver = { + .name = "k230-rng", + .of_match_table = of_match_ptr(k230_rng_dt_ids), + }, +}; + +module_platform_driver(k230_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Canaan K230 random number generator driver"); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c761952f0dc6d..fa8451721e84e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -796,5 +796,6 @@ config CRYPTO_DEV_SA2UL source "drivers/crypto/aspeed/Kconfig" source "drivers/crypto/starfive/Kconfig" +source "drivers/crypto/canaan/Kconfig" endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index d859d6a5f3a45..8a3cf4e4af6e8 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -51,3 +51,4 @@ obj-y += hisilicon/ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += intel/ obj-y += starfive/ +obj-y += canaan/ diff --git a/drivers/crypto/canaan/Kconfig b/drivers/crypto/canaan/Kconfig new file mode 100644 index 0000000000000..de3bd7e3d7a7d --- /dev/null +++ b/drivers/crypto/canaan/Kconfig @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# k230 AES-GCM configuration +# +config CRYPTO_DEV_KENDRYTE_CRYP + tristate "Support for K230 crypto accelerators" + select CRYPTO_AES + select CRYPTO_BLKCIPHER + default ARCH_CANAAN + help + This driver interfaces with the hardware crypto + accelerator for K230. + Supporting AES-GCM encryption and + decryption. + +config CRYPTO_DEV_KENDRYTE_HASH + tristate "Support for K230 sha256 accelerators" + select CRYPTO_HASH + select CRYPTO_SHA256 + default ARCH_CANAAN + help + This driver interfaces with the hardware + hash accelerator for K230. + Supporting sha256 hashing + algo. + +config CRYPTO_DEV_KENDRYTE_RSA + tristate "Support for k230 rsa-2048 accelerator" + select CRYPTO_SKCIPHER + default ARCH_CANAAN + help + This driver interfaces with the hardware + rsa accelerator for K230. + Supporting rsa-1024, rsa-2048, rsa-3072, + rsa-4096 encryption and decryption algo. \ No newline at end of file diff --git a/drivers/crypto/canaan/Makefile b/drivers/crypto/canaan/Makefile new file mode 100644 index 0000000000000..57206d9a8351b --- /dev/null +++ b/drivers/crypto/canaan/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Canaan AES-GCM Makefile +# +obj-$(CONFIG_CRYPTO_DEV_KENDRYTE_CRYP) += kendryte_crypto.o +kendryte_crypto-objs := kendryte-aes.o + +obj-$(CONFIG_CRYPTO_DEV_KENDRYTE_HASH) += kendryte_hash.o +kendryte_hash-objs := kendryte-hash.o + +obj-$(CONFIG_CRYPTO_DEV_KENDRYTE_RSA) += kendryte_rsa.o +kendryte_rsa-objs := kendryte-rsa.o \ No newline at end of file diff --git a/drivers/crypto/canaan/kendryte-aes.c b/drivers/crypto/canaan/kendryte-aes.c new file mode 100644 index 0000000000000..b6eb19beebc84 --- /dev/null +++ b/drivers/crypto/canaan/kendryte-aes.c @@ -0,0 +1,1361 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kendryte-aes.h" + +// #define _debug_print + +/***************************************************************************** + * Macros + ****************************************************************************/ +/** + * @brief Convert number of bits to number of bytes + * + * @param[in] bits Number of bits. + * @return Number of bytes. + */ +#define b2B(bits) (((bits) + 7) / 8) +/** + * @brief Convert number of bytes to number of bits + * + * @param[in] len Number of bytes. + * @return Number of bits. + */ +#define B2b(len) (8 * (len)) + +static void *puf_dma_base; +static void *puf_crypto_base; +static void *puf_kwp_base; +static void *puf_ka_base; +void *dma_virt_in; +void *dma_virt_out; +dma_addr_t dma_phys_in; +dma_addr_t dma_phys_out; +uint8_t kwp_buffer[BUFFER_SIZE]; +struct kendryte_crypto_info crypto_info; + +//----------------------BASE FUNCTION ----------------------------------------// +uint32_t be2le(uint32_t var) +{ + return (((0xff000000 & var) >> 24) | ((0x00ff0000 & var) >> 8) | + ((0x0000ff00 & var) << 8) | ((0x000000ff & var) << 24)); +} + +static void write_data(uint32_t *dst, uint8_t *src, size_t length, bool le) +{ + uint32_t *src32 = (uint32_t *)src; + + length = length / 4; + size_t i; + + for (i = 0; i < length; ++i) { + if (le) + *(dst + i) = be2le(*(src32 + i)); + else + *(dst + i) = *(src32 + i); + } +} + +static void read_data(uint8_t *dst, uint32_t *src, size_t length, bool le) +{ + uint32_t *dst32 = (uint32_t *)dst; + uint32_t word_nums = 0, rest = 0, last_word; + + word_nums = length / 4; + rest = length % 4; + uint32_t i; + + for (i = 0; i < word_nums; i++) { + if (le) + dst32[i] = be2le(src[i]); + else + dst32[i] = src[i]; + } + + if (rest != 0) { + if (le) + last_word = be2le(src[word_nums]); + else + last_word = src[word_nums]; + + memcpy(dst + (word_nums * 4), &last_word, rest); + } +} + +static enum kendryte_status_t get_config(uint32_t *cfg, struct kendryte_aes_ctx *ctx, + bool gctr, bool reg_in, bool reg_out) +{ + uint32_t val32; + + switch (ctx->cipher) { + case AES: + switch ((ctx->keylen) << 3) { + case 128: + val32 = 0x0; + break; + case 192: + val32 = 0x1; + break; + case 256: + val32 = 0x2; + break; + default: + return E_FIRMWARE; + } + break; + + default: + return E_FIRMWARE; + } + + if ((ctx->inlen) != ULLONG_MAX) + val32 |= 0x1 << GCM_CFG_GHASH_BITS; + + if (gctr) + val32 |= 0x1 << GCM_CFG_GCTR_BITS; + + val32 |= (ctx->encrypt ? 0x1 : 0x0) << GCM_CFG_ENCRYPT_BITS; + + if (reg_in) + val32 |= 0x1 << GCM_CFG_REG_IN_BITS; + + if (reg_out) + val32 |= 0x1 << GCM_CFG_REG_OUT_BITS; + + *cfg = val32; + + return SUCCESS; +} + +struct blsegs segment(uint8_t *buf, uint32_t buflen, const uint8_t *in, uint32_t inlen, + uint32_t blocksize, uint32_t minlen) +{ + struct blsegs ret = { .nsegs = 0 }; + // calculate total number of blocks to be processed + uint32_t nprocblocks = 0; + + if ((buflen + inlen) >= (minlen + blocksize)) + nprocblocks = (buflen + inlen - minlen) / blocksize; + + // no available block for processing, keep input in the internal buffer. + if (nprocblocks == 0) { + ret.seg[ret.nsegs++] = (struct segstr){ false, buf, buflen }; + ret.seg[ret.nsegs++] = (struct segstr){ false, in, inlen }; + return ret; + } + + const uint8_t *start = in; + // some blocks are ready for processing, using bytes in the internal buffer first + if (buflen != 0) { + // if all data in the internal buffer will be processed + if (nprocblocks * blocksize >= buflen) { + // fill buffer if not a complete block + uint32_t proclen = blocksize; + + nprocblocks--; + while (proclen < buflen) { + proclen += blocksize; + nprocblocks--; + } + memcpy(buf + buflen, start, proclen - buflen); + ret.seg[ret.nsegs++] = (struct segstr){ true, buf, proclen }; + start += (proclen - buflen); + inlen -= (proclen - buflen); + } else { + // some data will be remained in the internal buffer + ret.seg[ret.nsegs++] = + (struct segstr){ true, buf, nprocblocks * blocksize }; + ret.seg[ret.nsegs++] = + (struct segstr){ false, buf + nprocblocks * blocksize, + buflen - nprocblocks * blocksize }; + nprocblocks = 0; + } + } + // deal with input data + if (nprocblocks > 0) { + ret.seg[ret.nsegs++] = + (struct segstr){ true, start, nprocblocks * blocksize }; + } + ret.seg[ret.nsegs++] = (struct segstr){ false, start + nprocblocks * blocksize, + inlen - nprocblocks * blocksize }; + + return ret; +} + +//----------------------KWP FUNCTION----------------------------------------// +static enum kendryte_status_t kwp_start(void) +{ + uint32_t val32; + + writel(0x1, puf_kwp_base + KWP_START_OFFSET); + while (((val32 = readl(puf_kwp_base + KWP_STATUS_OFFSET)) & + KWP_STATUS_BUSY_MASK) != 0) + ; + + if (val32 & (0x1 << 2)) + return E_DENY; + else if (val32 & (0x1 << 3)) + return E_OVERFLOW; + else if (val32 & (0x1 << 4)) + return E_UNDERFLOW; + else if (val32 & (0x1 << 5)) + return E_VERFAIL; + else if (val32 != 0) { + pr_err("Error, KWP status: 0x%08x\n", val32); + return E_ERROR; + } + + return SUCCESS; +} + +static enum kendryte_status_t ka_skslot_check(bool valid, enum kendryte_ka_slot_t slot, + uint32_t keybits) +{ + // check keybits + switch (slot) { + case SK128_0: + case SK128_1: + case SK128_2: + case SK128_3: + case SK128_4: + case SK128_5: + case SK128_6: + case SK128_7: + if (keybits > 128) + return E_OVERFLOW; + break; + case SK256_0: + case SK256_1: + case SK256_2: + case SK256_3: + if (keybits > 256) + return E_OVERFLOW; + else if ((keybits <= 128) && (keybits != 0)) + return E_UNDERFLOW; + break; + case SK512_0: + case SK512_1: + if (keybits > 512) + return E_OVERFLOW; + else if ((keybits <= 256) && (keybits != 0)) + return E_UNDERFLOW; + break; + default: + return E_INVALID; + } + + // check registers + if (valid) { + uint32_t key_info; + uint32_t idx; + uint32_t tagbase; + + switch (slot) { + case SK128_0: + case SK128_1: + case SK128_2: + case SK128_3: + case SK128_4: + case SK128_5: + case SK128_6: + case SK128_7: + idx = slot - SK128_0; + tagbase = 0x30; + key_info = + readl(puf_ka_base + KA_SK_0_OFFSET + idx * 4); + if (((key_info & SK_KEY_VAILD_MASK) == 0) || + (((key_info & SK_KEY_SIZE_MASK) >> 4) != keybits) || + (((key_info & SK_KEY_TAG_MASK) >> 16) != + (tagbase + idx))) + return E_INVALID; + break; + case SK256_0: + case SK256_1: + case SK256_2: + case SK256_3: + idx = slot - SK256_0; + tagbase = 0x50; + key_info = readl(puf_ka_base + KA_SK_0_OFFSET + + idx * 2 * 4); + if (((key_info & SK_KEY_VAILD_MASK) == 0) || + (((key_info & SK_KEY_SIZE_MASK) >> 4) != keybits) || + (((key_info & SK_KEY_TAG_MASK) >> 16) != + (tagbase + idx)) || + (readl(puf_ka_base + KA_SK_0_OFFSET + idx * 2 * 4 + + 4) != ((tagbase + idx) << 16))) + return E_INVALID; + break; + case SK512_0: + case SK512_1: + idx = slot - SK512_0; + tagbase = 0x60; + key_info = readl(puf_ka_base + KA_SK_0_OFFSET + + idx * 4 * 4); + if (((key_info & SK_KEY_VAILD_MASK) == 0) || + (((key_info & SK_KEY_SIZE_MASK) >> 4) != keybits) || + (((key_info & SK_KEY_TAG_MASK) >> 16) != + (tagbase + idx)) || + (readl(puf_ka_base + KA_SK_0_OFFSET + idx * 4 * 4 + + 4) != ((tagbase + idx) << 16)) || + (readl(puf_ka_base + KA_SK_0_OFFSET + idx * 4 * 4 + + 8) != ((tagbase + idx) << 16)) || + (readl(puf_ka_base + KA_SK_0_OFFSET + idx * 4 * 4 + + 12) != ((tagbase + idx) << 16))) + return E_INVALID; + break; + default: + return E_INVALID; + } + } + + return SUCCESS; +} + +static enum kendryte_status_t keyslot_check(bool valid, enum kendryte_key_type_t keytype, + uint32_t slot, uint32_t keybits) +{ + switch (keytype) { + case SSKEY: + return ka_skslot_check(valid, (enum kendryte_ka_slot_t)slot, + keybits); + default: + return E_INVALID; + } +} + +int get_key_slot_idx(enum kendryte_key_type_t keytype, enum kendryte_ka_slot_t keyslot) +{ + switch (keytype) { + case SSKEY: + switch (keyslot) { + case SK128_0: + case SK128_1: + case SK128_2: + case SK128_3: + case SK128_4: + case SK128_5: + case SK128_6: + case SK128_7: + return (keyslot - SK128_0); + case SK256_0: + case SK256_1: + case SK256_2: + case SK256_3: + return ((keyslot - SK256_0) * 2); + case SK512_0: + case SK512_1: + return ((keyslot - SK512_0) * 4); + default: + return -1; + } + break; + + default: + return -1; + } +} + +//---------------------------------CRYTPO FUNCTION----------------------------------------// +enum kendryte_status_t crypto_write_iv(uint8_t *iv, size_t length) +{ + if (length > IV_MAXLEN) + return E_INVALID; + + write_data((uint32_t *)(puf_crypto_base + CRYPTO_IV_OFFSET), iv, length, + true); + + return SUCCESS; +} + +enum kendryte_status_t crypto_write_dgst(uint8_t *dgst, size_t length) +{ + if (length > DGST_INT_STATE_LEN) + return E_INVALID; + + write_data((uint32_t *)(puf_crypto_base + CRYPTO_DGST_IN_OFFSET), dgst, + length, true); + + return SUCCESS; +} + +void crypto_read_dgest(uint8_t *out, size_t length) +{ + length = length < DGST_INT_STATE_LEN ? length : DGST_INT_STATE_LEN; + read_data(out, (void *)(puf_crypto_base + CRYPTO_DGST_OUT_OFFSET), + length, true); +} + +//----------------------------------------DMA FUNCTION----------------------------------------// +void dma_write_start(void) +{ + writel(0x1, puf_dma_base + DMA_START_OFFSET); +} + +bool dma_check_busy_status(uint32_t *status) +{ + uint32_t stat = readl(puf_dma_base + DMA_STAT_0_OFFSET); + bool busy = (stat & DMA_STATUS_0_BUSY_MASK) != 0; + + if (status != NULL) + *status = stat; + + return busy; +} + +void dma_write_config_0(bool rng_enable, bool sgdma_enable, bool no_cypt) +{ + uint32_t value = 0; + + if (rng_enable) + value |= 0x1; + if (sgdma_enable) + value |= 0x1 << 1; + if (no_cypt) + value |= 0x1 << 2; + + writel(value, puf_dma_base + DMA_CFG_0_OFFSET); +} + +void dma_write_data_block_config(bool head, bool tail, bool dn_intrpt, + bool dn_pause, uint32_t offset) +{ + uint32_t value = 0; + + if (head) + value |= 0x1 << DMA_DSC_CFG_4_HEAD_BITS; + if (tail) + value |= 0x1 << DMA_DSC_CFG_4_TAIL_BITS; + if (dn_intrpt) + value |= 0x1 << DMA_DSC_CFG_4_DN_INTRPT_BITS; + if (dn_pause) + value |= 0x1 << DMA_DSC_CFG_4_DN_PAUSE_BITS; + value |= offset << DMA_DSC_CFG_4_OFFSET_BITS; + + writel(value, puf_dma_base + DMA_DSC_CFG_4_OFFSET); +} + +void dma_write_rwcfg(const uint8_t *out, const uint8_t *in, uint32_t len) +{ + writel(len, puf_dma_base + DMA_DSC_CFG_2_OFFSET); + + if (out == NULL) + writel((uintptr_t)out, puf_dma_base + DMA_DSC_CFG_1_OFFSET); + else + writel(dma_phys_out, puf_dma_base + DMA_DSC_CFG_1_OFFSET); + + if (in == NULL) + writel((uintptr_t)in, puf_dma_base + DMA_DSC_CFG_0_OFFSET); + else { + memcpy(dma_virt_in, in, len); + writel(dma_phys_in, puf_dma_base + DMA_DSC_CFG_0_OFFSET); + } +} + +void dma_write_key_config_0(enum kendryte_key_type_t keytype, + enum kendryte_algo_type_t algo, uint32_t size, + uint32_t slot_index) +{ + uint32_t value = 0; + + value |= slot_index << DMA_KEY_CFG_0_KEY_IDX_BITS; + value |= size << DMA_KEY_CFG_0_KEY_SIZE_BITS; + value |= algo << DMA_KEY_CFG_0_KEY_DST_BITS; + value |= keytype; + + writel(value, puf_dma_base + DMA_KEY_CFG_0_OFFSET); +} + +static enum kendryte_status_t gcm_prepare(struct kendryte_aes_ctx *ctx, + const uint8_t *out, uint32_t inlen) +{ + enum kendryte_status_t check; + uint32_t val32; + + dma_write_key_config_0(ctx->keytype, ALGO_TYPE_GCM, (ctx->keylen << 3), + get_key_slot_idx(ctx->keytype, ctx->keyslot)); + + check = get_config(&val32, ctx, out != NULL, false, false); + if (check != SUCCESS) + return check; + + writel(val32, ctx->dev->base + GCM_CFG_1_OFFSET); + + if ((ctx->inlen) != ULLONG_MAX) + writel(ctx->incj0, ctx->dev->base + GCM_CFG_2_OFFSET); + else + writel(0x0, ctx->dev->base + GCM_CFG_2_OFFSET); + + // J_0 + if (out != NULL) { + crypto_write_iv(ctx->j0, AES_BLOCK_SIZE); + if ((ctx->inlen) != ULLONG_MAX && inlen > 0) + ctx->incj0 += + ((inlen - 1 + AES_BLOCK_SIZE) / AES_BLOCK_SIZE); + } + + // Restore GHASH + crypto_write_dgst(ctx->ghash, AES_BLOCK_SIZE); + + return SUCCESS; +} + +static enum kendryte_status_t gcm_postproc(struct kendryte_aes_ctx *ctx) +{ + crypto_read_dgest(ctx->ghash, AES_BLOCK_SIZE); + return SUCCESS; +} + +static enum kendryte_status_t _ctx_update(struct kendryte_aes_ctx *ctx, uint8_t *out, + uint32_t *outlen, const uint8_t *in, + uint32_t inlen, bool last) +{ + uint32_t val32; + enum kendryte_status_t check; + + if (dma_check_busy_status(NULL)) + return E_BUSY; + + dma_write_config_0(false, false, false); + dma_write_data_block_config(ctx->start ? false : true, last, true, true, + 0); + dma_write_rwcfg(out, in, + inlen); // config physical address of DMA read and write + + check = gcm_prepare(ctx, out, inlen); + if (check != SUCCESS) + return check; + + // flush_cache_all(); + dma_write_start(); + while (dma_check_busy_status(&val32)) + ; + + if (val32 != 0) { + pr_err("DMA status 0: 0x%08x\n", val32); + return E_ERROR; + } + + val32 = readl(ctx->dev->base + GCM_STAT_OFFSET); + if ((val32 & GCM_STATUS_RESP_MASK) != 0) { + pr_err("GCM status: 0x%08x\n", val32); + return E_ERROR; + } + + check = gcm_postproc(ctx); + if (check != SUCCESS) + return check; + + if (out != NULL) { + *outlen = inlen; + memcpy(out, dma_virt_out, inlen); + } + + return SUCCESS; +} + +static enum kendryte_status_t ctx_update(enum gcm_op op, struct kendryte_aes_ctx *ctx, + bool encrypt, uint8_t *out, + uint32_t *outlen, const uint8_t *in, + uint32_t inlen) +{ + uint32_t i; + // check ctx is owned by this operation (GCM mode) + if ((ctx->op != op) || (ctx->encrypt != encrypt)) + return E_UNAVAIL; + + // continue if msg is NULL or msglen is zero + if ((in == NULL) || (inlen == 0)) { + if (outlen != NULL) + *outlen = 0; + return SUCCESS; + } + + switch (ctx->stage) { + case GCM_NONE_S: + break; + case GCM_AAD_S: + ctx->aadlen += (uint64_t)inlen; + break; + case GCM_TEXT_S: + ctx->inlen += (uint64_t)inlen; + break; + default: + return E_FIRMWARE; + } + + struct blsegs segs = segment(ctx->buffer, ctx->buflen, in, inlen, + AES_BLOCK_SIZE, ctx->minlen); + ctx->buflen = 0; + uint32_t seglen = 0; + enum kendryte_status_t check = SUCCESS; + + if (ctx->stage == GCM_TEXT_S) + *outlen = 0; + + for (i = 0; i < segs.nsegs; i++) { + if (segs.seg[i].process) { + // process + if (ctx->stage == GCM_TEXT_S) { + check = _ctx_update(ctx, out + *outlen, &seglen, + segs.seg[i].addr, + segs.seg[i].len, false); + } else { + check = _ctx_update(ctx, NULL, NULL, + segs.seg[i].addr, + segs.seg[i].len, false); + } + + if (check != SUCCESS) { + // release context + ctx->op = GCM_AVAILABLE_OP; + return check; + } + + if (ctx->stage == GCM_TEXT_S) + *outlen += seglen; + + if (ctx->start == false) + ctx->start = true; + } else { + // keep in the internal buffer + if ((segs.seg[i].addr == ctx->buffer) && + (ctx->buflen == 0)) + // skip copy what already in the right place + ctx->buflen += segs.seg[i].len; + else { + // copy into the buffer + memmove(ctx->buffer + ctx->buflen, + segs.seg[i].addr, segs.seg[i].len); + ctx->buflen += segs.seg[i].len; + } + } + } + + return SUCCESS; +} + +static enum kendryte_status_t gcm_tag(struct kendryte_aes_ctx *ctx, uint8_t *tag, + uint32_t taglen, bool from_reg) +{ + uint32_t val32, tmplen = 0; + enum kendryte_status_t check; + + union { + uint8_t uc[AES_BLOCK_SIZE]; + uint32_t u32[AES_BLOCK_SIZE / 4]; + } tmp; + + if (ctx->op == GCM_GHASH_OP) { + memcpy(tag, ctx->ghash, taglen); + return SUCCESS; + } + + // len(A) || len(C) + tmp.u32[0] = be2le((uint32_t)((ctx->aadlen << 3) >> 32)); + tmp.u32[1] = be2le((uint32_t)(ctx->aadlen << 3)); + tmp.u32[2] = be2le((uint32_t)((ctx->inlen << 3) >> 32)); + tmp.u32[3] = be2le((uint32_t)(ctx->inlen << 3)); + check = _ctx_update(ctx, NULL, NULL, tmp.uc, AES_BLOCK_SIZE, + true); + if (check != SUCCESS) + return check; + + // last GCTR + ctx->inlen = ULLONG_MAX; + + if (!from_reg) { + check = _ctx_update(ctx, tmp.uc, &tmplen, ctx->ghash, + AES_BLOCK_SIZE, true); + if ((check != SUCCESS) || (tmplen != AES_BLOCK_SIZE)) + return E_FIRMWARE; + + memcpy(tag, tmp.uc, taglen); + return SUCCESS; + } + + crypto_write_iv(ctx->j0, AES_BLOCK_SIZE); + + check = get_config(&val32, ctx, true, true, true); + if (check != SUCCESS) + return check; + + writel(val32, ctx->dev->base + GCM_CFG_1_OFFSET); + writel(0, ctx->dev->base + GCM_CFG_2_OFFSET); + + dma_write_data_block_config(true, true, true, true, 0); + dma_write_rwcfg(NULL, NULL, 0); + dma_write_config_0(false, false, false); + dma_write_key_config_0(ctx->keytype, ALGO_TYPE_GCM, (ctx->keylen << 3), + get_key_slot_idx(ctx->keytype, ctx->keyslot)); + + flush_cache_all(); + dma_write_start(); + + while (dma_check_busy_status(&val32)) + ; + + if (val32 != 0) { + pr_err("DMA status 0: 0x%08x\n", val32); + return E_ERROR; + } + + val32 = readl(ctx->dev->base + GCM_STAT_OFFSET); + if ((val32 & GCM_STATUS_RESP_MASK) != 0) { + pr_err("GCM status: 0x%08x\n", val32); + return E_ERROR; + } + crypto_read_dgest(tag, taglen); + + return SUCCESS; +} + +static enum kendryte_status_t ctx_final(enum gcm_op op, struct kendryte_aes_ctx *ctx, + bool encrypt, uint8_t *out, uint32_t *outlen, + uint8_t *tag, uint32_t taglen, bool from_reg) +{ + enum kendryte_status_t check = SUCCESS; + + if (outlen != NULL) + *outlen = 0; + + // check ctx is owned by this operation (GCM mode) + if ((ctx->op != op) || (ctx->encrypt != encrypt)) + return E_UNAVAIL; + + if (ctx->buflen != 0) { + check = _ctx_update(ctx, out, outlen, ctx->buffer, + ctx->buflen, true); + if (check != SUCCESS) + goto release_gcm; + } + + if (encrypt) + check = gcm_tag(ctx, tag, taglen, from_reg); + else + check = gcm_tag(ctx, tag, taglen, !from_reg); + +release_gcm: + ctx->op = GCM_AVAILABLE_OP; + + return check; +} + +static enum kendryte_status_t ctx_init(enum gcm_op op, struct kendryte_aes_ctx *ctx, + bool encrypt, enum kendryte_cipher_t cipher, + enum kendryte_key_type_t keytype, size_t keyaddr, + uint32_t keybits, const uint8_t *j0) +{ + enum kendryte_status_t check; + + // abort if gcm ctx is occupied + if (ctx->op != GCM_AVAILABLE_OP) + return E_BUSY; + + // check if op is valid + switch (op) { + case GCM_GHASH_OP: + case AES_GCM_OP: + case GCM_GMAC_OP: + break; + default: + return E_INVALID; + } + + // check key settings for block cipher + check = keyslot_check(true, keytype, (uint32_t)keyaddr, + keybits); + if ((keytype != SWKEY) && (check != SUCCESS)) + return check; + + // check and set J_0 if needed + if (op != GCM_GHASH_OP) { + if (j0 == NULL) + return E_INVALID; + memcpy(ctx->j0, j0, AES_BLOCK_SIZE); + } + + // initialize for block-cipher GCM mode + ctx->keylen = 0; + ctx->ivlen = 0; + ctx->aadlen = 0; + ctx->taglen = 0; + ctx->pclen = 0; + ctx->inlen = 0; + ctx->minlen = 1; + ctx->buflen = 0; + ctx->op = op; + ctx->incj0 = 1; + ctx->stage = GCM_NONE_S; + ctx->cipher = cipher; + ctx->encrypt = encrypt; + memset(ctx->ghash, 0, AES_BLOCK_SIZE); + // set key + ctx->keylen = keybits >> 3; + ctx->keytype = keytype; + if (keytype != SWKEY) + ctx->keyslot = (uint32_t)keyaddr; + else + memcpy(ctx->key, (const void *)keyaddr, b2B(keybits)); + + return SUCCESS; +} + +static enum kendryte_status_t build_j0(uint8_t *j0, enum kendryte_cipher_t cipher, + enum kendryte_key_type_t keytype, size_t keyaddr, + uint32_t keybits, const uint8_t *iv, + uint32_t ivlen) +{ + uint8_t tmp[AES_BLOCK_SIZE]; + uint64_t ivbits = ivlen << 3; + enum kendryte_status_t check; + + if ((iv == NULL) || (ivlen == 0)) { + pr_err("%s() Error: need more params!\n", __func__); + return E_INVALID; + } + + if (ivlen == 12) { + memcpy(j0, iv, ivlen); + memset(j0 + ivlen, 0, 3); + *(j0 + 15) = 1; + return SUCCESS; + } + + struct kendryte_aes_ctx ctx = { .op = GCM_AVAILABLE_OP }; + // GHASH init + check = ctx_init(GCM_GHASH_OP, &ctx, false, cipher, keytype, + keyaddr, keybits, NULL); + if (check != SUCCESS) + return check; + // GHASH update + check = ctx_update(GCM_GHASH_OP, &ctx, false, NULL, NULL, iv, + ivlen); + if (check != SUCCESS) + return check; + + memset(tmp, 0, AES_BLOCK_SIZE); + if ((ivlen % AES_BLOCK_SIZE) != 0) { + uint32_t padlen = AES_BLOCK_SIZE - (ivlen % AES_BLOCK_SIZE); + + check = ctx_update(GCM_GHASH_OP, &ctx, false, NULL, NULL, + tmp, padlen); + if (check != SUCCESS) + return check; + } + + *((uint32_t *)(tmp + 8)) = be2le((uint32_t)(ivbits >> 32)); + *((uint32_t *)(tmp + 12)) = be2le((uint32_t)ivbits); + + check = ctx_update(GCM_GHASH_OP, &ctx, false, NULL, NULL, tmp, + AES_BLOCK_SIZE); + if (check != SUCCESS) + return check; + + return ctx_final(GCM_GHASH_OP, &ctx, false, NULL, NULL, j0, + AES_BLOCK_SIZE, false); +} + +static enum kendryte_status_t step_stage(struct kendryte_aes_ctx *ctx, + enum gcm_stage stage) +{ + switch (ctx->stage) { + case GCM_NONE_S: + break; + case GCM_AAD_S: + switch (stage) { + case GCM_AAD_S: + return SUCCESS; + case GCM_TEXT_S: + if (ctx->buflen != 0) { // clear AAD and start input + enum kendryte_status_t check; + + check = _ctx_update(ctx, NULL, NULL, + ctx->buffer, ctx->buflen, + true); + if (check != SUCCESS) + return check; + ctx->buflen = 0; + } + break; + default: + return E_FIRMWARE; + } + break; + case GCM_TEXT_S: + if (stage != GCM_TEXT_S) + return E_INVALID; + break; + default: + return E_FIRMWARE; + } + + if (ctx->stage != stage) { + ctx->start = false; + ctx->stage = stage; + } + + return SUCCESS; +} + +static enum kendryte_status_t gcm_init(struct kendryte_aes_ctx *ctx, + enum kendryte_cipher_t cipher, + enum kendryte_key_type_t keytype, size_t keyaddr, + uint32_t keybits, const uint8_t *iv, + uint32_t ivlen, bool encrypt) +{ + enum kendryte_status_t check; + uint8_t j0[AES_BLOCK_SIZE]; + + check = build_j0(j0, cipher, keytype, keyaddr, keybits, iv, + ivlen); + if (check != SUCCESS) + return check; + + return ctx_init(AES_GCM_OP, ctx, encrypt, cipher, keytype, keyaddr, + keybits, j0); +} + +static enum kendryte_status_t gcm_update(struct kendryte_aes_ctx *ctx, uint8_t *out, + uint32_t *outlen, const uint8_t *in, + uint32_t inlen, bool encrypt) +{ + enum kendryte_status_t check = + step_stage(ctx, (out == NULL) ? GCM_AAD_S : GCM_TEXT_S); + + if (check != SUCCESS) + return check; + + return ctx_update(AES_GCM_OP, ctx, encrypt, out, outlen, in, inlen); +} + +static enum kendryte_status_t import_plaintext_key_to_slot( + struct kendryte_aes_ctx *ctx, enum kendryte_key_type_t keytype, + enum kendryte_ka_slot_t slot, const uint8_t *key, uint32_t keybits) +{ + enum kendryte_status_t check; + int i; + uint32_t val32; + + // keytype MUST be SSKEY + if (keytype != SSKEY) + return E_INVALID; + + // check KA key slot by key length + check = keyslot_check(false, keytype, slot, keybits); + if (check != SUCCESS) + return check; + + if (readl(puf_kwp_base + KWP_STATUS_OFFSET) & KWP_STATUS_BUSY_MASK) + return E_BUSY; + + val32 = 0x0 << 0 | keybits << 8; + + switch (keytype) { + case SSKEY: + val32 |= 0x0 << 19; + break; + default: + return E_FIRMWARE; + } + + val32 |= get_key_slot_idx(keytype, slot) << 20; + writel(val32, puf_kwp_base + KWP_CONFIG_OFFSET); + + memset(kwp_buffer, 0, KWP_KEY_MAXLEN); + memcpy(kwp_buffer, key, b2B(keybits)); + + uint32_t *buf = (uint32_t *)kwp_buffer; + + for (i = 0; i < KWP_KEY_MAXLEN / 4; ++i) + writel(be2le(buf[i]), puf_kwp_base + KWP_KEY_IN_OUT_OFFSET + + 4 * i); // store key into KWP + + return kwp_start(); +} + +static enum kendryte_status_t clear_ka_slot(struct kendryte_aes_ctx *ctx, + enum kendryte_ka_slot_t slot) +{ + uint32_t val32; + + switch (slot) { + case SK128_0: + case SK128_1: + case SK128_2: + case SK128_3: + case SK128_4: + case SK128_5: + case SK128_6: + case SK128_7: + val32 = 0x1 << (slot - SK128_0); + writel(val32, puf_ka_base + KA_SK_FREE_OFFSET); + return SUCCESS; + case SK256_0: + case SK256_1: + case SK256_2: + case SK256_3: + val32 = 0x3 << (2 * (slot - SK256_0)); + writel(val32, puf_ka_base + KA_SK_FREE_OFFSET); + return SUCCESS; + case SK512_0: + case SK512_1: + val32 = 0xf << (4 * (slot - SK512_0)); + writel(val32, puf_ka_base + KA_SK_FREE_OFFSET); + return SUCCESS; + + default: + return E_INVALID; + } +} + +static enum kendryte_status_t clear_key(struct kendryte_aes_ctx *ctx, + enum kendryte_key_type_t keytype, + enum kendryte_ka_slot_t slot, uint32_t keybits) +{ + enum kendryte_status_t check; + + check = keyslot_check(true, keytype, slot, keybits); + if (check != SUCCESS) + return check; + + return clear_ka_slot(ctx, slot); +} + +static int kendryte_gcm_aes_setkey(struct crypto_aead *tfm, const uint8_t *key, + unsigned int keylen) +{ + struct kendryte_aes_ctx *ctx = crypto_aead_ctx(tfm); + + ctx->keylen = keylen; // key length in bytes + memcpy(ctx->key, key, keylen); + + return 0; +} + +static int kendryte_gcm_aes_setauthsize(struct crypto_aead *tfm, + uint32_t authsize) +{ + switch (authsize) { + case 16: + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Encryption case: + * INPUT = Assocdata || Plaintext + * <- aadlen -> <- pclen -> + * <---------- total -----------> + * + * OUTPUT = Assocdata || Ciphertext || Tag + * <- aadlen -> <- outlen -> <- taglen -> + * <--------- total -----------> + * + * Decryption case: + * INPUT = Assocdata || Ciphertext || Tag + * <- aadlen -> <------- pclen ------------> + * <- taglen -> + * <--------- total --------------> + * + * OUTPUT = Assocdata || Plaintext + * <- aadlen -> <- crypten - tag -> + * <---------- total -----> + */ +static int kendryte_gcm_aes_crypt(struct aead_request *req, bool encrypt) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct kendryte_aes_ctx *ctx = crypto_aead_ctx(tfm); + enum kendryte_status_t check; + void *buf_src; + void *buf_dst; + const uint8_t *in; + uint8_t *tag; + uint8_t *tmptag; + uint8_t *out; + uint32_t inlen; + uint32_t outlen; + uint32_t toutlen; + uint32_t total; + enum kendryte_cipher_t cipher; + enum kendryte_key_type_t keytype; + enum kendryte_ka_slot_t keyslot; + const uint8_t *key; + uint32_t keybits; + const uint8_t *iv; + uint32_t ivlen; + uint8_t *aad; + uint32_t aadlen; + uint32_t taglen; + uint32_t pclen; + int ret = 0; + + puf_dma_base = ioremap(0x91210000, 0x100); + puf_kwp_base = ioremap(0x91210300, 0x100); + puf_crypto_base = ioremap(0x91210100, 0x100); + puf_ka_base = ioremap(0x91210C00, 0x100); + + cipher = AES; + keytype = SSKEY; + iv = req->iv; + ivlen = crypto_aead_ivsize(tfm); + aadlen = req->assoclen; + taglen = crypto_aead_authsize(tfm); + keybits = (ctx->keylen << 3); + key = ctx->key; + keyslot = (keybits > 128) ? SK256_0 : SK128_0; + pclen = req->cryptlen; + total = aadlen + pclen; + + buf_src = kzalloc(total, GFP_KERNEL); + if (encrypt) + buf_dst = kzalloc((total + taglen), GFP_KERNEL); + else + buf_dst = kzalloc((total - taglen), GFP_KERNEL); + + scatterwalk_map_and_copy(buf_src, req->src, 0, total, 0); + + if (aadlen > 0) { + aad = kzalloc(aadlen, GFP_KERNEL); + memcpy(aad, buf_src, aadlen); + } + + tag = kzalloc(AES_BLOCK_SIZE, GFP_KERNEL); + tmptag = kzalloc(AES_BLOCK_SIZE, GFP_KERNEL); + + // input data, plaintext or ciphertext + in = buf_src + aadlen; + inlen = pclen; + if (!encrypt) { + inlen -= taglen; + memcpy(tmptag, in + inlen, taglen); + } + + if (inlen > 0) + out = kzalloc(inlen, GFP_KERNEL); + else + out = kzalloc((inlen + 1), GFP_KERNEL); + + dma_virt_in = dma_alloc_coherent(ctx->dev->dev, (total + ivlen), + &dma_phys_in, GFP_KERNEL); + dma_virt_out = dma_alloc_coherent(ctx->dev->dev, (total + ivlen), + &dma_phys_out, GFP_KERNEL); + + // import key to internal slot + check = import_plaintext_key_to_slot(ctx, keytype, keyslot, key, keybits); + if (check != SUCCESS) + goto done; + + ctx->op = GCM_AVAILABLE_OP; + outlen = 0; + + // GCM init + check = gcm_init(ctx, cipher, keytype, keyslot, keybits, iv, ivlen, encrypt); + if (check != SUCCESS) + goto done; + + // GCM update + check = gcm_update(ctx, NULL, NULL, aad, aadlen, encrypt); + if (check != SUCCESS) + goto done; + + check = gcm_update(ctx, out, &toutlen, in, inlen, encrypt); + if (check != SUCCESS) + goto done; + outlen += toutlen; + + // GCM done + check = ctx_final(AES_GCM_OP, ctx, encrypt, out + outlen, &toutlen, + tag, taglen, true); + if (check != SUCCESS) + goto done; + + if (!encrypt) { + if (memcmp(tag, tmptag, taglen) != 0) { + check = E_VERFAIL; + goto done; + } + } + + outlen += toutlen; + + // clear key from internal slot + check = clear_key(ctx, keytype, keyslot, keybits); + if (check != SUCCESS) + goto done; + + if (aadlen > 0) { + memcpy(buf_dst, aad, aadlen); + memcpy(buf_dst + aadlen, out, outlen); + // output data, include or + if (encrypt) { + memcpy(buf_dst + aadlen + outlen, tag, taglen); + scatterwalk_map_and_copy(buf_dst, req->dst, 0, + total + taglen, 1); + } else { + scatterwalk_map_and_copy(buf_dst, req->dst, 0, + total - taglen, 1); + } + } else { + memcpy(buf_dst, out, outlen); + // output data, include or + if (encrypt) { + memcpy(buf_dst + outlen, tag, taglen); + scatterwalk_map_and_copy(buf_dst, req->dst, 0, + total + taglen, 1); + } else { + scatterwalk_map_and_copy(buf_dst, req->dst, 0, + total - taglen, 1); + } + } + +done: + if (check != SUCCESS) { + pr_err("Encrypt or Decrypt Error!\n"); + ret = -1; + } + + iounmap(puf_dma_base); + iounmap(puf_kwp_base); + iounmap(puf_crypto_base); + iounmap(puf_ka_base); + kfree(buf_src); + kfree(buf_dst); + if (aadlen > 0) + kfree(aad); + kfree(tag); + kfree(tmptag); + kfree(out); + dma_free_coherent(ctx->dev->dev, (total + ivlen), dma_virt_in, + dma_phys_in); + dma_free_coherent(ctx->dev->dev, (total + ivlen), dma_virt_out, + dma_phys_out); + + return ret; +} + +static int kendryte_cra_init(struct crypto_tfm *tfm) +{ + struct kendryte_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = &crypto_info; + + return 0; +} + +static int kendryte_gcm_aes_encrypt(struct aead_request *req) +{ + return kendryte_gcm_aes_crypt(req, true); +} + +static int kendryte_gcm_aes_decrypt(struct aead_request *req) +{ + return kendryte_gcm_aes_crypt(req, false); +} + +static int kendryte_gcm_aes_init(struct crypto_aead *tfm) +{ + return kendryte_cra_init(&tfm->base); +} + +struct aead_alg kendryte_gcm_aes_alg = { + .setkey = kendryte_gcm_aes_setkey, + .setauthsize = kendryte_gcm_aes_setauthsize, + .encrypt = kendryte_gcm_aes_encrypt, + .decrypt = kendryte_gcm_aes_decrypt, + .init = kendryte_gcm_aes_init, + .ivsize = GCM_AES_IV_SIZE, + .maxauthsize = AES_BLOCK_SIZE, + + .base = { + .cra_name = "gcm(aes)", + .cra_driver_name = "gcm-aes-canaan", + .cra_priority = 400, + .cra_blocksize = 1, + .cra_flags = CRYPTO_ALG_TYPE_AEAD, + .cra_ctxsize = sizeof(struct kendryte_aes_ctx), + .cra_alignmask = 0xf, + .cra_module = THIS_MODULE, + }, +}; + +static int kendryte_crypto_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + int err = -1; + + pr_info("Kendryte crypto driver probe!\n"); + + crypto_info.dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + crypto_info.base = devm_ioremap_resource(dev, res); + if (IS_ERR(crypto_info.base)) + return PTR_ERR(crypto_info.base); + + platform_set_drvdata(pdev, &crypto_info); + + err = crypto_register_aead(&kendryte_gcm_aes_alg); + if (err < 0) + goto gcm_err; + +out: + return err; + +gcm_err: + dev_err(&pdev->dev, "Unable to register cipher algorithm.\n"); + crypto_unregister_aead(&kendryte_gcm_aes_alg); + goto out; +} + +static int kendryte_crypto_remove(struct platform_device *pdev) +{ + crypto_unregister_aead(&kendryte_gcm_aes_alg); + + return 0; +} + +static const struct of_device_id of_kendryte_crypto_ids[] = { + { .compatible = "canaan,k230-crypto" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_kendryte_crypto_ids); + +static struct platform_driver kendryte_crypto_driver = { + .probe = kendryte_crypto_probe, + .remove = kendryte_crypto_remove, + .driver = { + .name = "kendryte-crypto", + .of_match_table = of_kendryte_crypto_ids, + }, +}; +module_platform_driver(kendryte_crypto_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CANAAN K230 Hardware Accelerator Crypto Driver"); diff --git a/drivers/crypto/canaan/kendryte-aes.h b/drivers/crypto/canaan/kendryte-aes.h new file mode 100644 index 0000000000000..4b1c6c0d1595e --- /dev/null +++ b/drivers/crypto/canaan/kendryte-aes.h @@ -0,0 +1,281 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __KENDRYTE_AES_H__ +#define __KENDRYTE_AES_H__ + +/* define single block cipher and mode*/ +#define KENDRYTE_CIPHER_AES 0 +#define KENDRYTE_CIPHER_SM4 1 +#define KENDRYTE_CIPHER_SHASH 2 +#define KENDRYTE_CIPHER_SM3 3 +#define KENDRYTE_CIPHER_RSA 4 +#define KENDRYTE_CIPHER_SM2 5 + +#define KENDRYTE_MODE_CBC 0 +#define KENDRYTE_MODE_ECB 1 +#define KENDRYTE_MODE_CFB 2 +#define KENDRYTE_MODE_OFB 3 +#define KENDRYTE_MODE_CTR 4 +#define KENDRYTE_MODE_CCM 5 +#define KENDRYTE_MODE_GCM 6 +#define KENDRYTE_MODE_SM4 7 +#define KENDRYTE_MODE_SHA256 8 +#define KENDRYTE_MODE_SM3 9 +#define KENDRYTE_MODE_RSA 10 +#define KENDRYTE_MODE_SM2 11 + +/* define the cipher name str */ +#define STR_CBC_AES "cbc(aes)" +#define STR_ECB_AES "ecb(aes)" +#define STR_CFB_AES "cfb(aes)" +#define STR_OFB_AES "ofb(aes)" +#define STR_CTR_AES "ctr(aes)" +#define STR_CCM_AES "ccm(aes)" +#define STR_GCM_AES "gcm(aes)" + +#define AES_BLOCK_SIZE 16 +#define ULLONG_MAX (~0ULL) +#define SW_KEY_MAXLEN 64 +#define DGST_INT_STATE_LEN 64 +#define IV_MAXLEN 16 + +//----------------------CRYPTO REGISTER OFFSET---------------------------------------// +#define CRYPTO_IV_OFFSET 0x30 +#define CRYPTO_SW_KEY_OFFSET 0x40 +#define CRYPTO_DGST_IN_OFFSET 0x80 +#define CRYPTO_DGST_OUT_OFFSET 0xc0 + +//----------------------GCM REGISTER BITS---------------------------------------// +#define GCM_CFG_BC_TYPE_BITS 0 +#define GCM_CFG_GHASH_BITS 2 +#define GCM_CFG_GCTR_BITS 3 +#define GCM_CFG_ENCRYPT_BITS 4 +#define GCM_CFG_REG_IN_BITS 5 +#define GCM_CFG_REG_OUT_BITS 6 +//----------------------GCM REGISTER OFFSET----------------------------------------// +#define GCM_STAT_OFFSET 0x70 +#define GCM_CFG_1_OFFSET 0x78 +#define GCM_CFG_2_OFFSET 0x7c +//----------------------REGISTER BIT MASKS----------------------------------// +#define GCM_STATUS_RESP_MASK 0xfffffffe + +//----------------------DMA REGISTER OFFSET----------------------------------------// +#define DMA_STAT_0_OFFSET 0x10 +#define DMA_STAT_1_OFFSET 0x14 +#define DMA_START_OFFSET 0x20 +#define DMA_CFG_0_OFFSET 0x24 +#define DMA_DSC_CFG_0_OFFSET 0x34 +#define DMA_DSC_CFG_1_OFFSET 0x38 +#define DMA_DSC_CFG_2_OFFSET 0x3c +#define DMA_DSC_CFG_3_OFFSET 0x40 +#define DMA_DSC_CFG_4_OFFSET 0x44 +#define DMA_KEY_CFG_0_OFFSET 0x6c +//----------------------DMA REGISTER BIT----------------------------------------// +#define DMA_KEY_CFG_0_KEY_DST_BITS 4 +#define DMA_KEY_CFG_0_KEY_SIZE_BITS 8 +#define DMA_KEY_CFG_0_KEY_IDX_BITS 24 + +#define DMA_DSC_CFG_4_WRITE_PROT_BITS 0 +#define DMA_DSC_CFG_4_READ_PROT_BITS 8 +#define DMA_DSC_CFG_4_FIX_READ_BITS 16 +#define DMA_DSC_CFG_4_FIX_WRITE_BITS 17 +#define DMA_DSC_CFG_4_NO_CRYP_BITS 23 +#define DMA_DSC_CFG_4_OFFSET_BITS 24 +#define DMA_DSC_CFG_4_DN_PAUSE_BITS 28 +#define DMA_DSC_CFG_4_DN_INTRPT_BITS 29 +#define DMA_DSC_CFG_4_TAIL_BITS 30 +#define DMA_DSC_CFG_4_HEAD_BITS 31 +//----------------------DMA REGISTER BIT MASKS----------------------------------// +#define DMA_STATUS_0_BUSY_MASK 0x00000001 + +//----------------------KWP REGISTER OFFSET----------------------------------// +#define KWP_STATUS_OFFSET 0x10 +#define KWP_START_OFFSET 0x14 +#define KWP_CONFIG_OFFSET 0x18 +#define KWP_KEY_IN_OUT_OFFSET 0x40 +#define KWP_KEY_MAXLEN 80 +#define BUFFER_SIZE 512 +//----------------------KWP REGISTER BIT MASKS----------------------------------// +#define KWP_STATUS_BUSY_MASK 0x00000001 + +//----------------------KA REGISTER OFFSET----------------------------------// +#define KA_SK_FREE_OFFSET 0x10 +#define KA_SK_0_OFFSET 0x20 +//----------------------KA REGISTER BIT MASKS----------------------------------// +#define SK_KEY_VAILD_MASK 0x00000001 +#define SK_KEY_ORIGIN_MASK 0x0000000e +#define SK_KEY_SIZE_MASK 0x00007ff0 +#define SK_KEY_TAG_MASK 0x00ff0000 + +/** + * @brief Status code + */ +enum kendryte_status_t { + SUCCESS, ///< Success. + E_ALIGN, ///< Address alignment mismatch. + E_OVERFLOW, ///< Space overflow. + E_UNDERFLOW, ///< Size too small. + E_INVALID, ///< Invalid argument. + E_BUSY, ///< Resource is occupied. + E_UNAVAIL, ///< Resource is unavailable. + E_FIRMWARE, ///< Firmware error. + E_VERFAIL, ///< Invalid public key or digital signature. + E_ECMPROG, ///< Invalid ECC microprogram. + E_DENY, ///< Access denied. + E_UNSUPPORT, ///< Not support. + E_INFINITY, ///< Point at infinity. + E_ERROR, ///< Unspecific error. +}; + +/** + * @brief Block cipher algorithm. + */ +enum kendryte_cipher_t { + AES, + SM4, + N_CIPHER_T, +}; + +/** + * @brief Key types + */ +enum kendryte_key_type_t { + SWKEY = 0, + OTPKEY = 1, + PUFKEY = 2, + RANDKEY = 3, + SHARESEC = 4, + SSKEY = 5, + PRKEY, +}; + +/** + * @brief Algo types + */ +enum kendryte_algo_type_t { + ALGO_TYPE_HKDF = 0, + ALGO_TYPE_HMAC, + ALGO_TYPE_CMAC, + ALGO_TYPE_KLB = 4, + ALGO_TYPE_SM2ENC = 7, + ALGO_TYPE_SP38A, + ALGO_TYPE_GCM, + ALGO_TYPE_XTS, + ALGO_TYPE_CCM, + ALGO_TYPE_CHACHA, + ALGO_TYPE_CYPT_REG_IO, + ALGO_TYPE_KEY_EXPORT, + ALGO_TYPE_NONE, +}; + +/** + * @brief Key array (KA) slots + */ +enum kendryte_ka_slot_t { + // session key slots + SK128_0, ///< 128-bit session key slot 0 + SK128_1, ///< 128-bit session key slot 1 + SK128_2, ///< 128-bit session key slot 2 + SK128_3, ///< 128-bit session key slot 3 + SK128_4, ///< 128-bit session key slot 4 + SK128_5, ///< 128-bit session key slot 5 + SK128_6, ///< 128-bit session key slot 6 + SK128_7, ///< 128-bit session key slot 7 + SK256_0, ///< 256-bit session key slot 0 + SK256_1, ///< 256-bit session key slot 1 + SK256_2, ///< 256-bit session key slot 2 + SK256_3, ///< 256-bit session key slot 3 + SK512_0, ///< 512-bit session key slot 0 + SK512_1, ///< 512-bit session key slot 1 + // private key slots + PRK_0, ///< private key slot 0 + PRK_1, ///< private key slot 1 + PRK_2, ///< private key slot 2 + /// shared secret slot 0. + SHARESEC_0, ///< shared secret slot 0 + N_KA_SLOT_T, ///< keep in the last one +}; + +/** + * structure for segment() return value + */ +struct segstr { + bool process; + const uint8_t *addr; + uint32_t len; +}; + +struct blsegs { + uint32_t nsegs; + struct segstr seg[3]; +}; + +/** + * enum type for GCM input + */ +enum gcm_stage { + GCM_NONE_S, + GCM_AAD_S, + GCM_TEXT_S, +}; + +/** + * enum type for GCM context protection + */ +enum gcm_op { + GCM_AVAILABLE_OP, + GCM_GHASH_OP, + AES_GCM_OP, + GCM_GMAC_OP, +}; + +enum gcm_input_data_t { + GCM_AAD_I, + GCM_PLAINTEXT_I, +}; + +struct kendryte_crypto_info { + struct device *dev; + struct clk *clk; + struct reset_control *rst; + void __iomem *base; + int irq; + spinlock_t lock; + + // spinlock *crypto_spinlock; +}; + +struct kendryte_aes_ctx { + struct kendryte_crypto_info *dev; + uint32_t mode; + + uint8_t key[32]; + uint64_t keylen; + uint64_t ivlen; + uint64_t aadlen; + uint8_t tag[AES_BLOCK_SIZE]; + uint64_t taglen; + uint64_t pclen; + uint64_t inlen; + uint32_t buflen; + uint32_t minlen; + uint32_t incj0; + bool start; + bool encrypt; + uint8_t j0[AES_BLOCK_SIZE]; + uint8_t ghash[AES_BLOCK_SIZE]; + uint8_t buffer[AES_BLOCK_SIZE]; + enum gcm_op op; + enum gcm_stage stage; + enum kendryte_key_type_t keytype; + enum kendryte_cipher_t cipher; + enum kendryte_ka_slot_t keyslot; +}; + +#endif /* __KENDRYTE_AES_H__ */ diff --git a/drivers/crypto/canaan/kendryte-hash.c b/drivers/crypto/canaan/kendryte-hash.c new file mode 100644 index 0000000000000..64b3ad748b655 --- /dev/null +++ b/drivers/crypto/canaan/kendryte-hash.c @@ -0,0 +1,613 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kendryte-hash.h" + +/***************************************************************************** + * Macros + ****************************************************************************/ +/** + * @brief Convert number of bits to number of bytes + * + * @param[in] bits Number of bits. + * @return Number of bytes. + */ +#define b2B(bits) (((bits) + 7) / 8) +/** + * @brief Convert number of bytes to number of bits + * + * @param[in] len Number of bytes. + * @return Number of bits. + */ +#define B2b(len) (8 * (len)) + +static void *puf_dma_base; +static void *puf_crypto_base; +void *hash_dma_virt_in; +dma_addr_t hash_dma_phys_in; +struct kendryte_sha256_info sha256_info; + +//----------------------BASE FUNCTION ----------------------------------------// +static uint32_t be2le(uint32_t var) +{ + return (((0xff000000 & var) >> 24) | ((0x00ff0000 & var) >> 8) | + ((0x0000ff00 & var) << 8) | ((0x000000ff & var) << 24)); +} + +static void write_data(uint32_t *dst, uint8_t *src, size_t length, bool le) +{ + uint32_t *src32 = (uint32_t *)src; + + length = length / 4; + size_t i; + + for (i = 0; i < length; ++i) { + if (le) + *(dst + i) = be2le(*(src32 + i)); + else + *(dst + i) = *(src32 + i); + } +} + +static void read_data(uint8_t *dst, uint32_t *src, size_t length, bool le) +{ + uint32_t *dst32 = (uint32_t *)dst; + uint32_t word_nums = 0, rest = 0, last_word; + + word_nums = length / 4; + rest = length % 4; + uint32_t i; + + for (i = 0; i < word_nums; i++) { + if (le) + dst32[i] = be2le(src[i]); + else + dst32[i] = src[i]; + } + + if (rest != 0) { + if (le) + last_word = be2le(src[word_nums]); + else + last_word = src[word_nums]; + + memcpy(dst + (word_nums * 4), &last_word, rest); + } +} + +static struct blsegs segment(uint8_t *buf, uint32_t buflen, const uint8_t *in, + uint32_t inlen, uint32_t blocksize, + uint32_t minlen) +{ + struct blsegs ret = { .nsegs = 0 }; + // calculate total number of blocks to be processed + uint32_t nprocblocks = 0; + + if ((buflen + inlen) >= (minlen + blocksize)) + nprocblocks = (buflen + inlen - minlen) / blocksize; + + // no available block for processing, keep input in the internal buffer. + if (nprocblocks == 0) { + ret.seg[ret.nsegs++] = (struct segstr){ false, buf, buflen }; + ret.seg[ret.nsegs++] = (struct segstr){ false, in, inlen }; + return ret; + } + + const uint8_t *start = in; + // some blocks are ready for processing, using bytes in the internal buffer first + if (buflen != 0) { + // if all data in the internal buffer will be processed + if (nprocblocks * blocksize >= buflen) { + // fill buffer if not a complete block + uint32_t proclen = blocksize; + + nprocblocks--; + while (proclen < buflen) { + proclen += blocksize; + nprocblocks--; + } + memcpy(buf + buflen, start, proclen - buflen); + ret.seg[ret.nsegs++] = + (struct segstr){ true, buf, proclen }; + start += (proclen - buflen); + inlen -= (proclen - buflen); + } else { + // some data will be remained in the internal buffer + ret.seg[ret.nsegs++] = + (struct segstr){ true, buf, + nprocblocks * blocksize }; + ret.seg[ret.nsegs++] = (struct segstr){ + false, buf + nprocblocks * blocksize, + buflen - nprocblocks * blocksize + }; + nprocblocks = 0; + } + } + // deal with input data + if (nprocblocks > 0) { + ret.seg[ret.nsegs++] = + (struct segstr){ true, start, nprocblocks * blocksize }; + } + ret.seg[ret.nsegs++] = + (struct segstr){ false, start + nprocblocks * blocksize, + inlen - nprocblocks * blocksize }; + + return ret; +} + +static int get_key_slot_idx(enum kendryte_key_type_t keytype) +{ + switch (keytype) { + case SWKEY: + return 0; + default: + return -1; + } +} + +//---------------------------------CRYTPO FUNCTION----------------------------------------// +static enum kendryte_status_t crypto_write_dgst(uint8_t *dgst, size_t length) +{ + if (length > DGST_INT_STATE_LEN) + return E_INVALID; + + write_data((uint32_t *)(puf_crypto_base + CRYPTO_DGST_IN_OFFSET), dgst, + length, true); + + return SUCCESS; +} + +static void crypto_read_dgest(uint8_t *out, size_t length) +{ + length = length < DGST_INT_STATE_LEN ? length : DGST_INT_STATE_LEN; + read_data(out, (void *)(puf_crypto_base + CRYPTO_DGST_OUT_OFFSET), + length, true); +} + +//----------------------------------------DMA FUNCTION----------------------------------------// +static void dma_write_start(void) +{ + writel(0x1, puf_dma_base + DMA_START_OFFSET); +} + +static bool dma_check_busy_status(uint32_t *status) +{ + uint32_t stat = readl(puf_dma_base + DMA_STAT_0_OFFSET); + bool busy = (stat & DMA_STATUS_0_BUSY_MASK) != 0; + + if (status != NULL) + *status = stat; + + return busy; +} + +static void dma_write_config_0(bool rng_enable, bool sgdma_enable, bool no_cypt) +{ + uint32_t value = 0; + + if (rng_enable) + value |= 0x1; + if (sgdma_enable) + value |= 0x1 << 1; + if (no_cypt) + value |= 0x1 << 2; + + writel(value, puf_dma_base + DMA_CFG_0_OFFSET); +} + +static void dma_write_data_block_config(bool head, bool tail, bool dn_intrpt, + bool dn_pause, uint32_t offset) +{ + uint32_t value = 0; + + if (head) + value |= 0x1 << DMA_DSC_CFG_4_HEAD_BITS; + if (tail) + value |= 0x1 << DMA_DSC_CFG_4_TAIL_BITS; + if (dn_intrpt) + value |= 0x1 << DMA_DSC_CFG_4_DN_INTRPT_BITS; + if (dn_pause) + value |= 0x1 << DMA_DSC_CFG_4_DN_PAUSE_BITS; + value |= offset << DMA_DSC_CFG_4_OFFSET_BITS; + + writel(value, puf_dma_base + DMA_DSC_CFG_4_OFFSET); +} + +static void dma_write_rwcfg(struct kendryte_sha256_ctx *ctx, const uint8_t *out, + const uint8_t *in, uint32_t len) +{ + hash_dma_virt_in = dma_alloc_coherent(ctx->dev->dev, (len + 32), + &hash_dma_phys_in, GFP_KERNEL); + + writel(len, puf_dma_base + DMA_DSC_CFG_2_OFFSET); + writel((uintptr_t)out, puf_dma_base + DMA_DSC_CFG_1_OFFSET); + + if (in == NULL) { + writel((uintptr_t)in, puf_dma_base + DMA_DSC_CFG_0_OFFSET); + } else { + memcpy(hash_dma_virt_in, in, len); + writel(hash_dma_phys_in, puf_dma_base + DMA_DSC_CFG_0_OFFSET); + } + dma_free_coherent(ctx->dev->dev, (len + 32), hash_dma_virt_in, + hash_dma_phys_in); +} + +static void dma_write_key_config_0(enum kendryte_key_type_t keytype, + enum kendryte_algo_type_t algo, + uint32_t size, uint32_t slot_index) +{ + uint32_t value = 0; + + value |= slot_index << DMA_KEY_CFG_0_KEY_IDX_BITS; + value |= size << DMA_KEY_CFG_0_KEY_SIZE_BITS; + value |= algo << DMA_KEY_CFG_0_KEY_DST_BITS; + value |= keytype; + + writel(value, puf_dma_base + DMA_KEY_CFG_0_OFFSET); +} + +static enum kendryte_status_t _ctx_final(struct kendryte_sha256_ctx *hash_ctx, + struct kendryte_dgst_st *md) +{ + if (md == NULL) + return E_INVALID; + + crypto_read_dgest(md->dgst, DGST_INT_STATE_LEN); + md->dlen = 32; + + return SUCCESS; +} + +static enum kendryte_status_t _ctx_update(struct kendryte_sha256_ctx *hash_ctx, + struct kendryte_dgst_st *md, + const uint8_t *msg, uint32_t msglen, + bool last) +{ + uint32_t val32; + + if (last && (md == NULL)) + return E_INVALID; + + if (dma_check_busy_status(NULL)) + return E_BUSY; + + dma_write_config_0(false, false, false); + dma_write_data_block_config(hash_ctx->start ? false : true, last, true, + true, 0); + dma_write_rwcfg(hash_ctx, NULL, msg, msglen); + dma_write_key_config_0(hash_ctx->keytype, ALGO_TYPE_HMAC, + (hash_ctx->keybits < 512) ? hash_ctx->keybits : + 512, + get_key_slot_idx(hash_ctx->keytype)); + + if (hash_ctx->start) + crypto_write_dgst(hash_ctx->state, DGST_INT_STATE_LEN); + + val32 = ((hash_ctx->hash == SHA_256) ? 0x03 : 0x08); + writel(val32, hash_ctx->dev->base + HASH_CONFIG_OFFSET); + writel(hash_ctx->curlen, hash_ctx->dev->base + HASH_PLEN_OFFSET); + + flush_cache_all(); + dma_write_start(); + while (dma_check_busy_status(&val32)) + ; + if (val32 != 0) { + pr_err("DMA status 0: 0x%08x\n", val32); + return E_ERROR; + } + + val32 = readl(hash_ctx->dev->base + HASH_STATUS_OFFSET); + if (val32 != 0) { + pr_err("[ERROR] HMAC status: 0x%08x\n", val32); + return E_ERROR; + } + + if (!last) { + crypto_read_dgest(hash_ctx->state, DGST_INT_STATE_LEN); + hash_ctx->curlen = + readl(hash_ctx->dev->base + HASH_ALEN_OFFSET); + } + + return SUCCESS; +} + +static enum kendryte_status_t +_sha256_final(struct kendryte_sha256_ctx *hash_ctx, struct kendryte_dgst_st *md) +{ + enum kendryte_status_t check = SUCCESS; + + check = _ctx_update(hash_ctx, md, hash_ctx->buff, hash_ctx->buflen, + true); + if (check != SUCCESS) + goto done; + + check = _ctx_final(hash_ctx, md); + +done: + hash_ctx->op = HMAC_AVAILABLE; + return check; +} + +static enum kendryte_status_t +_sha256_update(struct kendryte_sha256_ctx *hash_ctx, const uint8_t *msg, + uint32_t msglen) +{ + enum kendryte_status_t check; + uint32_t i; + // continue if msg is NULL or msglen is zero + if ((msg == NULL) || (msglen == 0)) + return SUCCESS; + + struct blsegs segs = segment(hash_ctx->buff, hash_ctx->buflen, msg, + msglen, hash_ctx->blocklen, + hash_ctx->minlen); + hash_ctx->buflen = 0; + + for (i = 0; i < segs.nsegs; i++) { + if (segs.seg[i].process) { + // process + check = _ctx_update( + hash_ctx, NULL, segs.seg[i].addr, + segs.seg[i].len, false); + if (check != SUCCESS) { + // release hmac context + hash_ctx->op = HMAC_AVAILABLE; + return check; + } + if (hash_ctx->start == false) + hash_ctx->start = true; + } else { + // keep in the internal buffer + if ((segs.seg[i].addr == hash_ctx->buff) && + (hash_ctx->buflen == + 0)) { // skip copy what already in the right place + hash_ctx->buflen += segs.seg[i].len; + } else { + // copy into the buffer + memmove(hash_ctx->buff + hash_ctx->buflen, + segs.seg[i].addr, segs.seg[i].len); + hash_ctx->buflen += segs.seg[i].len; + } + } + } + + return SUCCESS; +} + +static enum kendryte_status_t _sha256_init(struct kendryte_sha256_ctx *hash_ctx) +{ + size_t keyaddr; + uint32_t keybits; + + hash_ctx->blocklen = 64; + // initialize for hash + hash_ctx->buflen = 0; + hash_ctx->keybits = 0; + hash_ctx->minlen = 1; + hash_ctx->keytype = 0; + hash_ctx->curlen = 0; + hash_ctx->op = HMAC_HASH; + hash_ctx->hash = SHA_256; + hash_ctx->start = false; + + keyaddr = 0; + keybits = 0; + memset(hash_ctx->key, 0, HMAC_BLOCK_MAXLEN); + memcpy(hash_ctx->key, (const void *)keyaddr, b2B(keybits)); + + return SUCCESS; +} + +void sha256_free(struct kendryte_sha256_ctx *ctx, uint32_t msglen) +{ + iounmap(puf_dma_base); + iounmap(puf_crypto_base); +} + +static int kendryte_sha256_final(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct kendryte_sha256_ctx *ctx = crypto_ahash_ctx(tfm); + struct kendryte_dgst_st md; + enum kendryte_status_t check; + int ret = 0; + + check = _sha256_final(ctx, &md); + if (check != SUCCESS) + goto done; + + memcpy(req->result, md.dgst, md.dlen); + +done: + if (check != SUCCESS) { + pr_err("Hash-%s Error!\n", __func__); + ret = -1; + } + + sha256_free(ctx, req->nbytes); + + return 0; +} + +static int kendryte_sha256_update(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct kendryte_sha256_ctx *ctx = crypto_ahash_ctx(tfm); + uint8_t *msg; + uint32_t msglen; + enum kendryte_status_t check; + int ret = 0; + + msglen = req->nbytes; + msg = kzalloc(msglen, GFP_KERNEL); + scatterwalk_map_and_copy(msg, req->src, 0, msglen, 0); + + check = _sha256_update(ctx, msg, msglen); + if (check != SUCCESS) + goto done; + +done: + if (check != SUCCESS) { + pr_err("Hash-%s Error!\n", __func__); + ret = -1; + } + + kfree(msg); + return ret; +} + +static int kendryte_sha256_init(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct kendryte_sha256_ctx *ctx = crypto_ahash_ctx(tfm); + enum kendryte_status_t check; + int ret = 0; + + // ioremap + puf_dma_base = ioremap(0x91210000, 0x100); + puf_crypto_base = ioremap(0x91210100, 0x100); + + // hash-256 + ctx->op = HMAC_AVAILABLE; + check = _sha256_init(ctx); + if (check != SUCCESS) + goto done; + +done: + if (check != SUCCESS) { + pr_err("Hash-%s Error!\n", __func__); + ret = -1; + } + + return ret; +} + +static int kendryte_sha256_digest(struct ahash_request *req) +{ + int ret = 0; + + ret = kendryte_sha256_init(req); + ret += kendryte_sha256_update(req); + ret += kendryte_sha256_final(req); + if (ret) { + pr_err("Hash-%s Error!\n", __func__); + return ret; + } + + return 0; +} + +static int kendryte_sha256_import(struct ahash_request *req, const void *in) +{ + return 0; +} + +static int kendryte_sha256_export(struct ahash_request *req, void *out) +{ + return 0; +} + +static int kendryte_sha256_cra_init(struct crypto_tfm *tfm) +{ + struct kendryte_sha256_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = &sha256_info; + return 0; +} + +static struct ahash_alg + kendryte_sha256_alg = { .init = kendryte_sha256_init, + .update = kendryte_sha256_update, + .final = kendryte_sha256_final, + .digest = kendryte_sha256_digest, + .export = kendryte_sha256_export, + .import = kendryte_sha256_import, + .halg.digestsize = SHA256_DIGEST_SIZE, + .halg.statesize = + sizeof(struct kendryte_sha256_ctx), + .halg.base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-kendryte", + .cra_priority = 300, + .cra_flags = (CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_ASYNC), + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof( + struct kendryte_sha256_ctx), + .cra_init = kendryte_sha256_cra_init, + .cra_module = THIS_MODULE, + } }; + +static int kendryte_sha256_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + int err = -1; + + pr_info("Kendryte sha256 driver probe!\n"); + + sha256_info.dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sha256_info.base = devm_ioremap_resource(dev, res); + if (IS_ERR(sha256_info.base)) + return PTR_ERR(sha256_info.base); + + platform_set_drvdata(pdev, &sha256_info); + + err = crypto_register_ahash(&kendryte_sha256_alg); + if (err < 0) + goto hash_err; +out: + return err; + +hash_err: + dev_err(&pdev->dev, "Unable to register hash algorithm.\n"); + crypto_unregister_ahash(&kendryte_sha256_alg); + goto out; +} + +static int kendryte_sha256_remove(struct platform_device *pdev) +{ + crypto_unregister_ahash(&kendryte_sha256_alg); + + return 0; +} + +static const struct of_device_id of_kendryte_sha256_ids[] = { + { .compatible = "canaan,k230-hash" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_kendryte_sha256_ids); + +static struct platform_driver kendryte_sha256_driver = { + .probe = kendryte_sha256_probe, + .remove = kendryte_sha256_remove, + .driver = { + .name = "kendryte-sha256", + .of_match_table = of_kendryte_sha256_ids, + }, +}; +module_platform_driver(kendryte_sha256_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CANAAN K230 Hardware Accelerator SHA256 Driver"); diff --git a/drivers/crypto/canaan/kendryte-hash.h b/drivers/crypto/canaan/kendryte-hash.h new file mode 100644 index 0000000000000..4a4037e637d40 --- /dev/null +++ b/drivers/crypto/canaan/kendryte-hash.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __KENDRYTE_HASH_H__ +#define __KENDRYTE_HASH_H__ + +#define HMAC_SW_KEY_MAXLEN 64 +#define HMAC_BLOCK_MAXLEN 128 +#define DGST_INT_STATE_LEN 64 +#define DLEN_MAX 64 + +//----------------------DMA REGISTER OFFSET----------------------------------------// +#define DMA_STAT_0_OFFSET 0x10 +#define DMA_STAT_1_OFFSET 0x14 +#define DMA_START_OFFSET 0x20 +#define DMA_CFG_0_OFFSET 0x24 +#define DMA_DSC_CFG_0_OFFSET 0x34 +#define DMA_DSC_CFG_1_OFFSET 0x38 +#define DMA_DSC_CFG_2_OFFSET 0x3c +#define DMA_DSC_CFG_3_OFFSET 0x40 +#define DMA_DSC_CFG_4_OFFSET 0x44 +#define DMA_KEY_CFG_0_OFFSET 0x6c +//----------------------DMA REGISTER BIT----------------------------------------// +#define DMA_KEY_CFG_0_KEY_DST_BITS 4 +#define DMA_KEY_CFG_0_KEY_SIZE_BITS 8 +#define DMA_KEY_CFG_0_KEY_IDX_BITS 24 + +#define DMA_DSC_CFG_4_WRITE_PROT_BITS 0 +#define DMA_DSC_CFG_4_READ_PROT_BITS 8 +#define DMA_DSC_CFG_4_FIX_READ_BITS 16 +#define DMA_DSC_CFG_4_FIX_WRITE_BITS 17 +#define DMA_DSC_CFG_4_NO_CRYP_BITS 23 +#define DMA_DSC_CFG_4_OFFSET_BITS 24 +#define DMA_DSC_CFG_4_DN_PAUSE_BITS 28 +#define DMA_DSC_CFG_4_DN_INTRPT_BITS 29 +#define DMA_DSC_CFG_4_TAIL_BITS 30 +#define DMA_DSC_CFG_4_HEAD_BITS 31 +//----------------------DMA REGISTER BIT MASKS----------------------------------// +#define DMA_STATUS_0_BUSY_MASK 0x00000001 + +//----------------------CRYPTO REGISTER OFFSET---------------------------------------// +#define CRYPTO_IV_OFFSET 0x30 +#define CRYPTO_SW_KEY_OFFSET 0x40 +#define CRYPTO_DGST_IN_OFFSET 0x80 +#define CRYPTO_DGST_OUT_OFFSET 0xc0 + +//----------------------HASH REGISTER OFFSET----------------------------------------// +#define HASH_STATUS_OFFSET 0x10 +#define HASH_CONFIG_OFFSET 0x18 +#define HASH_PLEN_OFFSET 0x20 +#define HASH_ALEN_OFFSET 0x30 +//----------------------HASH REGISTER BIT MASKS----------------------------------// +#define HMAC_HASH_INTRPT_INTRPT_ST_MASK 0x00000001 +#define HMAC_HASH_INTRPT_INTRPT_EN_MASK 0x00010000 +#define HMAC_HASH_FEATURE_HMAC_MASK 0x00000001 +#define HMAC_HASH_FEATURE_SHA2_MASK 0x00000002 +#define HMAC_HASH_STATUS_BUSY_MASK 0x00000001 +#define HMAC_HASH_STATUS_RESP_MASK 0xfffffffe +#define HMAC_HASH_CFG_VARIANT_MASK 0x00000007 +#define HMAC_HASH_CFG_FUNC_MASK 0x00000100 +#define HMAC_HASH_PLEN_VALUE_MASK 0xffffffff +#define HMAC_HASH_ALEN_VALUE_MASK 0xffffffff + +/** + * @brief Status code + */ +enum kendryte_status_t { + SUCCESS, ///< Success. + E_ALIGN, ///< Address alignment mismatch. + E_OVERFLOW, ///< Space overflow. + E_UNDERFLOW, ///< Size too small. + E_INVALID, ///< Invalid argument. + E_BUSY, ///< Resource is occupied. + E_UNAVAIL, ///< Resource is unavailable. + E_FIRMWARE, ///< Firmware error. + E_VERFAIL, ///< Invalid public key or digital signature. + E_ECMPROG, ///< Invalid ECC microprogram. + E_DENY, ///< Access denied. + E_UNSUPPORT, ///< Not support. + E_INFINITY, ///< Point at infinity. + E_ERROR, ///< Unspecific error. +}; + +/** + * @brief Key types + */ +enum kendryte_key_type_t { + SWKEY = 0, + OTPKEY = 1, + PUFKEY = 2, + RANDKEY = 3, + SHARESEC = 4, + SSKEY = 5, + PRKEY, +}; + +/** + * @brief Algo types + */ +enum kendryte_algo_type_t { + ALGO_TYPE_HKDF = 0, + ALGO_TYPE_HMAC, + ALGO_TYPE_CMAC, + ALGO_TYPE_KLB = 4, + ALGO_TYPE_SM2ENC = 7, + ALGO_TYPE_SP38A, + ALGO_TYPE_GCM, + ALGO_TYPE_XTS, + ALGO_TYPE_CCM, + ALGO_TYPE_CHACHA, + ALGO_TYPE_CYPT_REG_IO, + ALGO_TYPE_KEY_EXPORT, + ALGO_TYPE_NONE, +}; + +/** + * structure for segment() return value + */ +struct segstr { + bool process; + const uint8_t *addr; + uint32_t len; +}; + +struct blsegs { + uint32_t nsegs; + struct segstr seg[3]; +}; + +enum kendryte_hash_t { + SHA_224, + SHA_256, + SHA_384, + SHA_512, + SHA_512_224, + SHA_512_256, + SM3, + N_HASH_T, +}; + +enum hmac_op { + HMAC_AVAILABLE, + HMAC_HASH, + HMAC_HMAC, +}; + +struct kendryte_sha256_info { + struct device *dev; + struct clk *clk; + struct reset_control *rst; + void __iomem *base; + int irq; +}; + +struct kendryte_dgst_st { + uint32_t dlen; + uint8_t dgst[DLEN_MAX]; +}; + +struct kendryte_sha256_ctx { + struct kendryte_sha256_info *dev; + + uint8_t buff[HMAC_BLOCK_MAXLEN]; + uint8_t key[HMAC_BLOCK_MAXLEN]; + uint8_t state[DGST_INT_STATE_LEN]; + uint32_t buflen; + uint32_t keybits; + uint32_t minlen; + uint32_t curlen; + uint32_t keyslot; + uint32_t blocklen; + enum kendryte_key_type_t keytype; + enum hmac_op op; + enum kendryte_hash_t hash; + bool start; +}; + +#endif /* __KENDRYTE_HASH_H__ */ diff --git a/drivers/crypto/canaan/kendryte-rsa.c b/drivers/crypto/canaan/kendryte-rsa.c new file mode 100644 index 0000000000000..59b20a98f9da8 --- /dev/null +++ b/drivers/crypto/canaan/kendryte-rsa.c @@ -0,0 +1,839 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kendryte-rsa.h" + +struct kendryte_rsa_dev rsa_device; +static uint8_t pkc_buffer[PKC_BUFFER_SIZE]; + +void reverse(uint8_t *dst, const uint8_t *src, size_t len) +{ + size_t i, j; + + for (i = 0, j = len - 1; i < len; i++, j--) + dst[i] = src[j]; +} + +static int16_t bn_cmp(const uint8_t *a, const uint8_t *b, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) { + if (a[i] == b[i]) + continue; + return ((int16_t)(a[i]) - (int16_t)(b[i])); + } + return 0; +} + +static void *rsa_memcpy(void *dest, const void *src, int count) +{ + uint32_t *tmp = (uint32_t *)dest, *s = (uint32_t *)src; + int c = count / 4; + + while (c--) + *tmp++ = *s++; + + return dest; +} + +static void read_ecp_operand(struct kendryte_rsa_ctx *ctx, uint32_t pos, + uint8_t *res, uint32_t elen) +{ + uint32_t wlen = ((elen + 3) / 4) * 4; + uint32_t rlen = wlen; + + rsa_memcpy(pkc_buffer, + (uint8_t *)(ctx->dev->base + ECP_DATA_OFFSET) + wlen * pos, + rlen); + reverse(res, pkc_buffer, elen); +} + +static void write_ecp_operand(struct kendryte_rsa_ctx *ctx, uint32_t pos, + const uint8_t *op, uint32_t elen) +{ + uint32_t wlen = ((elen + 3) / 4) * 4; + + memset(pkc_buffer, 0, wlen); + if (op != NULL) + reverse(pkc_buffer, op, elen); + rsa_memcpy((uint8_t *)(ctx->dev->base + ECP_DATA_OFFSET) + wlen * pos, + pkc_buffer, wlen); +} + +static enum kendryte_status_t +rsa_get_field_elen(enum kendryte_ecp_field_t *field, uint32_t *elen, + enum kendryte_rsa_type_t rsatype) +{ + enum kendryte_ecp_field_t rf; + uint32_t rl; + + switch (rsatype) { + case RSA1024: + rf = P1024; + rl = 128; + break; + case RSA2048: + rf = P2048; + rl = 256; + break; + case RSA3072: + rf = P3072; + rl = 384; + break; + case RSA4096: + rf = P4096; + rl = 512; + break; + default: + return E_INVALID; + } + + if (field != NULL) + *field = rf; + if (elen != NULL) + *elen = rl; + return SUCCESS; +} + +//----------------------RSA MICRO PROGRAMS FUNCTION ----------------------------------------// +/** + * @brief RSA micro programs for ECF39303-00000000 + */ +static struct kendryte_rsa_mprog_func_st prog_ECF39303_RSA1024 = { + .prk = "\x40\x00\x00\x8a\x60\x40\x04\x0a\x80\x80\x08\x8a\xa0\xc0\x0c\x0a" + "\x00\x04\x11\x26\x40\x40\x15\x26\x00\x0c\x80\x43\x66\x10\x10\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x80\x80\x08\x8a\x00\x0b\x80\xc3\x66\x10\x10\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF39303_RSA2048 = { + .prk = "\x40\x00\x00\x8a\x80\x40\x08\x8a\xc0\x80\x10\x0a\x00\xc1\x18\x8a" + "\x00\x08\x21\x26\x40\x40\x29\x26\x00\x0c\x80\x43\xc6\x10\x18\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\xc0\x80\x10\x0a\x00\x0b\x80\xc3\xc6\x10\x18\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF39303_RSA3072 = { + .prk = "\x40\x00\x00\x8a\xa0\x40\x0c\x8a\x00\x81\x18\x0a\x60\xc1\x24\x8a" + "\x00\x0c\x31\x26\x40\x40\x3d\x26\x00\x0c\x80\x43\x26\x11\x20\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x00\x81\x18\x0a\x00\x0b\x80\xc3\x26\x11\x20\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF39303_RSA4096 = { + .prk = "\x40\x00\x00\x8a\xc0\x40\x10\x0a\x40\x81\x20\x0a\xc0\xc1\x30\x8a" + "\x00\x10\x41\x26\x40\x40\x51\x26\x00\x0c\x80\x43\x86\x11\x28\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x40\x81\x20\x0a\x00\x0b\x80\xc3\x86\x11\x28\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", +}; + +/** + * @brief RSA micro programs for ECF09303-00000000 + */ +static struct kendryte_rsa_mprog_func_st prog_ECF09303_RSA1024 = { + .prk = "\x88\x00\x00\x8e\x40\x00\x00\x8a\x80\x80\x08\x8a\xa0\x40\x04\x0a" + "\x00\x04\x11\x26\x40\x40\x15\x26\x00\x0c\x80\x43\x66\x10\x10\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x80\x80\x08\x8a\x00\x0b\x80\xc3\x66\x10\x10\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF09303_RSA2048 = { + .prk = "\x08\x01\x00\x8e\x40\x00\x00\x8a\xc0\x80\x10\x0a\x00\x41\x08\x8a" + "\x00\x08\x21\x26\x40\x40\x29\x26\x00\x0c\x80\x43\xc6\x10\x18\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\xc0\x80\x10\x0a\x00\x0b\x80\xc3\xc6\x10\x18\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF09303_RSA3072 = { + .prk = "\x88\x01\x00\x0e\x40\x00\x00\x8a\x00\x81\x18\x0a\x60\x41\x0c\x0a" + "\x00\x0c\x31\x26\x40\x40\x3d\x26\x00\x0c\x80\x43\x26\x11\x20\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x00\x81\x18\x0a\x00\x0b\x80\xc3\x26\x11\x20\x88" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static struct kendryte_rsa_mprog_func_st prog_ECF09303_RSA4096 = { + .prk = "\x08\x02\x00\x8e\x40\x00\x00\x8a\x40\x81\x20\x0a\xc0\x41\x10\x8a" + "\x00\x10\x41\x26\x40\x40\x51\x26\x00\x0c\x80\x43\x86\x11\x28\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .puk = "\x40\x00\x00\x8a\x40\x81\x20\x0a\x00\x0b\x80\xc3\x86\x11\x28\x08" + "\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +/** + * @brief CMAC of RSA micro programs for ECF39303-00000000 + */ +static struct kendryte_rsa_mprog_cmac_st sum_ECF39303_00000000_RSA1024 = { + .prk = "\xc8\x41\x5c\x25\xc8\xcf\x59\xa2\x44\x36\xa1\x0d\xd9\x19\x57\xbe", + .puk = "\x8a\x76\xb9\x4f\x91\xf0\x6b\x5f\x38\x8f\x95\xa7\xd9\x1c\xfb\xfd", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF39303_00000000_RSA2048 = { + .prk = "\xde\x95\xd0\x35\x2e\x47\x2e\x51\xce\x44\x80\x2a\x61\xbf\x9e\xf2", + .puk = "\x81\xac\xcd\x33\x4e\x43\x17\x68\x5d\xad\x83\x42\x78\x99\x49\x27", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF39303_00000000_RSA3072 = { + .prk = "\xfe\x00\x41\x8c\xa3\xd3\x71\xe1\x0a\x74\x48\xcf\xd4\x85\x1c\xdf", + .puk = "\x8d\x0b\x92\x7d\xa0\x90\x5a\xaf\xc2\x73\x1e\x54\x25\x57\x09\x75", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF39303_00000000_RSA4096 = { + .prk = "\x07\x68\xfa\xa9\x5e\xba\xff\xe3\xba\x8b\xa8\x8a\xaf\x47\x6b\x12", + .puk = "\x96\x52\x20\xd0\x66\xc7\x1a\x6b\x4f\xa5\xf3\x04\x7a\x20\x87\x52", +}; + +/** + * @brief CMAC of RSA micro programs for ECF09303-00000000 + */ +static struct kendryte_rsa_mprog_cmac_st sum_ECF09303_00000000_RSA1024 = { + .prk = "\x81\x8e\x08\xa7\xc1\xb2\xfa\xe7\x36\x69\x2e\x5a\xaa\x08\x8c\xeb", + .puk = "\x4f\x59\x8f\xa8\x7f\x80\x39\x73\xd2\xb3\xec\x0c\x1d\x95\x5b\x85", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF09303_00000000_RSA2048 = { + .prk = "\x53\x12\x35\x6b\x74\xf8\x6a\xb9\xc5\x48\x4c\x5e\x6b\xbb\x3e\xa3", + .puk = "\xe1\x4c\x60\xc2\x8c\x5b\x22\xe4\x58\x7c\x17\x07\x9a\x11\x20\x8d", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF09303_00000000_RSA3072 = { + .prk = "\x0f\xd6\xa9\xd2\xe7\x3a\x71\x6e\xf4\x5e\x8d\x86\x24\xa1\xff\xbd", + .puk = "\x13\xc4\x8d\xb1\x66\x04\xb3\xa0\x9e\xcb\x73\x63\xdf\xef\xe6\x3e", +}; + +static struct kendryte_rsa_mprog_cmac_st sum_ECF09303_00000000_RSA4096 = { + .prk = "\x72\x41\x3e\x33\xba\x9b\x84\x8a\x43\x12\x3c\xb0\x96\x4b\xca\xbb", + .puk = "\x8a\x00\xac\x58\xc0\x04\x40\xc9\x1d\x81\x75\x3f\x14\x83\xec\x53", +}; + +/** + * @brief group of CMAC of RSA micro programs for ECF39303 + */ +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF39303_RSA1024[] = { + &sum_ECF39303_00000000_RSA1024, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF39303_RSA2048[] = { + &sum_ECF39303_00000000_RSA2048, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF39303_RSA3072[] = { + &sum_ECF39303_00000000_RSA3072, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF39303_RSA4096[] = { + &sum_ECF39303_00000000_RSA4096, +}; + +/** + * @brief group of CMAC of RSA micro programs for ECF09303 + */ +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF09303_RSA1024[] = { + &sum_ECF09303_00000000_RSA1024, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF09303_RSA2048[] = { + &sum_ECF09303_00000000_RSA2048, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF09303_RSA3072[] = { + &sum_ECF09303_00000000_RSA3072, +}; + +static struct kendryte_rsa_mprog_cmac_st *gsum_ECF09303_RSA4096[] = { + &sum_ECF09303_00000000_RSA4096, +}; + +struct kendryte_rsa_mprog_st rsa_ECF39303[] = { + { + .cmac = gsum_ECF39303_RSA1024, + .func = &prog_ECF39303_RSA1024, + }, + { + .cmac = gsum_ECF39303_RSA2048, + .func = &prog_ECF39303_RSA2048, + }, + { + .cmac = gsum_ECF39303_RSA3072, + .func = &prog_ECF39303_RSA3072, + }, + { + .cmac = gsum_ECF39303_RSA4096, + .func = &prog_ECF39303_RSA4096, + }, +}; + +struct kendryte_rsa_mprog_st rsa_ECF09303[] = { + { + .cmac = gsum_ECF09303_RSA1024, + .func = &prog_ECF09303_RSA1024, + }, + { + .cmac = gsum_ECF09303_RSA2048, + .func = &prog_ECF09303_RSA2048, + }, + { + .cmac = gsum_ECF09303_RSA3072, + .func = &prog_ECF09303_RSA3072, + }, + { + .cmac = gsum_ECF09303_RSA4096, + .func = &prog_ECF09303_RSA4096, + }, +}; + +struct kendryte_rsa_mprog_st *rsa_mprog[] = { + rsa_ECF39303, + rsa_ECF09303, +}; + +//----------------------RSA FUNCTION ----------------------------------------// +/** + * @brief Starting ECP and wait until done + * + * @return ECCA status register value + */ +static uint32_t kendryte_ecc_start(struct kendryte_rsa_ctx *ctx) +{ + uint32_t ret; + + writel(0x1, ctx->dev->base + ECP_CTRL_OFFSET); + do { + ret = readl(ctx->dev->base + ECP_STATUS_OFFSET); + } while ((ret & ECP_STATUS_BUSY_MASK) != 0); + + return ret; +} + +static int kendryte_rsa_sign(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct kendryte_rsa_ctx *ctx = crypto_skcipher_ctx(tfm); + uint32_t elen = 0, val32 = 0; + enum kendryte_ecp_field_t field; + enum kendryte_status_t check = SUCCESS; + void *buf_src, *buf_dst; + const void *n, *priv, *msg; + uint32_t puk; + enum kendryte_rsa_type_t rsatype; + enum kendryte_ecp_version_t ecp_version = ECP_ECF39303; + enum kendryte_mp_version_t mp_version = MP_00000000; + uint8_t out[PKC_BUFFER_SIZE]; + int ret = 0; + + check = rsa_get_field_elen(&field, &elen, ctx->rsatype); + if (check != SUCCESS) + goto rsa_err; + + buf_src = kzalloc(elen, GFP_KERNEL); + buf_dst = kzalloc(elen, GFP_KERNEL); + if ((buf_src == NULL) || (buf_dst == NULL)) { + pr_err("Could not kzalloc buffer.\n"); + ret = -1; + goto done; + } + scatterwalk_map_and_copy(buf_src, req->src, 0, elen, 0); // message + memset(out, 0x0, PKC_BUFFER_SIZE); + msg = buf_src; + n = ctx->n; + puk = ctx->e; + priv = ctx->d; + rsatype = ctx->rsatype; + + if ((n == NULL) || (puk == 0) || (priv == NULL) || (msg == NULL)) { + check = E_INVALID; + goto rsa_err; + } + + if (bn_cmp(msg, n, elen) >= 0) { + check = E_INVALID; + goto rsa_err; + } + + val32 = field << ECP_ECP_EC_FIELD_BITS; + writel(val32, ctx->dev->base + ECP_EC_OFFSET); + writel(puk, ctx->dev->base + ECP_E_SHORT_OFFSET); + write_ecp_operand(ctx, 0, n, elen); + write_ecp_operand(ctx, 1, NULL, elen); + write_ecp_operand(ctx, 2, msg, elen); + write_ecp_operand(ctx, 3, priv, elen); + + struct kendryte_rsa_mprog_st *prog = &(rsa_mprog[ecp_version][rsatype]); + struct kendryte_rsa_mprog_cmac_st *cmac = prog->cmac[mp_version]; + + rsa_memcpy((void *)(ctx->dev->base + ECP_MAC_OFFSET), cmac->prk, + ECP_MPMAC_SIZE); + rsa_memcpy((void *)(ctx->dev->base + ECP_PROGRAM_OFFSET), + prog->func->prk, ECP_MPROG_SIZE); + + val32 = kendryte_ecc_start(ctx); + + if (val32 & ECP_STATUS_MPROG_MASK) { + check = E_ECMPROG; + goto rsa_err; + } + + if (val32) { + check = E_VERFAIL; + goto rsa_err; + } + + read_ecp_operand(ctx, 2, out, elen); + memcpy(buf_dst, out, elen); + scatterwalk_map_and_copy(buf_dst, req->dst, 0, elen, 1); + + return 0; + +rsa_err: + if (check != SUCCESS) { + pr_err("Kendryte RSA sign error-%d!\n", check); + return -1; + } + +done: + kfree(buf_src); + kfree(buf_dst); + return ret; +} + +static int kendryte_rsa_verify(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct kendryte_rsa_ctx *ctx = crypto_skcipher_ctx(tfm); + uint32_t elen = 0, val32 = 0; + enum kendryte_ecp_field_t field; + enum kendryte_status_t check = SUCCESS; + void *buf_src, *buf_dst; + const void *n, *sig; + uint32_t puk; + enum kendryte_rsa_type_t rsatype; + enum kendryte_ecp_version_t ecp_version = ECP_ECF39303; + enum kendryte_mp_version_t mp_version = MP_00000000; + uint8_t msg[PKC_BUFFER_SIZE]; + int ret = 0; + + check = rsa_get_field_elen(&field, &elen, ctx->rsatype); + if (check != SUCCESS) + goto rsa_err; + + buf_src = kzalloc(elen, GFP_KERNEL); + buf_dst = kzalloc(elen, GFP_KERNEL); + if ((buf_src == NULL) || (buf_dst == NULL)) { + pr_err("Could not kzalloc buffer.\n"); + ret = -1; + goto done; + } + scatterwalk_map_and_copy(buf_src, req->src, 0, elen, 0); // signature + memset(msg, 0x0, PKC_BUFFER_SIZE); + sig = buf_src; + n = ctx->n; + puk = ctx->e; + rsatype = ctx->rsatype; + + if (sig == NULL || n == NULL || puk == 0) { + check = E_INVALID; + goto rsa_err; + } + + if (bn_cmp(sig, n, elen) >= 0) { + check = E_INVALID; + goto rsa_err; + } + + val32 = field << ECP_ECP_EC_FIELD_BITS; + writel(val32, ctx->dev->base + ECP_EC_OFFSET); + writel(puk, ctx->dev->base + ECP_E_SHORT_OFFSET); + write_ecp_operand(ctx, 0, n, elen); + write_ecp_operand(ctx, 2, sig, elen); + + struct kendryte_rsa_mprog_st *prog = &(rsa_mprog[ecp_version][rsatype]); + struct kendryte_rsa_mprog_cmac_st *cmac = prog->cmac[mp_version]; + + rsa_memcpy((void *)(ctx->dev->base + ECP_MAC_OFFSET), cmac->puk, + ECP_MPMAC_SIZE); + rsa_memcpy((void *)(ctx->dev->base + ECP_PROGRAM_OFFSET), + prog->func->puk, ECP_MPROG_SIZE); + + val32 = kendryte_ecc_start(ctx); + + if (val32 & ECP_STATUS_MPROG_MASK) { + check = E_ECMPROG; + goto rsa_err; + } + + if (val32) { + check = E_VERFAIL; + goto rsa_err; + } + + read_ecp_operand(ctx, 2, msg, elen); + memcpy(buf_dst, msg, elen); + scatterwalk_map_and_copy(buf_dst, req->dst, 0, elen, 1); + + return 0; + +rsa_err: + if (check != SUCCESS) { + pr_err("Kendryte RSA verify error-%d!\n", check); + return -1; + } +done: + kfree(buf_src); + kfree(buf_dst); + return ret; +} + +static int kendryte_rsa_setkey(struct crypto_skcipher *tfm, const uint8_t *key, + unsigned int keylen) +{ + struct kendryte_rsa_ctx *ctx = crypto_skcipher_ctx(tfm); + int len = 0; + + ctx->key_sz = keylen; + memcpy(ctx->key, key, keylen); + if (keylen == (128 * 2 + 4)) { + len = 128; + ctx->rsatype = RSA1024; + } else if (keylen == (256 * 2 + 4)) { + len = 256; + ctx->rsatype = RSA2048; + } else if (keylen == (384 * 2 + 4)) { + len = 384; + ctx->rsatype = RSA3072; + } else if (keylen == (512 * 2 + 4)) { + len = 512; + ctx->rsatype = RSA4096; + } else { + len = -1; + ctx->rsatype = N_RSA_TYPE_T; + return -1; + } + + memcpy(&ctx->n, ctx->key, len); + memcpy(&ctx->d, (ctx->key + len), len); + memcpy(&ctx->e, (ctx->key + len * 2), 4); + + return 0; +} + +static int kendryte_cra_init(struct crypto_tfm *tfm) +{ + struct kendryte_rsa_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = &rsa_device; + return 0; +} + +static int kendryte_rsa_init(struct crypto_skcipher *tfm) +{ + return kendryte_cra_init(&tfm->base); +} + +static struct skcipher_alg + kendryte_rsa_alg = { .encrypt = kendryte_rsa_verify, + .decrypt = kendryte_rsa_sign, + .ivsize = 1, + .setkey = kendryte_rsa_setkey, + .min_keysize = 0, + .max_keysize = 2048, + .init = kendryte_rsa_init, + .base = { + .cra_name = "k230-rsa", + .cra_driver_name = "kendryte-rsa", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_ASYNC, + .cra_blocksize = 64, + .cra_ctxsize = + sizeof(struct kendryte_rsa_ctx), + .cra_module = THIS_MODULE, + } }; + +static int kendryte_rsa_remove(struct platform_device *pdev) +{ + crypto_unregister_skcipher(&kendryte_rsa_alg); + return 0; +} + +static int kendryte_rsa_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + int err = -1; + + rsa_device.dev = dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rsa_device.base = devm_ioremap_resource(dev, res); + if (IS_ERR(rsa_device.base)) + return PTR_ERR(rsa_device.base); + + platform_set_drvdata(pdev, &rsa_device); + + err = crypto_register_skcipher(&kendryte_rsa_alg); + if (err < 0) + goto rsa_err; + + pr_info("Kendryte RSA driver probe!\n"); + +out: + return err; + +rsa_err: + dev_err(&pdev->dev, "Unable to register RSA algorithm!\n"); + crypto_unregister_skcipher(&kendryte_rsa_alg); + goto out; +} + +static const struct of_device_id of_kendryte_rsa_ids[] = { + { .compatible = "canaan,k230-rsa" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_kendryte_rsa_ids); + +static struct platform_driver + kendryte_rsa_driver = { .probe = kendryte_rsa_probe, + .remove = kendryte_rsa_remove, + .driver = { + .name = "kendryte-rsa", + .of_match_table = of_kendryte_rsa_ids, + } }; +module_platform_driver(kendryte_rsa_driver); diff --git a/drivers/crypto/canaan/kendryte-rsa.h b/drivers/crypto/canaan/kendryte-rsa.h new file mode 100644 index 0000000000000..134fd2dd61d0f --- /dev/null +++ b/drivers/crypto/canaan/kendryte-rsa.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __KENDRYTE_RSA_T__ +#define __KENDRYTE_RSA_T__ + +#define PKC_BUFFER_SIZE 512 +#define ECP_MPMAC_SIZE 16 +#define ECP_MPROG_SIZE 256 + +//----------------------RSA REGISTER OFFSET---------------------------------------// +#define ECP_CTRL_OFFSET 0x8 +#define ECP_STATUS_OFFSET 0xc +#define ECP_EC_OFFSET 0x100 +#define ECP_E_SHORT_OFFSET 0x110 +#define ECP_MAC_OFFSET 0x1f0 +#define ECP_PROGRAM_OFFSET 0x200 +#define ECP_DATA_OFFSET 0x300 + +//----------------------RSA REGISTER BITS---------------------------------------// +#define ECP_ECP_EC_FIELD_BITS 8 +//----------------------RSA REGISTER BIT MASKS----------------------------------// +#define ECP_STATUS_BUSY_MASK 0x00000001 +#define ECP_STATUS_MPROG_MASK 0x00000002 + +/** + * @brief Status code + */ +enum kendryte_status_t { + SUCCESS, ///< Success. + E_ALIGN, ///< Address alignment mismatch. + E_OVERFLOW, ///< Space overflow. + E_UNDERFLOW, ///< Size too small. + E_INVALID, ///< Invalid argument. + E_BUSY, ///< Resource is occupied. + E_UNAVAIL, ///< Resource is unavailable. + E_FIRMWARE, ///< Firmware error. + E_VERFAIL, ///< Invalid public key or digital signature. + E_ECMPROG, ///< Invalid ECC microprogram. + E_DENY, ///< Access denied. + E_UNSUPPORT, ///< Not support. + E_INFINITY, ///< Point at infinity. + E_ERROR, ///< Unspecific error. +}; + +/** + * @brief CMAC of RSA micro programs + */ +struct kendryte_rsa_mprog_cmac_st { + const void *prk; + const void *puk; +}; + +/** + * @brief Functions of RSA micro programs + */ +struct kendryte_rsa_mprog_func_st { + const void *prk; + const void *puk; +}; + +/** + * @brief RSA micro programs + */ +struct kendryte_rsa_mprog_st { + struct kendryte_rsa_mprog_cmac_st **cmac; + struct kendryte_rsa_mprog_func_st *func; +}; + +enum kendryte_ecp_field_t { + P1024 = 0x85, + P2048, + P3072, + P4096, + N_ECP_FIELD_T, +}; + +enum kendryte_rsa_type_t { + RSA1024, ///< RSA-1024 + RSA2048, ///< RSA-2048 + RSA3072, ///< RSA-3072 + RSA4096, ///< RSA-4096 + N_RSA_TYPE_T, // keep in the last one +}; + +enum kendryte_ecp_version_t { + ECP_UNSUPPORTED = -1, + ECP_ECF39303, + ECP_ECF09303, +}; + +enum kendryte_mp_version_t { + MP_UNSUPPORTED = -1, + MP_00000000, + MP_3EE2DE76, +}; + +struct kendryte_rsa_dev { + void __iomem *base; + struct device *dev; + struct clk *clk; + struct reset_control *rst; +}; + +struct kendryte_rsa_ctx { + struct kendryte_rsa_dev *dev; + + uint8_t n[512]; + uint32_t e; + uint8_t d[512]; + uint8_t key[2048]; + uint32_t key_sz; + + enum kendryte_rsa_type_t rsatype; +}; + +#endif /* __KENDRYTE_RSA_T__ */ diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 5bc9c4874fe3b..9724727fe554d 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -417,4 +417,14 @@ config NVMEM_QORIQ_EFUSE This driver can also be built as a module. If so, the module will be called nvmem_qoriq_efuse. +config NVMEM_KENDRYTE_K230_OTP + tristate "Kendryte k230 OTP support" + default ARCH_CANAAN + help + This is a OTP driver to kendryte k230 SOC. + + This driver can also be built as a module. + If so, the module will be called + nvmem_kendryte_otp. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 423baf089515c..7f39571880cd6 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -81,3 +81,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o obj-$(CONFIG_NVMEM_QORIQ_EFUSE) += nvmem-qoriq-efuse.o nvmem-qoriq-efuse-y := qoriq-efuse.o +obj-$(CONFIG_NVMEM_KENDRYTE_K230_OTP) += nvmem_kendryte_k230_otp.o +nvmem_kendryte_k230_otp-y := kendryte_k230_otp.o diff --git a/drivers/nvmem/kendryte_k230_otp.c b/drivers/nvmem/kendryte_k230_otp.c new file mode 100644 index 0000000000000..ac9365b339ff8 --- /dev/null +++ b/drivers/nvmem/kendryte_k230_otp.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Kendryte K230 OTP Support driver + * + * Copyright (C) 2024, Canaan Bright Sight Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OTP_BYPASS_ADDR_P 0x91102040 +#define OTP_REG_OFFSET 0x0 +#define OTP_USER_START_OFFSET 0x0 + +enum OTP_STATUS_E { + OTP_BYPASS_STATUS = 0, + OTP_MAX_STATUS = 1, +}; + +struct otp_priv { + struct device *dev; + void __iomem *base; + struct nvmem_config *config; +}; + +static uint32_t be2le(uint32_t var) +{ + return (((0xff000000 & var) >> 24) | ((0x00ff0000 & var) >> 8) | + ((0x0000ff00 & var) << 8) | ((0x000000ff & var) << 24)); +} + +/** + * @brief After the OTP is powered on, the driver can read the sysctl register SOC_BOOT_CTL + * to determine whether the OTP has been bypassed. + * + * @return true + * @return false + */ +static bool sysctl_boot_get_otp_bypass(void) +{ + void __iomem *OTP_BYPASS_ADDR_V; + + OTP_BYPASS_ADDR_V = ioremap(OTP_BYPASS_ADDR_P, 4); + if (readl(OTP_BYPASS_ADDR_V) & 0x10) + return true; + else + return false; +} + +static bool otp_get_status(enum OTP_STATUS_E eStatus) +{ + if (eStatus == OTP_BYPASS_STATUS) + return sysctl_boot_get_otp_bypass(); + else + return false; +} + +/** + * @brief OTP read operation, can only read specific areas, + * including production information, reserved user space + * + * @param context + * @param offset + * @param val + * @param bytes + * @return int + */ +static int k230_otp_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct otp_priv *priv = context; + uint32_t *outbuf = (uint32_t *)val; + uint32_t *out32; + uint32_t WORD_SIZE = priv->config->word_size; + uint32_t wlen = bytes / WORD_SIZE; + uint32_t word; + uint32_t i = 0; + + if (true == otp_get_status(OTP_BYPASS_STATUS)) + return -1; + + if (wlen > 0) { + memcpy(outbuf, (void *)(priv->base + OTP_REG_OFFSET + offset), + wlen * WORD_SIZE); + + out32 = (uint32_t *)outbuf; + for (i = 0; i < wlen; ++i) + *(out32 + i) = be2le(*(out32 + i)); + } + + if (bytes % WORD_SIZE != 0) { + outbuf += wlen * WORD_SIZE; + word = readl(priv->base + OTP_REG_OFFSET + offset + + wlen * WORD_SIZE); + word = be2le(word); + memcpy(outbuf, &word, bytes % WORD_SIZE); + } + + return 0; +} + +static struct nvmem_config kendryte_otp_nvmem_config = { + .name = "kendryte_otp", + .owner = THIS_MODULE, + .read_only = true, + .word_size = 4, + .reg_read = k230_otp_read, + // .reg_write = k230_otp_write, + .size = 0x300, +}; + +static const struct of_device_id kendryte_otp_dt_ids[] = { + { .compatible = "canaan,k230-otp" }, + {}, +}; +MODULE_DEVICE_TABLE(of, kendryte_otp_dt_ids); + +static int kendryte_otp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct otp_priv *priv; + struct nvmem_device *nvmem; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + /* Get OTP base address register from DTS. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + kendryte_otp_nvmem_config.dev = dev; + kendryte_otp_nvmem_config.priv = priv; + priv->config = &kendryte_otp_nvmem_config; + nvmem = devm_nvmem_register(dev, &kendryte_otp_nvmem_config); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static struct platform_driver kendryte_otp_driver = { + .probe = kendryte_otp_probe, + .driver = { + .name = "kendryte_otp", + .of_match_table = kendryte_otp_dt_ids, + }, +}; +module_platform_driver(kendryte_otp_driver); + +MODULE_DESCRIPTION("kendryte k230 otp driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index c81a00fbca7db..af871cd9ab8de 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -286,6 +286,17 @@ config IMX8MM_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config CANAAN_THERMAL + tristate "Temperature sensor driver for canaan k230 SoCs" + default ARCH_CANAAN + help + Support Temperature Sensor (TSENSOR) module on canaan k230 SoC. + If you say yes here you get thermal support for the canaan k230 SoC. + The current chip supported is: + - K230 + - K230D + + config K3_THERMAL tristate "Texas Instruments K3 thermal support" depends on ARCH_K3 || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index c934cab309ae0..f2367c415018b 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o +obj-$(CONFIG_CANAAN_THERMAL) += canaan_thermal.o obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o diff --git a/drivers/thermal/canaan_thermal.c b/drivers/thermal/canaan_thermal.c new file mode 100644 index 0000000000000..3a0142e22da42 --- /dev/null +++ b/drivers/thermal/canaan_thermal.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Kendryte K230 temperature sensor support driver + * + * Copyright (C) 2024, Canaan Bright Sight Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TS_CONFIG 0x00 +#define TS_DATA 0x04 +#define TS_POWERDOWN 0x22 +#define TS_POWERON 0x23 + +struct canaan_thermal_data { + struct thermal_zone_device *tz; + void __iomem *base; +}; + +static int canaan_get_temp(struct thermal_zone_device *tz, int *temp) +{ + struct canaan_thermal_data *data = tz->devdata; + u32 val = 0; + + iowrite32(TS_POWERDOWN, data->base + TS_CONFIG); + iowrite32(TS_POWERON, data->base + TS_CONFIG); + msleep(20); + + while (1) { + val = ioread32(data->base + TS_DATA); + // msleep(2600); + + if (val >> 12) { + *temp = val; + break; + } + } + + return 0; +} + +static struct thermal_zone_device_ops canaan_tz_ops = { + .get_temp = canaan_get_temp, +}; + +static const struct of_device_id of_canaan_thermal_match[] = { + { .compatible = "canaan,k230-tsensor" }, + { /* end */ } +}; +MODULE_DEVICE_TABLE(of, of_canaan_thermal_match); + +static int canaan_thermal_probe(struct platform_device *pdev) +{ + struct canaan_thermal_data *data; + struct resource *res; + int ret; + + dev_vdbg(&pdev->dev, "[TS]: %s %d\n", __func__, __LINE__); + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + platform_set_drvdata(pdev, data); + + data->tz = thermal_tripless_zone_device_register( + "canaan_thermal_zone", data, &canaan_tz_ops, NULL); + + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "failed to register thermal zone device %d\n", ret); + return ret; + } + + iowrite32(TS_POWERDOWN, data->base + TS_CONFIG); + iowrite32(TS_POWERON, data->base + TS_CONFIG); + msleep(20); + + dev_vdbg(&pdev->dev, "[TS]: %s %d\n", __func__, __LINE__); + + return 0; +} + +static int canaan_thermal_remove(struct platform_device *pdev) +{ + struct canaan_thermal_data *data = platform_get_drvdata(pdev); + + thermal_zone_device_unregister(data->tz); + + return 0; +} + +static struct platform_driver canaan_thermal = { + .driver = { + .name = "canaan_thermal", + .of_match_table = of_canaan_thermal_match, + }, + .probe = canaan_thermal_probe, + .remove = canaan_thermal_remove, +}; +module_platform_driver(canaan_thermal); + +MODULE_DESCRIPTION("Thermal driver for canaan k230 Soc"); +MODULE_LICENSE("GPL");