From ae5611b1b7a857edb3d9c8e900b550c76f7c236e Mon Sep 17 00:00:00 2001
From: "Mingming.Su" <Mingming.Su@mediatek.com>
Date: Fri, 17 Dec 2021 20:27:34 +0800
Subject: [PATCH] Add trngv2 driver support

---
 drivers/char/hw_random/mtk-rng.c | 105 +++++++++++++++++++++++--------
 1 file changed, 78 insertions(+), 27 deletions(-)

--- a/drivers/char/hw_random/mtk-rng.c
+++ b/drivers/char/hw_random/mtk-rng.c
@@ -6,6 +6,7 @@
  */
 #define MTK_RNG_DEV KBUILD_MODNAME
 
+#include <linux/arm-smccc.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -15,8 +16,12 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/soc/mediatek/mtk_sip_svc.h>
+
+#define MTK_SIP_KERNEL_GET_RND		MTK_SIP_SMC_CMD(0x550)
 
 /* Runtime PM autosuspend timeout: */
 #define RNG_AUTOSUSPEND_TIMEOUT		100
@@ -32,10 +37,15 @@
 
 #define to_mtk_rng(p)	container_of(p, struct mtk_rng, rng)
 
+struct mtk_rng_of_data{
+	unsigned int rng_version;
+};
+
 struct mtk_rng {
 	void __iomem *base;
 	struct clk *clk;
 	struct hwrng rng;
+	const struct mtk_rng_of_data *soc;
 };
 
 static int mtk_rng_init(struct hwrng *rng)
@@ -103,6 +113,26 @@ static int mtk_rng_read(struct hwrng *rn
 	return retval || !wait ? retval : -EIO;
 }
 
+static int mtk_rngv2_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_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -112,25 +142,43 @@ static int mtk_rng_probe(struct platform
 	if (!priv)
 		return -ENOMEM;
 
-	priv->rng.name = pdev->name;
+	priv->soc = of_device_get_match_data(&pdev->dev);
+	if (priv->soc->rng_version == 1) {
+		struct resource  *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res) {
+			dev_err(&pdev->dev, "no iomem resource\n");
+			return -ENXIO;
+		}
+
+		priv->base = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(priv->base))
+			return PTR_ERR(priv->base);
+
+		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;
+		}
+
 #ifndef CONFIG_PM
-	priv->rng.init = mtk_rng_init;
-	priv->rng.cleanup = mtk_rng_cleanup;
+		priv->rng.init = mtk_rng_init;
+		priv->rng.cleanup = mtk_rng_cleanup;
 #endif
-	priv->rng.read = mtk_rng_read;
+		priv->rng.read = mtk_rng_read;
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+						 RNG_AUTOSUSPEND_TIMEOUT);
+		pm_runtime_use_autosuspend(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	} else {
+		priv->rng.read = mtk_rngv2_read;
+	}
+
+	priv->rng.name = pdev->name;
 	priv->rng.priv = (unsigned long)&pdev->dev;
 	priv->rng.quality = 900;
 
-	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);
+	dev_set_drvdata(&pdev->dev, priv);
 
 	ret = devm_hwrng_register(&pdev->dev, &priv->rng);
 	if (ret) {
@@ -139,11 +187,6 @@ 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);
-	pm_runtime_enable(&pdev->dev);
-
 	dev_info(&pdev->dev, "registered RNG driver\n");
 
 	return 0;
@@ -178,9 +221,22 @@ static const struct dev_pm_ops mtk_rng_p
 #define MTK_RNG_PM_OPS NULL
 #endif	/* CONFIG_PM */
 
+static const struct mtk_rng_of_data mt7981_rng_data = {
+	.rng_version = 2,
+};
+
+static const struct mtk_rng_of_data mt7986_rng_data = {
+	.rng_version = 1,
+};
+
+static const struct mtk_rng_of_data mt7623_rng_data = {
+	.rng_version = 1,
+};
+
 static const struct of_device_id mtk_rng_match[] = {
-	{ .compatible = "mediatek,mt7986-rng" },
-	{ .compatible = "mediatek,mt7623-rng" },
+	{ .compatible = "mediatek,mt7981-rng", .data = &mt7981_rng_data },
+	{ .compatible = "mediatek,mt7986-rng", .data = &mt7986_rng_data },
+	{ .compatible = "mediatek,mt7623-rng", .data = &mt7623_rng_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, mtk_rng_match);
