| 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(-) |
| |
| diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c |
| index a8bd06da7..75fca4cef 100644 |
| --- 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,41 +113,74 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) |
| 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) |
| { |
| struct resource *res; |
| int ret; |
| struct mtk_rng *priv; |
| |
| - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| - if (!res) { |
| - dev_err(&pdev->dev, "no iomem resource\n"); |
| - return -ENXIO; |
| - } |
| - |
| priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
| if (!priv) |
| return -ENOMEM; |
| |
| - priv->rng.name = pdev->name; |
| + priv->soc = of_device_get_match_data(&pdev->dev); |
| + if (priv->soc->rng_version == 1) { |
| + 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_ioremap_resource(&pdev->dev, res); |
| - 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) { |
| @@ -146,11 +189,6 @@ static int mtk_rng_probe(struct platform_device *pdev) |
| 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; |
| @@ -185,9 +223,22 @@ static const struct dev_pm_ops mtk_rng_pm_ops = { |
| #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); |
| -- |
| 2.18.0 |
| |