Adding device probe and DMA init for StarFive hardware crypto engine. Signed-off-by: Jia Jie Ho <jiajie.ho@xxxxxxxxxxxxxxxx> Signed-off-by: Huan Feng <huan.feng@xxxxxxxxxxxxxxxx> --- MAINTAINERS | 7 + drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/starfive/Kconfig | 20 ++ drivers/crypto/starfive/Makefile | 4 + drivers/crypto/starfive/starfive-cryp.c | 268 ++++++++++++++++++++++++ drivers/crypto/starfive/starfive-regs.h | 26 +++ drivers/crypto/starfive/starfive-str.h | 74 +++++++ 8 files changed, 401 insertions(+) create mode 100644 drivers/crypto/starfive/Kconfig create mode 100644 drivers/crypto/starfive/Makefile create mode 100644 drivers/crypto/starfive/starfive-cryp.c create mode 100644 drivers/crypto/starfive/starfive-regs.h create mode 100644 drivers/crypto/starfive/starfive-str.h diff --git a/MAINTAINERS b/MAINTAINERS index 65140500d9f8..ca189a563a39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19609,6 +19609,13 @@ F: Documentation/devicetree/bindings/clock/starfive* F: drivers/clk/starfive/ F: include/dt-bindings/clock/starfive* +STARFIVE CRYPTO DRIVER +M: Jia Jie Ho <jiajie.ho@xxxxxxxxxxxxxxxx> +M: William Qiu <william.qiu@xxxxxxxxxxxxxxxx> +S: Maintained +F: Documentation/devicetree/bindings/crypto/starfive* +F: drivers/crypto/starfive/ + STARFIVE PINCTRL DRIVER M: Emil Renner Berthing <kernel@xxxxxxxx> M: Jianlong Huang <jianlong.huang@xxxxxxxxxxxxxxxx> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 55e75fbb658e..64b94376601c 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -817,5 +817,6 @@ config CRYPTO_DEV_SA2UL source "drivers/crypto/keembay/Kconfig" source "drivers/crypto/aspeed/Kconfig" +source "drivers/crypto/starfive/Kconfig" endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 116de173a66c..212931c84412 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -53,3 +53,4 @@ obj-y += xilinx/ obj-y += hisilicon/ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += keembay/ +obj-y += starfive/ diff --git a/drivers/crypto/starfive/Kconfig b/drivers/crypto/starfive/Kconfig new file mode 100644 index 000000000000..f8a2b6ecbddc --- /dev/null +++ b/drivers/crypto/starfive/Kconfig @@ -0,0 +1,20 @@ +# +# StarFive crypto drivers configuration +# + +config CRYPTO_DEV_STARFIVE + tristate "StarFive cryptographic engine driver" + depends on SOC_STARFIVE + select CRYPTO_ENGINE + select CRYPTO_RSA + select CRYPTO_AES + select CRYPTO_CCM + select ARM_AMBA + select DMADEVICES + select AMBA_PL08X + help + Support for StarFive crypto hardware acceleration engine. + This module provides acceleration for public key algo, + skciphers, AEAD and hash functions. + + If you choose 'M' here, this module will be called starfive-crypto. diff --git a/drivers/crypto/starfive/Makefile b/drivers/crypto/starfive/Makefile new file mode 100644 index 000000000000..5a84f808a671 --- /dev/null +++ b/drivers/crypto/starfive/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_CRYPTO_DEV_STARFIVE) += starfive-crypto.o +starfive-crypto-objs := starfive-cryp.o diff --git a/drivers/crypto/starfive/starfive-cryp.c b/drivers/crypto/starfive/starfive-cryp.c new file mode 100644 index 000000000000..574f9e8f4cc1 --- /dev/null +++ b/drivers/crypto/starfive/starfive-cryp.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cryptographic API. + * + * Support for StarFive hardware cryptographic engine. + * Copyright (c) 2022 StarFive Technology + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include "starfive-str.h" + +#define DRIVER_NAME "starfive-crypto" + +struct starfive_dev_list { + struct list_head dev_list; + spinlock_t lock; /* protect dev_list */ +}; + +static struct starfive_dev_list dev_list = { + .dev_list = LIST_HEAD_INIT(dev_list.dev_list), + .lock = __SPIN_LOCK_UNLOCKED(dev_list.lock), +}; + +struct starfive_sec_dev *starfive_sec_find_dev(struct starfive_sec_ctx *ctx) +{ + struct starfive_sec_dev *sdev = NULL, *tmp; + + spin_lock_bh(&dev_list.lock); + if (!ctx->sdev) { + list_for_each_entry(tmp, &dev_list.dev_list, list) { + sdev = tmp; + break; + } + ctx->sdev = sdev; + } else { + sdev = ctx->sdev; + } + + spin_unlock_bh(&dev_list.lock); + + return sdev; +} + +static const struct of_device_id starfive_dt_ids[] = { + { .compatible = "starfive,jh7110-crypto", .data = NULL}, + {}, +}; +MODULE_DEVICE_TABLE(of, starfive_dt_ids); + +static int starfive_dma_init(struct starfive_sec_dev *sdev) +{ + dma_cap_mask_t mask; + int err; + + sdev->sec_xm_m = NULL; + sdev->sec_xm_p = NULL; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + sdev->sec_xm_m = dma_request_chan(sdev->dev, "sec_m"); + if (IS_ERR(sdev->sec_xm_m)) { + dev_err(sdev->dev, "sec_m dma channel request failed.\n"); + return PTR_ERR(sdev->sec_xm_m); + } + + sdev->sec_xm_p = dma_request_chan(sdev->dev, "sec_p"); + if (IS_ERR(sdev->sec_xm_p)) { + dev_err(sdev->dev, "sec_p dma channel request failed.\n"); + goto err_dma_out; + } + + init_completion(&sdev->sec_comp_m); + init_completion(&sdev->sec_comp_p); + + return 0; + +err_dma_out: + dma_release_channel(sdev->sec_xm_m); + + return err; +} + +static void starfive_dma_cleanup(struct starfive_sec_dev *sdev) +{ + dma_release_channel(sdev->sec_xm_p); + dma_release_channel(sdev->sec_xm_m); +} + +static int starfive_cryp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct starfive_sec_dev *sdev; + struct resource *res; + int pages = 0; + int ret; + + sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); + if (!sdev) + return -ENOMEM; + + sdev->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "secreg"); + sdev->io_base = devm_ioremap_resource(dev, res); + + if (IS_ERR(sdev->io_base)) + return PTR_ERR(sdev->io_base); + + sdev->use_side_channel_mitigation = + device_property_read_bool(dev, "enable-side-channel-mitigation"); + sdev->use_dma = device_property_read_bool(dev, "enable-dma"); + sdev->dma_maxburst = 32; + + sdev->sec_hclk = devm_clk_get(dev, "sec_hclk"); + if (IS_ERR(sdev->sec_hclk)) { + dev_err(dev, "Failed to get sec_hclk.\n"); + return PTR_ERR(sdev->sec_hclk); + } + + sdev->sec_ahb = devm_clk_get(dev, "sec_ahb"); + if (IS_ERR(sdev->sec_ahb)) { + dev_err(dev, "Failed to get sec_ahb.\n"); + return PTR_ERR(sdev->sec_ahb); + } + + sdev->rst_hresetn = devm_reset_control_get_shared(sdev->dev, "sec_hre"); + if (IS_ERR(sdev->rst_hresetn)) { + dev_err(sdev->dev, "Failed to get sec_hre.\n"); + return PTR_ERR(sdev->rst_hresetn); + } + + clk_prepare_enable(sdev->sec_hclk); + clk_prepare_enable(sdev->sec_ahb); + reset_control_deassert(sdev->rst_hresetn); + + platform_set_drvdata(pdev, sdev); + + spin_lock(&dev_list.lock); + list_add(&sdev->list, &dev_list.dev_list); + spin_unlock(&dev_list.lock); + + if (sdev->use_dma) { + ret = starfive_dma_init(sdev); + if (ret) { + dev_err(dev, "Failed to initialize DMA channel.\n"); + goto err_dma_init; + } + } + + pages = get_order(STARFIVE_MSG_BUFFER_SIZE); + + sdev->pages_count = pages >> 1; + sdev->data_buf_len = STARFIVE_MSG_BUFFER_SIZE >> 1; + + /* Initialize crypto engine */ + sdev->engine = crypto_engine_alloc_init(dev, 1); + if (!sdev->engine) { + ret = -ENOMEM; + goto err_engine; + } + + ret = crypto_engine_start(sdev->engine); + if (ret) + goto err_engine_start; + + dev_info(dev, "Crypto engine started\n"); + + return 0; + +err_engine_start: + crypto_engine_exit(sdev->engine); +err_engine: + starfive_dma_cleanup(sdev); +err_dma_init: + spin_lock(&dev_list.lock); + list_del(&sdev->list); + spin_unlock(&dev_list.lock); + + return ret; +} + +static int starfive_cryp_remove(struct platform_device *pdev) +{ + struct starfive_sec_dev *sdev = platform_get_drvdata(pdev); + + if (!sdev) + return -ENODEV; + + crypto_engine_stop(sdev->engine); + crypto_engine_exit(sdev->engine); + + starfive_dma_cleanup(sdev); + + spin_lock(&dev_list.lock); + list_del(&sdev->list); + spin_unlock(&dev_list.lock); + + clk_disable_unprepare(sdev->sec_hclk); + clk_disable_unprepare(sdev->sec_ahb); + reset_control_assert(sdev->rst_hresetn); + + return 0; +} + +#ifdef CONFIG_PM +static int starfive_cryp_runtime_suspend(struct device *dev) +{ + struct starfive_sec_dev *sdev = dev_get_drvdata(dev); + + clk_disable_unprepare(sdev->sec_ahb); + clk_disable_unprepare(sdev->sec_hclk); + + return 0; +} + +static int starfive_cryp_runtime_resume(struct device *dev) +{ + struct starfive_sec_dev *sdev = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(sdev->sec_ahb); + if (ret) { + dev_err(sdev->dev, "Failed to prepare_enable sec_ahb clock\n"); + return ret; + } + + ret = clk_prepare_enable(sdev->sec_hclk); + if (ret) { + dev_err(sdev->dev, "Failed to prepare_enable sec_hclk clock\n"); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops starfive_cryp_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(starfive_cryp_runtime_suspend, + starfive_cryp_runtime_resume, NULL) +}; + +static struct platform_driver starfive_cryp_driver = { + .probe = starfive_cryp_probe, + .remove = starfive_cryp_remove, + .driver = { + .name = DRIVER_NAME, + .pm = &starfive_cryp_pm_ops, + .of_match_table = starfive_dt_ids, + }, +}; + +module_platform_driver(starfive_cryp_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("StarFive hardware crypto acceleration"); diff --git a/drivers/crypto/starfive/starfive-regs.h b/drivers/crypto/starfive/starfive-regs.h new file mode 100644 index 000000000000..0d680cb1f502 --- /dev/null +++ b/drivers/crypto/starfive/starfive-regs.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __STARFIVE_REGS_H__ +#define __STARFIVE_REGS_H__ + +#define STARFIVE_ALG_CR_OFFSET 0x0 +#define STARFIVE_ALG_FIFO_OFFSET 0x4 +#define STARFIVE_IE_MASK_OFFSET 0x8 +#define STARFIVE_IE_FLAG_OFFSET 0xc +#define STARFIVE_DMA_IN_LEN_OFFSET 0x10 +#define STARFIVE_DMA_OUT_LEN_OFFSET 0x14 + +union starfive_alg_cr { + u32 v; + struct { + u32 start :1; + u32 aes_dma_en :1; + u32 rsvd_0 :1; + u32 hash_dma_en :1; + u32 alg_done :1; + u32 rsvd_1 :3; + u32 clear :1; + u32 rsvd_2 :23; + }; +}; + +#endif diff --git a/drivers/crypto/starfive/starfive-str.h b/drivers/crypto/starfive/starfive-str.h new file mode 100644 index 000000000000..4ba3c56f0573 --- /dev/null +++ b/drivers/crypto/starfive/starfive-str.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __STARFIVE_STR_H__ +#define __STARFIVE_STR_H__ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> + +#include <crypto/engine.h> + +#include "starfive-regs.h" + +#define STARFIVE_MSG_BUFFER_SIZE SZ_16K + +struct starfive_sec_ctx { + struct crypto_engine_ctx enginectx; + struct starfive_sec_dev *sdev; + + u8 *buffer; +}; + +struct starfive_sec_dev { + struct list_head list; + struct device *dev; + + struct clk *sec_hclk; + struct clk *sec_ahb; + struct reset_control *rst_hresetn; + + void __iomem *io_base; + phys_addr_t io_phys_base; + + size_t data_buf_len; + int pages_count; + u32 use_side_channel_mitigation; + u32 use_dma; + u32 dma_maxburst; + struct dma_chan *sec_xm_m; + struct dma_chan *sec_xm_p; + struct dma_slave_config cfg_in; + struct dma_slave_config cfg_out; + struct completion sec_comp_m; + struct completion sec_comp_p; + + struct crypto_engine *engine; + + union starfive_alg_cr alg_cr; +}; + +static inline u32 starfive_sec_read(struct starfive_sec_dev *sdev, u32 offset) +{ + return __raw_readl(sdev->io_base + offset); +} + +static inline u8 starfive_sec_readb(struct starfive_sec_dev *sdev, u32 offset) +{ + return __raw_readb(sdev->io_base + offset); +} + +static inline void starfive_sec_write(struct starfive_sec_dev *sdev, + u32 offset, u32 value) +{ + __raw_writel(value, sdev->io_base + offset); +} + +static inline void starfive_sec_writeb(struct starfive_sec_dev *sdev, + u32 offset, u8 value) +{ + __raw_writeb(value, sdev->io_base + offset); +} + +struct starfive_sec_dev *starfive_sec_find_dev(struct starfive_sec_ctx *ctx); + +#endif -- 2.25.1