From 726087de6e9654badb496347ba46d88eba53a01f Mon Sep 17 00:00:00 2001 From: Jason Zhu Date: Mon, 10 Dec 2018 17:01:03 +0800 Subject: [PATCH] crypto: support rockchip hardware crypto Support: rsa & sha algorithm Usage: Set CONFIG_RK_CRYPTO to enable rk crypto. Change-Id: I2b6a920308fcdf46481bcf38fc6be532a02255bd Signed-off-by: Jason Zhu --- drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/rockchip/Kconfig | 5 + drivers/crypto/rockchip/Makefile | 8 + drivers/crypto/rockchip/rockchip_crypto.c | 120 ++++++++++++ drivers/crypto/rockchip/rockchip_crypto_hd.c | 196 +++++++++++++++++++ include/dm/uclass-id.h | 2 +- include/rockchip_crypto/rockchip_crypto.h | 31 +++ include/rockchip_crypto/rockchip_crypto_hd.h | 112 +++++++++++ 9 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 drivers/crypto/rockchip/Kconfig create mode 100644 drivers/crypto/rockchip/Makefile create mode 100644 drivers/crypto/rockchip/rockchip_crypto.c create mode 100644 drivers/crypto/rockchip/rockchip_crypto_hd.c create mode 100644 include/rockchip_crypto/rockchip_crypto.h create mode 100644 include/rockchip_crypto/rockchip_crypto_hd.h diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 1ea116be75..709268c8c7 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -1,5 +1,6 @@ menu "Hardware crypto devices" source drivers/crypto/fsl/Kconfig +source drivers/crypto/rockchip/Kconfig endmenu diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index fb8c10b38c..0b770fcd64 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o obj-y += rsa_mod_exp/ obj-y += fsl/ +obj-$(CONFIG_CRYPTO_ROCKCHIP) += rockchip/ diff --git a/drivers/crypto/rockchip/Kconfig b/drivers/crypto/rockchip/Kconfig new file mode 100644 index 0000000000..40b332e41d --- /dev/null +++ b/drivers/crypto/rockchip/Kconfig @@ -0,0 +1,5 @@ +config CRYPTO_ROCKCHIP + bool "Support Rockchip Hardware Crypto" + help + The module supports Rockchip Hardware Crypto. + This accelerates algorithmic operations. \ No newline at end of file diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile new file mode 100644 index 0000000000..bb1557984d --- /dev/null +++ b/drivers/crypto/rockchip/Makefile @@ -0,0 +1,8 @@ +# +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd +# + +obj-y += rockchip_crypto_hd.o +obj-y += rockchip_crypto.o diff --git a/drivers/crypto/rockchip/rockchip_crypto.c b/drivers/crypto/rockchip/rockchip_crypto.c new file mode 100644 index 0000000000..208d3619e0 --- /dev/null +++ b/drivers/crypto/rockchip/rockchip_crypto.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include + +int get_rk_crypto_desc(struct rk_crypto_desc *crypto_desc) +{ + int ret; + + ret = uclass_get_device_by_name(UCLASS_RKCRYPTO, "crypto", + &crypto_desc->dev); + if (ret) { + printf("%s: Can not get crypto dev.\n", __func__); + return ret; + } + + crypto_desc->ops = crypto_get_ops(crypto_desc->dev); + + return 0; +} + +int rk_crypto_sha_init(struct rk_crypto_desc *rk_crypto, u32 msg_len, + int hash_bits) +{ + return rk_crypto->ops->sha_init(rk_crypto->dev, msg_len, msg_len); +} + +int rk_crypto_sha_byte_swap(struct rk_crypto_desc *rk_crypto, int en) +{ + return rk_crypto->ops->sha_byte_swap(rk_crypto->dev, en); +} + +int rk_crypto_sha_start(struct rk_crypto_desc *rk_crypto, u32 *data, + u32 data_len) +{ + return rk_crypto->ops->sha_start(rk_crypto->dev, data, data_len); +} + +int rk_crypto_sha_end(struct rk_crypto_desc *rk_crypto, u32 *result) +{ + return rk_crypto->ops->sha_end(rk_crypto->dev, result); +} + +int rk_crypto_sha_check(struct rk_crypto_desc *rk_crypto, u32 *in_hash) +{ + int ret; + u32 data_hash[8]; + + ret = rk_crypto_sha_end(rk_crypto, data_hash); + if (ret) + return -1; + + return memcmp(in_hash, data_hash, 32); +} + +int rk_crypto_rsa_init(struct rk_crypto_desc *rk_crypto) +{ + return rk_crypto->ops->rsa_init(rk_crypto->dev); +} + +int rk_crypto_rsa_start(struct rk_crypto_desc *rk_crypto, + u32 *m, u32 *n, u32 *e, u32 *c) +{ + return rk_crypto->ops->rsa_start(rk_crypto->dev, m, n, e, c); +} + +int rk_crypto_rsa_end(struct rk_crypto_desc *rk_crypto, u32 *result) +{ + return rk_crypto->ops->rsa_end(rk_crypto->dev, result); +} + +int rk_crypto_rsa_check(struct rk_crypto_desc *rk_crypto) +{ + u32 datahash[8]; + u32 rsa_result[8]; + int ret = 0; + + ret = rk_crypto_sha_end(rk_crypto, datahash); + if (ret) + return ret; + + ret = rk_crypto_rsa_end(rk_crypto, rsa_result); + if (ret) + return ret; + + return memcmp(rsa_result, datahash, 32); +} + +int rk_crypto_probe(void) +{ + int ret; + struct udevice *dev; + + ret = uclass_get_device_by_name(UCLASS_RKCRYPTO, "crypto", &dev); + if (ret) { + printf("%s: Can not get crypto dev.\n", __func__); + return -1; + } + + ret = device_probe(dev); + if (ret) { + printf("%s: Crypto probe error.\n", __func__); + return -1; + } + + return 0; +} + +UCLASS_DRIVER(crypto) = { + .id = UCLASS_RKCRYPTO, + .name = "crypto", +}; diff --git a/drivers/crypto/rockchip/rockchip_crypto_hd.c b/drivers/crypto/rockchip/rockchip_crypto_hd.c new file mode 100644 index 0000000000..d765411bbc --- /dev/null +++ b/drivers/crypto/rockchip/rockchip_crypto_hd.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rockchip_crypto_plat { + fdt_addr_t base; + s32 frequency; +}; + +struct rockchip_crypto_priv { + volatile struct rk_crypto_reg *regbase; + struct clk clk; + unsigned int max_freq; +}; + +static int rockchip_crypto_ofdata_to_platdata(struct udevice *bus) +{ + struct rockchip_crypto_plat *plat = dev_get_platdata(bus); + struct rockchip_crypto_priv *priv = dev_get_priv(bus); + int ret = 0; + + plat->base = dev_read_u32_default(bus, "default-addr", 0); + debug("Crypto base address is %x\n", (int)(size_t)plat->base); + ret = clk_get_by_index(bus, 0, &priv->clk); + if (ret < 0) { + printf("Could not get clock for %s: %d\n", bus->name, ret); + return ret; + } + + plat->frequency = dev_read_u32_default(bus, "default-frequency", + CRYPTO_DEFAULT_CLK); + debug("Crypto clock frequency is %x\n", (int)(size_t)plat->frequency); + + return 0; +} + +static int rockchip_crypto_probe(struct udevice *dev) +{ + struct rockchip_crypto_plat *plat = dev_get_platdata(dev); + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + int ret = 0; + + priv->regbase = (volatile struct rk_crypto_reg *) + (plat->base & 0xffffffff); + priv->max_freq = plat->frequency; + ret = clk_set_rate(&priv->clk, priv->max_freq); + if (ret < 0) { + printf("%s: Failed to set clock: %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static int rockchip_crypto_sha_init(struct udevice *dev, u32 msg_len, + int hash_bits) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + priv->regbase->crypto_hash_meg_len = msg_len; + if (hash_bits == SHA_256_BIT) { + priv->regbase->crypto_hash_ctrl = HASH_SWAP_DO | ENGINE_SELECTION_SHA256; + priv->regbase->crypto_conf &= ~(BYTESWAP_HRFIFO); + } else { + printf("Do not support that hash_bits is not equal to 256"); + return -ENOTSUPP; + } + + rk_setreg(&priv->regbase->crypto_ctrl, HASH_FLUSH); + do {} while (priv->regbase->crypto_ctrl & HASH_FLUSH); + + return 0; +} + +static int rockchip_crypto_sha_byte_swap(struct udevice *dev, int en) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + if (en) + priv->regbase->crypto_conf |= BYTESWAP_HRFIFO; + else + priv->regbase->crypto_conf &= ~BYTESWAP_HRFIFO; + return 0; +} + +static int rockchip_crypto_sha_start(struct udevice *dev, u32 *data, + u32 data_len) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + if (data_len == 0) + return 0; + + flush_cache((unsigned long)data, data_len); + do {} while (priv->regbase->crypto_ctrl & HASH_START); + priv->regbase->crypto_intsts = HASH_DONE_INT; + priv->regbase->crypto_hrdmas = (u32)(unsigned long)data; + priv->regbase->crypto_hrdmal = ((data_len + 3) >> 2); + rk_setreg(&priv->regbase->crypto_ctrl, HASH_START); + + return 0; +} + +static int rockchip_crypto_sha_end(struct udevice *dev, u32 *result) +{ + int i; + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + do {} while (priv->regbase->crypto_ctrl & HASH_START); + do {} while (!priv->regbase->crypto_hash_sts); + for (i = 0; i < 8; i++) + *result++ = priv->regbase->crypto_hash_dout[i]; + + return 0; +} + +static int rockchip_crypto_rsa_init(struct udevice *dev) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + priv->regbase->crypto_pka_ctrl = PKA_BLOCK_SIZE_2048; + rk_setreg(&priv->regbase->crypto_ctrl, PKA_HASH_CTRL); + priv->regbase->crypto_intsts = 0xffffffff; + do {} while (priv->regbase->crypto_ctrl & PKA_CTRL); + + return 0; +} + +static int rockchip_crypto_rsa_start(struct udevice *dev, u32 *m, + u32 *n, u32 *e, u32 *c) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + + priv->regbase->crypto_intsts = PKA_DONE_INT; + memcpy((void *)&priv->regbase->crypto_pka_m, (void *)m, 256); + memcpy((void *)&priv->regbase->crypto_pka_n, (void *)n, 256); + memcpy((void *)&priv->regbase->crypto_pka_e, (void *)e, 256); + memcpy((void *)&priv->regbase->crypto_pka_c, (void *)c, 256); + do {} while (priv->regbase->crypto_ctrl & PKA_START); + rk_setreg(&priv->regbase->crypto_ctrl, PKA_START); + + return 0; +} + +static int rockchip_crypto_rsa_end(struct udevice *dev, u32 *result) +{ + struct rockchip_crypto_priv *priv = dev_get_priv(dev); + int i; + + do {} while (priv->regbase->crypto_ctrl & PKA_START); + for (i = 0; i < 8; i++) + *result++ = *((u32 *)(&priv->regbase->crypto_pka_m + i)); + + return 0; +} + +static const struct dm_rk_crypto_ops rockchip_crypto_ops = { + .sha_init = rockchip_crypto_sha_init, + .sha_byte_swap = rockchip_crypto_sha_byte_swap, + .sha_start = rockchip_crypto_sha_start, + .sha_end = rockchip_crypto_sha_end, + .rsa_init = rockchip_crypto_rsa_init, + .rsa_start = rockchip_crypto_rsa_start, + .rsa_end = rockchip_crypto_rsa_end, +}; + +static const struct udevice_id rockchip_crypto_ids[] = { + { .compatible = "rockchip,rk3399-crypto" }, + { } +}; + +U_BOOT_DRIVER(rockchip_crypto_drv) = { + .name = "rockchip_crypto", + .id = UCLASS_RKCRYPTO, + .of_match = rockchip_crypto_ids, + .ops = &rockchip_crypto_ops, + .ofdata_to_platdata = rockchip_crypto_ofdata_to_platdata, + .probe = rockchip_crypto_probe, + .priv_auto_alloc_size = sizeof(struct rockchip_crypto_priv), + .platdata_auto_alloc_size = sizeof(struct rockchip_crypto_plat), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 76c5eb7d88..70910f319e 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -100,7 +100,7 @@ enum uclass_id { UCLASS_CHARGE_DISPLAY, /* Charge display */ UCLASS_DVFS, /* DVFS policy */ UCLASS_IO_DOMAIN, /* IO domain */ - + UCLASS_RKCRYPTO, /* Rockchip Crypto */ UCLASS_COUNT, UCLASS_INVALID = -1, }; diff --git a/include/rockchip_crypto/rockchip_crypto.h b/include/rockchip_crypto/rockchip_crypto.h new file mode 100644 index 0000000000..ca7fbb01df --- /dev/null +++ b/include/rockchip_crypto/rockchip_crypto.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + */ + +#ifndef _ROCKCHIP_CRYPTO_H_ +#define _ROCKCHIP_CRYPTO_H_ + +#define crypto_get_ops(dev) ((struct dm_rk_crypto_ops *)(dev)->driver->ops) + +struct rk_crypto_desc { + struct udevice *dev; + struct dm_rk_crypto_ops *ops; +}; + +int get_rk_crypto_desc(struct rk_crypto_desc *crypto_desc); +int rk_crypto_sha_init(struct rk_crypto_desc *rk_crypto, u32 msg_len, + int hash_bits); +int rk_crypto_sha_byte_swap(struct rk_crypto_desc *rk_crypto, int en); +int rk_crypto_sha_start(struct rk_crypto_desc *rk_crypto, u32 *data, + u32 data_len); +int rk_crypto_sha_end(struct rk_crypto_desc *rk_crypto, u32 *result); +int rk_crypto_sha_check(struct rk_crypto_desc *rk_crypto, u32 *in_hash); +int rk_crypto_rsa_init(struct rk_crypto_desc *rk_crypto); +int rk_crypto_rsa_start(struct rk_crypto_desc *rk_crypto, u32 *m, + u32 *n, u32 *e, u32 *c); +int rk_crypto_rsa_end(struct rk_crypto_desc *rk_crypto, u32 *result); +int rk_crypto_rsa_check(struct rk_crypto_desc *rk_crypto); +int rk_crypto_probe(void); + +#endif diff --git a/include/rockchip_crypto/rockchip_crypto_hd.h b/include/rockchip_crypto/rockchip_crypto_hd.h new file mode 100644 index 0000000000..c34fbdb90d --- /dev/null +++ b/include/rockchip_crypto/rockchip_crypto_hd.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + */ + +#ifndef _ROCKCHIP_CRYPTO_HD_H_ +#define _ROCKCHIP_CRYPTO_HD_H_ + +struct rk_crypto_reg { + u32 crypto_intsts; + u32 crypto_intena; + u32 crypto_ctrl; + u32 crypto_conf; + u32 crypto_brdmas; + u32 crypto_btdmas; + u32 crypto_brdmal; + u32 crypto_hrdmas; + u32 crypto_hrdmal; + u32 reserved0[(0x80 - 0x24) / 4]; + + u32 crypto_aes_ctrl; + u32 crypto_aes_sts; + u32 crypto_aes_din[4]; + u32 crypto_aes_dout[4]; + u32 crypto_aes_iv[4]; + u32 crypto_aes_key[8]; + u32 crypto_aes_cnt[4]; + u32 reserved1[(0x100 - 0xe8) / 4]; + + u32 crypto_tdes_ctrl; + u32 crypto_tdes_sts; + u32 crypto_tdes_din[2]; + u32 crypto_tdes_dout[2]; + u32 crypto_tdes_iv[2]; + u32 crypto_tdes_key1[2]; + u32 crypto_tdes_key2[2]; + u32 crypto_tdes_key3[2]; + u32 reserved2[(0x180 - 0x138) / 4]; + + u32 crypto_hash_ctrl; + u32 crypto_hash_sts; + u32 crypto_hash_meg_len; + u32 crypto_hash_dout[8]; + u32 crypto_hash_seed[5]; + u32 reserved3[(0x200 - 0x1c0) / 4]; + + u32 crypto_trng_ctrl; + u32 crypto_trng_dout[8]; + u32 reserved4[(0x280 - 0x224) / 4]; + + u32 crypto_pka_ctrl; + u32 reserved5[(0x400 - 0x284) / 4]; + + u32 crypto_pka_m; + u32 reserved6[(0x500 - 0x404) / 4]; + + u32 crypto_pka_c; + u32 reserved7[(0x600 - 0x504) / 4]; + + u32 crypto_pka_n; + u32 reserved8[(0x700 - 0x604) / 4]; + + u32 crypto_pka_e; +}; + +#define CRYPTO_DEFAULT_CLK 10000000 +#define SHA_256_BIT 256 +/* crypto_hash_ctrl */ +#define HASH_SWAP_DO 0x8 +#define ENGINE_SELECTION_SHA256 0x2 +/* crypto_conf */ +#define HR_ADDR_MODE (1 << 8) +#define BT_ADDR_MODE (1 << 7) +#define BR_ADDR_MODE (1 << 6) +#define BYTESWAP_HRFIFO (1 << 5) +#define BYTESWAP_BTFIFO (1 << 4) +#define BYTESWAP_BRFIFO (1 << 3) +#define DESSEL (1 << 2) +/* crypto_ctrl */ +#define TRNG_FLUSH (1 << 9) +#define TRNG_START (1 << 8) +#define PKA_FLUSH (1 << 7) +#define HASH_FLUSH (1 << 6) +#define BLOCK_FLUSH (1 << 5) +#define PKA_START (1 << 4) +#define HASH_START (1 << 3) +#define BLOCK_START (1 << 2) +#define TDES_START (1 << 1) +#define AES_START (1 << 0) +#define PKA_HASH_CTRL (PKA_FLUSH | HASH_FLUSH) +#define PKA_CTRL (PKA_FLUSH | PKA_START) +/* crypto_intsts */ +#define PKA_DONE_INT (1 << 5) +#define HASH_DONE_INT (1 << 4) +#define HRDMA_ERR_INT (1 << 3) +#define HRDMA_DONE_INT (1 << 2) +#define BCDMA_ERR_INT (1 << 1) +#define BCDMA_DONE_INT (1 << 0) +/* crypto_pka_ctrl */ +#define PKA_BLOCK_SIZE_2048 2 + +struct dm_rk_crypto_ops { + int (*sha_init)(struct udevice *dev, u32 msg_len, int hash_bits); + int (*sha_byte_swap)(struct udevice *dev, int en); + int (*sha_start)(struct udevice *dev, u32 *data, u32 data_len); + int (*sha_end)(struct udevice *dev, u32 *result); + int (*rsa_init)(struct udevice *dev); + int (*rsa_start)(struct udevice *dev, u32 *m, u32 *n, u32 *e, u32 *c); + int (*rsa_end)(struct udevice *dev, u32 *result); +}; + +#endif