From 170f467e077935bbe4960d732c8e74ef043b818a Mon Sep 17 00:00:00 2001 From: wevsty Date: Mon, 24 Aug 2020 02:27:11 +0800 Subject: [PATCH] rockchip: support hardware random number generator for RK3328 and RK3399 Signed-off-by: wevsty --- target/linux/rockchip/armv8/config-5.4 | 2 + target/linux/rockchip/image/armv8.mk | 3 +- ...-for-rockchip-hardware-random-number.patch | 388 ++++++++++++++++++ ...ip-add-hardware-random-number-genera.patch | 50 +++ ...p-enable-hardware-rng-for-NanoPi-R2S.patch | 19 + 5 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 target/linux/rockchip/patches-5.4/105-char-add-support-for-rockchip-hardware-random-number.patch create mode 100644 target/linux/rockchip/patches-5.4/106-arm64-dts-rockchip-add-hardware-random-number-genera.patch create mode 100644 target/linux/rockchip/patches-5.4/107-rockchip-enable-hardware-rng-for-NanoPi-R2S.patch diff --git a/target/linux/rockchip/armv8/config-5.4 b/target/linux/rockchip/armv8/config-5.4 index d7256a84a1..358c6daa69 100644 --- a/target/linux/rockchip/armv8/config-5.4 +++ b/target/linux/rockchip/armv8/config-5.4 @@ -182,6 +182,8 @@ CONFIG_HUGETLB_PAGE=y CONFIG_HWMON=y CONFIG_HWSPINLOCK=y CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_ROCKCHIP=y # CONFIG_HZ_PERIODIC is not set CONFIG_I2C=y CONFIG_I2C_ALGOBIT=y diff --git a/target/linux/rockchip/image/armv8.mk b/target/linux/rockchip/image/armv8.mk index 3198d606ea..c0c08479e9 100644 --- a/target/linux/rockchip/image/armv8.mk +++ b/target/linux/rockchip/image/armv8.mk @@ -10,7 +10,8 @@ define Device/friendlyarm_nanopi-r2s DEVICE_MODEL := NanoPi R2S SOC := rk3328 UBOOT_DEVICE_NAME := nanopi-r2s-rk3328 - DEVICE_PACKAGES := kmod-usb-net kmod-usb-net-rtl8152 + DEVICE_PACKAGES := kmod-usb-net kmod-usb-net-rtl8152 \ + kmod-crypto-rng rng-tools $(call Device/FitImageLzma) endef TARGET_DEVICES += friendlyarm_nanopi-r2s diff --git a/target/linux/rockchip/patches-5.4/105-char-add-support-for-rockchip-hardware-random-number.patch b/target/linux/rockchip/patches-5.4/105-char-add-support-for-rockchip-hardware-random-number.patch new file mode 100644 index 0000000000..196cc00ae2 --- /dev/null +++ b/target/linux/rockchip/patches-5.4/105-char-add-support-for-rockchip-hardware-random-number.patch @@ -0,0 +1,388 @@ +From e5b5361651940ff5c0c1784dfd0130abec7ab535 Mon Sep 17 00:00:00 2001 +From: wevsty +Date: Mon, 24 Aug 2020 02:27:11 +0800 +Subject: [PATCH] char: add support for rockchip hardware random number + generator + +This patch provides hardware random number generator support for all rockchip SOC. + +rockchip-rng.c from https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/char/hw_random/rockchip-rng.c + +Signed-off-by: wevsty +--- + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -345,6 +345,19 @@ config HW_RANDOM_STM32 + + If unsure, say N. + ++config HW_RANDOM_ROCKCHIP ++ tristate "Rockchip Random Number Generator support" ++ depends on ARCH_ROCKCHIP ++ default HW_RANDOM ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Rockchip cpus. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rockchip-rng. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_PIC32 + tristate "Microchip PIC32 Random Number Generator support" + depends on HW_RANDOM && MACH_PIC32 +--- /dev/null ++++ b/drivers/char/hw_random/rockchip-rng.c +@@ -0,0 +1,340 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * rockchip-rng.c Random Number Generator driver for the Rockchip ++ * ++ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd. ++ * Author: Lin Jinhan ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define _SBF(s, v) ((v) << (s)) ++#define HIWORD_UPDATE(val, mask, shift) \ ++ ((val) << (shift) | (mask) << ((shift) + 16)) ++ ++#define ROCKCHIP_AUTOSUSPEND_DELAY 100 ++#define ROCKCHIP_POLL_PERIOD_US 100 ++#define ROCKCHIP_POLL_TIMEOUT_US 10000 ++#define RK_MAX_RNG_BYTE (32) ++ ++/* start of CRYPTO V1 register define */ ++#define CRYPTO_V1_CTRL 0x0008 ++#define CRYPTO_V1_RNG_START BIT(8) ++#define CRYPTO_V1_RNG_FLUSH BIT(9) ++ ++#define CRYPTO_V1_TRNG_CTRL 0x0200 ++#define CRYPTO_V1_OSC_ENABLE BIT(16) ++#define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x) (x) ++ ++#define CRYPTO_V1_TRNG_DOUT_0 0x0204 ++/* end of CRYPTO V1 register define */ ++ ++/* start of CRYPTO V2 register define */ ++#define CRYPTO_V2_RNG_CTL 0x0400 ++#define CRYPTO_V2_RNG_64_BIT_LEN _SBF(4, 0x00) ++#define CRYPTO_V2_RNG_128_BIT_LEN _SBF(4, 0x01) ++#define CRYPTO_V2_RNG_192_BIT_LEN _SBF(4, 0x02) ++#define CRYPTO_V2_RNG_256_BIT_LEN _SBF(4, 0x03) ++#define CRYPTO_V2_RNG_FATESY_SOC_RING _SBF(2, 0x00) ++#define CRYPTO_V2_RNG_SLOWER_SOC_RING_0 _SBF(2, 0x01) ++#define CRYPTO_V2_RNG_SLOWER_SOC_RING_1 _SBF(2, 0x02) ++#define CRYPTO_V2_RNG_SLOWEST_SOC_RING _SBF(2, 0x03) ++#define CRYPTO_V2_RNG_ENABLE BIT(1) ++#define CRYPTO_V2_RNG_START BIT(0) ++#define CRYPTO_V2_RNG_SAMPLE_CNT 0x0404 ++#define CRYPTO_V2_RNG_DOUT_0 0x0410 ++/* end of CRYPTO V2 register define */ ++ ++struct rk_rng_soc_data { ++ const char * const *clks; ++ int clks_num; ++ int (*rk_rng_read)(struct hwrng *rng, void *buf, size_t max, bool wait); ++}; ++ ++struct rk_rng { ++ struct device *dev; ++ struct hwrng rng; ++ void __iomem *mem; ++ struct rk_rng_soc_data *soc_data; ++ u32 clk_num; ++ struct clk_bulk_data *clk_bulks; ++}; ++ ++static const char * const rk_rng_v1_clks[] = { ++ "hclk_crypto", ++ "clk_crypto", ++}; ++ ++static const char * const rk_rng_v2_clks[] = { ++ "hclk_crypto", ++ "aclk_crypto", ++ "clk_crypto", ++ "clk_crypto_apk", ++}; ++ ++static void rk_rng_writel(struct rk_rng *rng, u32 val, u32 offset) ++{ ++ __raw_writel(val, rng->mem + offset); ++} ++ ++static u32 rk_rng_readl(struct rk_rng *rng, u32 offset) ++{ ++ return __raw_readl(rng->mem + offset); ++} ++ ++static int rk_rng_init(struct hwrng *rng) ++{ ++ int ret; ++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); ++ ++ dev_dbg(rk_rng->dev, "clk_bulk_prepare_enable.\n"); ++ ++ ret = clk_bulk_prepare_enable(rk_rng->clk_num, rk_rng->clk_bulks); ++ if (ret < 0) { ++ dev_err(rk_rng->dev, "failed to enable clks %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void rk_rng_cleanup(struct hwrng *rng) ++{ ++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); ++ ++ dev_dbg(rk_rng->dev, "clk_bulk_disable_unprepare.\n"); ++ clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks); ++} ++ ++static void rk_rng_read_regs(struct rk_rng *rng, u32 offset, void *buf, ++ size_t size) ++{ ++ u32 i; ++ ++ for (i = 0; i < size; i += 4) ++ *(u32 *)(buf + i) = be32_to_cpu(rk_rng_readl(rng, offset + i)); ++} ++ ++static int rk_rng_v1_read(struct hwrng *rng, void *buf, size_t max, bool wait) ++{ ++ int ret = 0; ++ u32 reg_ctrl = 0; ++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); ++ ++ ret = pm_runtime_get_sync(rk_rng->dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(rk_rng->dev); ++ return ret; ++ } ++ ++ /* enable osc_ring to get entropy, sample period is set as 100 */ ++ reg_ctrl = CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100); ++ rk_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_TRNG_CTRL); ++ ++ reg_ctrl = HIWORD_UPDATE(CRYPTO_V1_RNG_START, CRYPTO_V1_RNG_START, 0); ++ ++ rk_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_CTRL); ++ ++ ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V1_CTRL, reg_ctrl, ++ !(reg_ctrl & CRYPTO_V1_RNG_START), ++ ROCKCHIP_POLL_PERIOD_US, ++ ROCKCHIP_POLL_TIMEOUT_US); ++ if (ret < 0) ++ goto out; ++ ++ ret = min_t(size_t, max, RK_MAX_RNG_BYTE); ++ ++ rk_rng_read_regs(rk_rng, CRYPTO_V1_TRNG_DOUT_0, buf, ret); ++ ++out: ++ /* close TRNG */ ++ rk_rng_writel(rk_rng, HIWORD_UPDATE(0, CRYPTO_V1_RNG_START, 0), ++ CRYPTO_V1_CTRL); ++ ++ pm_runtime_mark_last_busy(rk_rng->dev); ++ pm_runtime_put_sync_autosuspend(rk_rng->dev); ++ ++ return ret; ++} ++ ++static int rk_rng_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait) ++{ ++ int ret = 0; ++ u32 reg_ctrl = 0; ++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); ++ ++ ret = pm_runtime_get_sync(rk_rng->dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(rk_rng->dev); ++ return ret; ++ } ++ ++ /* enable osc_ring to get entropy, sample period is set as 100 */ ++ rk_rng_writel(rk_rng, 100, CRYPTO_V2_RNG_SAMPLE_CNT); ++ ++ reg_ctrl |= CRYPTO_V2_RNG_256_BIT_LEN; ++ reg_ctrl |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0; ++ reg_ctrl |= CRYPTO_V2_RNG_ENABLE; ++ reg_ctrl |= CRYPTO_V2_RNG_START; ++ ++ rk_rng_writel(rk_rng, HIWORD_UPDATE(reg_ctrl, 0xffff, 0), ++ CRYPTO_V2_RNG_CTL); ++ ++ ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V2_RNG_CTL, reg_ctrl, ++ !(reg_ctrl & CRYPTO_V2_RNG_START), ++ ROCKCHIP_POLL_PERIOD_US, ++ ROCKCHIP_POLL_TIMEOUT_US); ++ if (ret < 0) ++ goto out; ++ ++ ret = min_t(size_t, max, RK_MAX_RNG_BYTE); ++ ++ rk_rng_read_regs(rk_rng, CRYPTO_V2_RNG_DOUT_0, buf, ret); ++ ++out: ++ /* close TRNG */ ++ rk_rng_writel(rk_rng, HIWORD_UPDATE(0, 0xffff, 0), CRYPTO_V2_RNG_CTL); ++ ++ pm_runtime_mark_last_busy(rk_rng->dev); ++ pm_runtime_put_sync_autosuspend(rk_rng->dev); ++ ++ return ret; ++} ++ ++static const struct rk_rng_soc_data rk_rng_v1_soc_data = { ++ .clks_num = ARRAY_SIZE(rk_rng_v1_clks), ++ .clks = rk_rng_v1_clks, ++ .rk_rng_read = rk_rng_v1_read, ++}; ++ ++static const struct rk_rng_soc_data rk_rng_v2_soc_data = { ++ .clks_num = ARRAY_SIZE(rk_rng_v2_clks), ++ .clks = rk_rng_v2_clks, ++ .rk_rng_read = rk_rng_v2_read, ++}; ++ ++static const struct of_device_id rk_rng_dt_match[] = { ++ { ++ .compatible = "rockchip,cryptov1-rng", ++ .data = (void *)&rk_rng_v1_soc_data, ++ }, ++ { ++ .compatible = "rockchip,cryptov2-rng", ++ .data = (void *)&rk_rng_v2_soc_data, ++ }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rk_rng_dt_match); ++ ++static int rk_rng_probe(struct platform_device *pdev) ++{ ++ int i; ++ int ret; ++ struct rk_rng *rk_rng; ++ struct device_node *np = pdev->dev.of_node; ++ const struct of_device_id *match; ++ ++ dev_dbg(&pdev->dev, "probing...\n"); ++ rk_rng = devm_kzalloc(&pdev->dev, sizeof(struct rk_rng), GFP_KERNEL); ++ if (!rk_rng) ++ return -ENOMEM; ++ ++ match = of_match_node(rk_rng_dt_match, np); ++ rk_rng->soc_data = (struct rk_rng_soc_data *)match->data; ++ ++ rk_rng->dev = &pdev->dev; ++ rk_rng->rng.name = "rockchip"; ++#ifndef CONFIG_PM ++ rk_rng->rng.init = rk_rng_init; ++ rk_rng->rng.cleanup = rk_rng_cleanup, ++#endif ++ rk_rng->rng.read = rk_rng->soc_data->rk_rng_read; ++ rk_rng->rng.quality = 999; ++ ++ rk_rng->clk_bulks = ++ devm_kzalloc(&pdev->dev, sizeof(*rk_rng->clk_bulks) * ++ rk_rng->soc_data->clks_num, GFP_KERNEL); ++ ++ rk_rng->clk_num = rk_rng->soc_data->clks_num; ++ ++ for (i = 0; i < rk_rng->soc_data->clks_num; i++) ++ rk_rng->clk_bulks[i].id = rk_rng->soc_data->clks[i]; ++ ++ rk_rng->mem = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); ++ if (IS_ERR(rk_rng->mem)) ++ return PTR_ERR(rk_rng->mem); ++ ++ ret = devm_clk_bulk_get(&pdev->dev, rk_rng->clk_num, ++ rk_rng->clk_bulks); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to get clks property\n"); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, rk_rng); ++ ++ pm_runtime_set_autosuspend_delay(&pdev->dev, ++ ROCKCHIP_AUTOSUSPEND_DELAY); ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_runtime_enable(&pdev->dev); ++ ++ ret = devm_hwrng_register(&pdev->dev, &rk_rng->rng); ++ if (ret) { ++ pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int rk_rng_runtime_suspend(struct device *dev) ++{ ++ struct rk_rng *rk_rng = dev_get_drvdata(dev); ++ ++ rk_rng_cleanup(&rk_rng->rng); ++ ++ return 0; ++} ++ ++static int rk_rng_runtime_resume(struct device *dev) ++{ ++ struct rk_rng *rk_rng = dev_get_drvdata(dev); ++ ++ return rk_rng_init(&rk_rng->rng); ++} ++ ++static const struct dev_pm_ops rk_rng_pm_ops = { ++ SET_RUNTIME_PM_OPS(rk_rng_runtime_suspend, ++ rk_rng_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++}; ++ ++#endif ++ ++static struct platform_driver rk_rng_driver = { ++ .driver = { ++ .name = "rockchip-rng", ++#ifdef CONFIG_PM ++ .pm = &rk_rng_pm_ops, ++#endif ++ .of_match_table = rk_rng_dt_match, ++ }, ++ .probe = rk_rng_probe, ++}; ++ ++module_platform_driver(rk_rng_driver); ++ ++MODULE_DESCRIPTION("ROCKCHIP H/W Random Number Generator driver"); ++MODULE_AUTHOR("Lin Jinhan "); ++MODULE_LICENSE("GPL v2"); ++ +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += + obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o + obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o + obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o ++obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o + obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o + obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o + obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o diff --git a/target/linux/rockchip/patches-5.4/106-arm64-dts-rockchip-add-hardware-random-number-genera.patch b/target/linux/rockchip/patches-5.4/106-arm64-dts-rockchip-add-hardware-random-number-genera.patch new file mode 100644 index 0000000000..aa7c5c39d4 --- /dev/null +++ b/target/linux/rockchip/patches-5.4/106-arm64-dts-rockchip-add-hardware-random-number-genera.patch @@ -0,0 +1,50 @@ +From e5b5361651940ff5c0c1784dfd0130abec7ab535 Mon Sep 17 00:00:00 2001 +From: wevsty +Date: Mon, 24 Aug 2020 02:27:11 +0800 +Subject: [PATCH] arm64: dts: rockchip: add hardware random number generator + for RK3328 and RK3399 + +Adding Hardware Random Number Generator Resources to the RK3328 and RK3399. + +Signed-off-by: wevsty +--- + +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -279,6 +279,17 @@ + status = "disabled"; + }; + ++ rng: rng@ff060000 { ++ compatible = "rockchip,cryptov1-rng"; ++ reg = <0x0 0xff060000 0x0 0x4000>; ++ ++ clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>; ++ clock-names = "clk_crypto", "hclk_crypto"; ++ assigned-clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>; ++ assigned-clock-rates = <150000000>, <100000000>; ++ status = "disabled"; ++ }; ++ + grf: syscon@ff100000 { + compatible = "rockchip,rk3328-grf", "syscon", "simple-mfd"; + reg = <0x0 0xff100000 0x0 0x1000>; +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1879,6 +1879,16 @@ + }; + }; + ++ rng: rng@ff8b8000 { ++ compatible = "rockchip,cryptov1-rng"; ++ reg = <0x0 0xff8b8000 0x0 0x1000>; ++ clocks = <&cru SCLK_CRYPTO1>, <&cru HCLK_S_CRYPTO1>; ++ clock-names = "clk_crypto", "hclk_crypto"; ++ assigned-clocks = <&cru SCLK_CRYPTO1>, <&cru HCLK_S_CRYPTO1>; ++ assigned-clock-rates = <150000000>, <100000000>; ++ status = "disabled"; ++ }; ++ + gpu: gpu@ff9a0000 { + compatible = "rockchip,rk3399-mali", "arm,mali-t860"; + reg = <0x0 0xff9a0000 0x0 0x10000>; diff --git a/target/linux/rockchip/patches-5.4/107-rockchip-enable-hardware-rng-for-NanoPi-R2S.patch b/target/linux/rockchip/patches-5.4/107-rockchip-enable-hardware-rng-for-NanoPi-R2S.patch new file mode 100644 index 0000000000..0f32bd132c --- /dev/null +++ b/target/linux/rockchip/patches-5.4/107-rockchip-enable-hardware-rng-for-NanoPi-R2S.patch @@ -0,0 +1,19 @@ +From e5b5361651940ff5c0c1784dfd0130abec7ab535 Mon Sep 17 00:00:00 2001 +From: wevsty +Date: Mon, 24 Aug 2020 02:27:11 +0800 +Subject: [PATCH] rockchip: rk3328: enable hardware rng for NanoPi R2S + + +Signed-off-by: wevsty +--- + +--- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +@@ -410,3 +410,7 @@ + realtek,led-data = <0x87>; + }; + }; ++ ++&rng { ++ status = "okay"; ++};