forked from mirror/openwrt
mediatek: replace downstream TRNGv2 driver
Replace the downstream mtk-rng-v2 driver which was acquires random bytes from TF-A via SMC. A new approach is needed as TF-A for MT7986 has changed and now requires to use SMC instead of directly accessing the TRNG via MMIO. However, we can't know whether we are on old or new TF-A, many devices (like the BananaPi BPi-R3) allow updating TF-A BL3 in the field, so it may be of the old or new type, and the RNG driver will have to figure it out somehow. This currently means that MT7986 with newer TF-A has broken/non-working HWRNG in Linux: root@OpenWrt:~# hexdump -C /dev/hwrng hexdump: /dev/hwrng: I/O error Fix this by creating a new combined driver which replaces the previous mtk-rng-v2 driver, and is able to auto-detect which convention to use on MT7986. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
parent
57bf713ef7
commit
b7a2f80740
6 changed files with 272 additions and 136 deletions
|
|
@ -222,7 +222,6 @@ CONFIG_HAS_IOPORT_MAP=y
|
|||
CONFIG_HWMON=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_MTK=y
|
||||
CONFIG_HW_RANDOM_MTK_V2=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
|
|
|
|||
|
|
@ -221,7 +221,6 @@ CONFIG_HAS_IOPORT_MAP=y
|
|||
CONFIG_HWMON=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_MTK=y
|
||||
# CONFIG_HW_RANDOM_MTK_V2 is not set
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
|
|
|
|||
|
|
@ -161,7 +161,6 @@ CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
|
|||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_MTK=y
|
||||
# CONFIG_HW_RANDOM_MTK_V2 is not set
|
||||
CONFIG_HZ_FIXED=0
|
||||
# CONFIG_IDPF is not set
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
From f9c0c36eefaa8c6ee224634bf9c0b8b4ed87b43a Mon Sep 17 00:00:00 2001
|
||||
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
Date: Thu, 10 Apr 2025 18:22:38 +0300
|
||||
Subject: [PATCH] hwrng: mtk - Add struct device pointer to device context struct
|
||||
|
||||
Add a struct device pointer field to the device's context struct. This
|
||||
makes using the unsigned long priv pointer in struct hwrng unnecessary, so
|
||||
remove that one as well.
|
||||
|
||||
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
---
|
||||
drivers/char/hw_random/mtk-rng.c | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/char/hw_random/mtk-rng.c
|
||||
+++ b/drivers/char/hw_random/mtk-rng.c
|
||||
@@ -36,6 +36,7 @@ struct mtk_rng {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct hwrng rng;
|
||||
+ struct device *dev;
|
||||
};
|
||||
|
||||
static int mtk_rng_init(struct hwrng *rng)
|
||||
@@ -85,7 +86,7 @@ static int mtk_rng_read(struct hwrng *rn
|
||||
struct mtk_rng *priv = to_mtk_rng(rng);
|
||||
int retval = 0;
|
||||
|
||||
- pm_runtime_get_sync((struct device *)priv->rng.priv);
|
||||
+ pm_runtime_get_sync(priv->dev);
|
||||
|
||||
while (max >= sizeof(u32)) {
|
||||
if (!mtk_rng_wait_ready(rng, wait))
|
||||
@@ -97,8 +98,8 @@ static int mtk_rng_read(struct hwrng *rn
|
||||
max -= sizeof(u32);
|
||||
}
|
||||
|
||||
- pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
|
||||
- pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
|
||||
+ pm_runtime_mark_last_busy(priv->dev);
|
||||
+ pm_runtime_put_sync_autosuspend(priv->dev);
|
||||
|
||||
return retval || !wait ? retval : -EIO;
|
||||
}
|
||||
@@ -112,13 +113,13 @@ static int mtk_rng_probe(struct platform
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
+ priv->dev = &pdev->dev;
|
||||
priv->rng.name = pdev->name;
|
||||
#ifndef CONFIG_PM
|
||||
priv->rng.init = mtk_rng_init;
|
||||
priv->rng.cleanup = mtk_rng_cleanup;
|
||||
#endif
|
||||
priv->rng.read = mtk_rng_read;
|
||||
- priv->rng.priv = (unsigned long)&pdev->dev;
|
||||
priv->rng.quality = 900;
|
||||
|
||||
priv->clk = devm_clk_get(&pdev->dev, "rng");
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
From 9837930d6738e9fdc323ad887ace7c236a61d70c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Wed, 25 Jan 2023 00:27:49 +0000
|
||||
Subject: [PATCH] hwrng: add driver for MediaTek TRNG SMC
|
||||
|
||||
Add driver providing kernel-side support for the Random Number
|
||||
Generator hardware found on Mediatek SoCs which have a driver in ARM
|
||||
TrustedFirmware-A allowing Linux to read random numbers using a
|
||||
non-standard vendor-defined Secure Monitor Call.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/char/hw_random/Kconfig | 16 +++++++
|
||||
drivers/char/hw_random/Makefile | 1 +
|
||||
drivers/char/hw_random/mtk-rng-v2.c | 74 +++++++++++++++++++++++++++++
|
||||
3 files changed, 91 insertions(+)
|
||||
create mode 100644 drivers/char/hw_random/mtk-rng-v2.c
|
||||
|
||||
--- a/drivers/char/hw_random/Kconfig
|
||||
+++ b/drivers/char/hw_random/Kconfig
|
||||
@@ -452,6 +452,23 @@ config HW_RANDOM_MTK
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
+config HW_RANDOM_MTK_V2
|
||||
+ tristate "Mediatek Random Number Generator support (v2/SMC)"
|
||||
+ depends on HAVE_ARM_SMCCC
|
||||
+ depends on HW_RANDOM
|
||||
+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
|
||||
+ default y
|
||||
+ help
|
||||
+ This driver provides kernel-side support for the Random Number
|
||||
+ Generator hardware found on Mediatek SoCs which have a driver
|
||||
+ in ARM TrustedFirmware-A allowing Linux to read using a non-
|
||||
+ standard vendor-defined Secure Monitor Call.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here. the
|
||||
+ module will be called mtk-rng-v2.
|
||||
+
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
config HW_RANDOM_S390
|
||||
tristate "S390 True Random Number Generator support"
|
||||
depends on S390
|
||||
--- a/drivers/char/hw_random/Makefile
|
||||
+++ b/drivers/char/hw_random/Makefile
|
||||
@@ -39,6 +39,7 @@ obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-r
|
||||
obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
|
||||
obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
|
||||
+obj-$(CONFIG_HW_RANDOM_MTK_V2) += mtk-rng-v2.o
|
||||
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
|
||||
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/hw_random/mtk-rng-v2.c
|
||||
@@ -0,0 +1,76 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Driver for Mediatek Hardware Random Number Generator (v2/SMCC)
|
||||
+ *
|
||||
+ * Copyright (C) 2023 Daniel Golle <daniel@makrotopia.org>
|
||||
+ * based on patch from Mingming Su <Mingming.Su@mediatek.com>
|
||||
+ */
|
||||
+#define MTK_RNG_DEV KBUILD_MODNAME
|
||||
+
|
||||
+#include <linux/arm-smccc.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/hw_random.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/soc/mediatek/mtk_sip_svc.h>
|
||||
+
|
||||
+#define MTK_SIP_KERNEL_GET_RND MTK_SIP_SMC_CMD(0x550)
|
||||
+
|
||||
+static int mtk_rng_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+ int retval = 0;
|
||||
+
|
||||
+ while (max >= sizeof(u32)) {
|
||||
+ arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0,
|
||||
+ &res);
|
||||
+ if (res.a0)
|
||||
+ break;
|
||||
+
|
||||
+ *(u32 *)buf = res.a1;
|
||||
+ retval += sizeof(u32);
|
||||
+ buf += sizeof(u32);
|
||||
+ max -= sizeof(u32);
|
||||
+ }
|
||||
+
|
||||
+ return retval || !wait ? retval : -EIO;
|
||||
+}
|
||||
+
|
||||
+static int mtk_rng_v2_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct hwrng *trng;
|
||||
+
|
||||
+ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
|
||||
+ if (!trng)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ trng->name = pdev->name;
|
||||
+ trng->read = mtk_rng_v2_read;
|
||||
+ trng->quality = 900;
|
||||
+
|
||||
+ return devm_hwrng_register(&pdev->dev, trng);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id mtk_rng_v2_match[] = {
|
||||
+ { .compatible = "mediatek,mt7981-rng" },
|
||||
+ { .compatible = "mediatek,mt7987-rng" },
|
||||
+ { .compatible = "mediatek,mt7988-rng" },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mtk_rng_v2_match);
|
||||
+
|
||||
+static struct platform_driver mtk_rng_v2_driver = {
|
||||
+ .probe = mtk_rng_v2_probe,
|
||||
+ .driver = {
|
||||
+ .name = KBUILD_MODNAME,
|
||||
+ .of_match_table = mtk_rng_v2_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(mtk_rng_v2_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Mediatek Random Number Generator Driver (v2/SMC)");
|
||||
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
From d211e2184d820207d14f5e8f84938c639875bf0d Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 3 Mar 2026 23:45:46 +0000
|
||||
Subject: [PATCH] hwrng: mtk - add support for hw access via SMCC
|
||||
|
||||
Newer versions of ARM TrustedFirmware-A on MediaTek's ARMv8 SoCs no longer
|
||||
allow accessing the TRNG from outside of the trusted firmware.
|
||||
Instead, a vendor-defined custom Secure Monitor Call can be used to
|
||||
acquire random bytes.
|
||||
Add support for newer SoCs (MT7981, MT7987, MT7988). On MT7986 the best bet
|
||||
is to test if firmware blocks direct access to the hwrng and if so, expect
|
||||
the SMCC interface to be usable.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/char/hw_random/mtk-rng.c | 128 ++++++++++++++++++++++++++-----
|
||||
1 file changed, 107 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/drivers/char/hw_random/mtk-rng.c
|
||||
+++ b/drivers/char/hw_random/mtk-rng.c
|
||||
@@ -3,6 +3,7 @@
|
||||
* Driver for Mediatek Hardware Random Number Generator
|
||||
*
|
||||
* Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
|
||||
+ * Copyright (C) 2026 Daniel Golle <daniel@makrotopia.org>
|
||||
*/
|
||||
#define MTK_RNG_DEV KBUILD_MODNAME
|
||||
|
||||
@@ -17,6 +18,8 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
+#include <linux/arm-smccc.h>
|
||||
+#include <linux/soc/mediatek/mtk_sip_svc.h>
|
||||
|
||||
/* Runtime PM autosuspend timeout: */
|
||||
#define RNG_AUTOSUSPEND_TIMEOUT 100
|
||||
@@ -30,6 +33,11 @@
|
||||
|
||||
#define RNG_DATA 0x08
|
||||
|
||||
+/* Driver feature flags */
|
||||
+#define MTK_RNG_SMC BIT(0)
|
||||
+
|
||||
+#define MTK_SIP_KERNEL_GET_RND MTK_SIP_SMC_CMD(0x550)
|
||||
+
|
||||
#define to_mtk_rng(p) container_of(p, struct mtk_rng, rng)
|
||||
|
||||
struct mtk_rng {
|
||||
@@ -37,6 +45,7 @@ struct mtk_rng {
|
||||
struct clk *clk;
|
||||
struct hwrng rng;
|
||||
struct device *dev;
|
||||
+ unsigned long flags;
|
||||
};
|
||||
|
||||
static int mtk_rng_init(struct hwrng *rng)
|
||||
@@ -104,6 +113,56 @@ static int mtk_rng_read(struct hwrng *rn
|
||||
return retval || !wait ? retval : -EIO;
|
||||
}
|
||||
|
||||
+static int mtk_rng_read_smc(struct hwrng *rng, void *buf, size_t max,
|
||||
+ bool wait)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+ int retval = 0;
|
||||
+
|
||||
+ while (max >= sizeof(u32)) {
|
||||
+ arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0,
|
||||
+ &res);
|
||||
+ if (res.a0)
|
||||
+ break;
|
||||
+
|
||||
+ *(u32 *)buf = res.a1;
|
||||
+ retval += sizeof(u32);
|
||||
+ buf += sizeof(u32);
|
||||
+ max -= sizeof(u32);
|
||||
+ }
|
||||
+
|
||||
+ return retval || !wait ? retval : -EIO;
|
||||
+}
|
||||
+
|
||||
+static bool mtk_rng_hw_accessible(struct mtk_rng *priv)
|
||||
+{
|
||||
+ u32 val;
|
||||
+ int err;
|
||||
+
|
||||
+ err = clk_prepare_enable(priv->clk);
|
||||
+ if (err)
|
||||
+ return false;
|
||||
+
|
||||
+ val = readl(priv->base + RNG_CTRL);
|
||||
+ val |= RNG_EN;
|
||||
+ writel(val, priv->base + RNG_CTRL);
|
||||
+
|
||||
+ val = readl(priv->base + RNG_CTRL);
|
||||
+
|
||||
+ if (val & RNG_EN) {
|
||||
+ /* HW is accessible, clean up: disable RNG and clock */
|
||||
+ writel(val & ~RNG_EN, priv->base + RNG_CTRL);
|
||||
+ clk_disable_unprepare(priv->clk);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If TF-A blocks direct access, the register reads back as 0.
|
||||
+ * Leave the clock enabled as TF-A's SMC handler needs it.
|
||||
+ */
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int mtk_rng_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@@ -115,23 +174,42 @@ static int mtk_rng_probe(struct platform
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
priv->rng.name = pdev->name;
|
||||
-#ifndef CONFIG_PM
|
||||
- priv->rng.init = mtk_rng_init;
|
||||
- priv->rng.cleanup = mtk_rng_cleanup;
|
||||
-#endif
|
||||
- priv->rng.read = mtk_rng_read;
|
||||
priv->rng.quality = 900;
|
||||
+ priv->flags = (unsigned long)device_get_match_data(&pdev->dev);
|
||||
|
||||
- priv->clk = devm_clk_get(&pdev->dev, "rng");
|
||||
- if (IS_ERR(priv->clk)) {
|
||||
- ret = PTR_ERR(priv->clk);
|
||||
- dev_err(&pdev->dev, "no clock for device: %d\n", ret);
|
||||
- return ret;
|
||||
+ if (!(priv->flags & MTK_RNG_SMC)) {
|
||||
+ priv->clk = devm_clk_get(&pdev->dev, "rng");
|
||||
+ if (IS_ERR(priv->clk)) {
|
||||
+ ret = PTR_ERR(priv->clk);
|
||||
+ dev_err(&pdev->dev, "no clock for device: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(priv->base))
|
||||
+ return PTR_ERR(priv->base);
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) &&
|
||||
+ of_device_is_compatible(pdev->dev.of_node,
|
||||
+ "mediatek,mt7986-rng") &&
|
||||
+ !mtk_rng_hw_accessible(priv)) {
|
||||
+ priv->flags |= MTK_RNG_SMC;
|
||||
+ dev_info(&pdev->dev,
|
||||
+ "HW RNG not MMIO accessible, using SMC\n");
|
||||
+ }
|
||||
}
|
||||
|
||||
- priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
- if (IS_ERR(priv->base))
|
||||
- return PTR_ERR(priv->base);
|
||||
+ if (priv->flags & MTK_RNG_SMC) {
|
||||
+ if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC))
|
||||
+ return -ENODEV;
|
||||
+ priv->rng.read = mtk_rng_read_smc;
|
||||
+ } else {
|
||||
+#ifndef CONFIG_PM
|
||||
+ priv->rng.init = mtk_rng_init;
|
||||
+ priv->rng.cleanup = mtk_rng_cleanup;
|
||||
+#endif
|
||||
+ priv->rng.read = mtk_rng_read;
|
||||
+ }
|
||||
|
||||
ret = devm_hwrng_register(&pdev->dev, &priv->rng);
|
||||
if (ret) {
|
||||
@@ -140,12 +218,15 @@ static int mtk_rng_probe(struct platform
|
||||
return ret;
|
||||
}
|
||||
|
||||
- dev_set_drvdata(&pdev->dev, priv);
|
||||
- pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT);
|
||||
- pm_runtime_use_autosuspend(&pdev->dev);
|
||||
- ret = devm_pm_runtime_enable(&pdev->dev);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ if (!(priv->flags & MTK_RNG_SMC)) {
|
||||
+ dev_set_drvdata(&pdev->dev, priv);
|
||||
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
|
||||
+ RNG_AUTOSUSPEND_TIMEOUT);
|
||||
+ pm_runtime_use_autosuspend(&pdev->dev);
|
||||
+ ret = devm_pm_runtime_enable(&pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
dev_info(&pdev->dev, "registered RNG driver\n");
|
||||
|
||||
@@ -182,8 +263,12 @@ static const struct dev_pm_ops mtk_rng_p
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct of_device_id mtk_rng_match[] = {
|
||||
- { .compatible = "mediatek,mt7986-rng" },
|
||||
{ .compatible = "mediatek,mt7623-rng" },
|
||||
+ { .compatible = "mediatek,mt7622-rng" },
|
||||
+ { .compatible = "mediatek,mt7981-rng", .data = (void *)MTK_RNG_SMC },
|
||||
+ { .compatible = "mediatek,mt7986-rng" },
|
||||
+ { .compatible = "mediatek,mt7987-rng", .data = (void *)MTK_RNG_SMC },
|
||||
+ { .compatible = "mediatek,mt7988-rng", .data = (void *)MTK_RNG_SMC },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk_rng_match);
|
||||
@@ -201,4 +286,5 @@ module_platform_driver(mtk_rng_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
|
||||
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
||||
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
Loading…
Add table
Reference in a new issue