]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
mediatek: replace downstream TRNGv2 driver 22266/head
authorDaniel Golle <daniel@makrotopia.org>
Wed, 4 Mar 2026 01:18:08 +0000 (01:18 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 5 Mar 2026 02:26:41 +0000 (02:26 +0000)
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>
target/linux/mediatek/filogic/config-6.12
target/linux/mediatek/mt7622/config-6.12
target/linux/mediatek/mt7629/config-6.12
target/linux/mediatek/patches-6.12/051-v6.16-hwrng-mtk-Add-struct-device-pointer-to-device-contex.patch [new file with mode: 0644]
target/linux/mediatek/patches-6.12/320-hwrng-add-driver-for-MediaTek-TRNG-SMC.patch [deleted file]
target/linux/mediatek/patches-6.12/320-hwrng-mtk-add-support-for-hw-access-via-SMCC.patch [new file with mode: 0644]

index a6f4ea3d1638d007649937be138c4ceb745f2fe4..9174ffb222f2878b4f30aea6b8640f3216864e66 100644 (file)
@@ -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
index 1b8f94ea679378a7f2d9e99a439ff8813f646327..e6f491869242eb4c1df3d1aba57218ad4ef77f77 100644 (file)
@@ -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
index f54814b8d270cb7555879f114c6f62ff1896dd31..bf657caf5b3a049a126e4212f2e9144a1c7541fa 100644 (file)
@@ -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=""
diff --git a/target/linux/mediatek/patches-6.12/051-v6.16-hwrng-mtk-Add-struct-device-pointer-to-device-contex.patch b/target/linux/mediatek/patches-6.12/051-v6.16-hwrng-mtk-Add-struct-device-pointer-to-device-contex.patch
new file mode 100644 (file)
index 0000000..70c771d
--- /dev/null
@@ -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");
diff --git a/target/linux/mediatek/patches-6.12/320-hwrng-add-driver-for-MediaTek-TRNG-SMC.patch b/target/linux/mediatek/patches-6.12/320-hwrng-add-driver-for-MediaTek-TRNG-SMC.patch
deleted file mode 100644 (file)
index 3d7ca7c..0000000
+++ /dev/null
@@ -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");
diff --git a/target/linux/mediatek/patches-6.12/320-hwrng-mtk-add-support-for-hw-access-via-SMCC.patch b/target/linux/mediatek/patches-6.12/320-hwrng-mtk-add-support-for-hw-access-via-SMCC.patch
new file mode 100644 (file)
index 0000000..9bd9d0a
--- /dev/null
@@ -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");