diff mbox series

[v4] crypto: hisilicon/trng - add support for HiSTB TRNG

Message ID 20230331101943.831347-1-mmyangfl@gmail.com (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series [v4] crypto: hisilicon/trng - add support for HiSTB TRNG | expand

Commit Message

David Yang March 31, 2023, 10:19 a.m. UTC
HiSTB TRNG are found on some HiSilicon STB SoCs.

Signed-off-by: David Yang <mmyangfl@gmail.com>
---
v2: fix typo
v3: add option for post process depth, adjust timeout
v4: do not case to __iomem, as requested
 drivers/crypto/hisilicon/Kconfig         |   7 +
 drivers/crypto/hisilicon/Makefile        |   2 +-
 drivers/crypto/hisilicon/trng/Makefile   |   3 +
 drivers/crypto/hisilicon/trng/trng-stb.c | 186 +++++++++++++++++++++++
 4 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/hisilicon/trng/trng-stb.c

Comments

Herbert Xu April 1, 2023, 8:06 a.m. UTC | #1
On Fri, Mar 31, 2023 at 06:19:34PM +0800, David Yang wrote:
>
> +	struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;

Plesae don't use rng->priv at all.  We're trying to phase it
out because it encourages horrible casting like this.

Please follow the model used in the meson driver.

Thanks,
David Yang April 1, 2023, 2:05 p.m. UTC | #2
Herbert Xu <herbert@gondor.apana.org.au> 于2023年4月1日周六 16:07写道:
>
> On Fri, Mar 31, 2023 at 06:19:34PM +0800, David Yang wrote:
> >
> > +     struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;
>
> Plesae don't use rng->priv at all.  We're trying to phase it
> out because it encourages horrible casting like this.
>
> Please follow the model used in the meson driver.
>
> Thanks,
> --
> Email: Herbert Xu <herbert@gondor.apana.org.au>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

Which meson driver? I didn't find any rng module under amlogic/ dir.
Herbert Xu April 3, 2023, 4:18 a.m. UTC | #3
On Sat, Apr 01, 2023 at 10:05:25PM +0800, Yangfl wrote:
>
> Which meson driver? I didn't find any rng module under amlogic/ dir.

drivers/char/hw_random/meson-rng.c 

Cheers,
diff mbox series

Patch

diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
index 4137a8bf131f..e8690c223584 100644
--- a/drivers/crypto/hisilicon/Kconfig
+++ b/drivers/crypto/hisilicon/Kconfig
@@ -82,3 +82,10 @@  config CRYPTO_DEV_HISI_TRNG
 	select CRYPTO_RNG
 	help
 	  Support for HiSilicon TRNG Driver.
+
+config CRYPTO_DEV_HISTB_TRNG
+	tristate "Support for HiSTB TRNG Driver"
+	depends on ARCH_HISI || COMPILE_TEST
+	select HW_RANDOM
+	help
+	  Support for HiSTB TRNG Driver.
diff --git a/drivers/crypto/hisilicon/Makefile b/drivers/crypto/hisilicon/Makefile
index 8595a5a5d228..fc51e0edec69 100644
--- a/drivers/crypto/hisilicon/Makefile
+++ b/drivers/crypto/hisilicon/Makefile
@@ -5,4 +5,4 @@  obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
 obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
 hisi_qm-objs = qm.o sgl.o debugfs.o
 obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
-obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += trng/
+obj-y += trng/
diff --git a/drivers/crypto/hisilicon/trng/Makefile b/drivers/crypto/hisilicon/trng/Makefile
index d909079f351c..cf20b057c66b 100644
--- a/drivers/crypto/hisilicon/trng/Makefile
+++ b/drivers/crypto/hisilicon/trng/Makefile
@@ -1,2 +1,5 @@ 
 obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += hisi-trng-v2.o
 hisi-trng-v2-objs = trng.o
+
+obj-$(CONFIG_CRYPTO_DEV_HISTB_TRNG) += histb-trng.o
+histb-trng-objs += trng-stb.o
diff --git a/drivers/crypto/hisilicon/trng/trng-stb.c b/drivers/crypto/hisilicon/trng/trng-stb.c
new file mode 100644
index 000000000000..239f3451c2a1
--- /dev/null
+++ b/drivers/crypto/hisilicon/trng/trng-stb.c
@@ -0,0 +1,186 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Device driver for True RNG in HiSTB SoCs
+ *
+ * Copyright (c) 2023 David Yang
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#define HISTB_TRNG_CTRL		0x0
+#define  RNG_SOURCE			GENMASK(1, 0)
+#define  DROP_ENABLE			BIT(5)
+#define  POST_PROCESS_ENABLE		BIT(7)
+#define  POST_PROCESS_DEPTH		GENMASK(15, 8)
+#define HISTB_TRNG_NUMBER	0x4
+#define HISTB_TRNG_STAT		0x8
+#define  DATA_COUNT			GENMASK(2, 0)	/* max 4 */
+
+struct histb_trng_priv {
+	void __iomem *base;
+};
+
+/*
+ * Observed:
+ * depth = 1 -> ~1ms
+ * depth = 255 -> ~16ms
+ */
+static int histb_trng_wait(struct hwrng *rng)
+{
+	struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;
+	void __iomem *base = priv->base;
+	u32 val;
+
+	return readl_relaxed_poll_timeout(base + HISTB_TRNG_STAT,
+					  val, val & DATA_COUNT,
+					  1000, 30 * 1000);
+}
+
+static void histb_trng_init(struct hwrng *rng, unsigned int depth)
+{
+	struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;
+	void __iomem *base = priv->base;
+	u32 val;
+
+	val = readl_relaxed(base + HISTB_TRNG_CTRL);
+
+	val &= ~RNG_SOURCE;
+	val |= 2;
+
+	val &= ~POST_PROCESS_DEPTH;
+	val |= min(depth, 0xffu) << 8;
+
+	val |= POST_PROCESS_ENABLE;
+	val |= DROP_ENABLE;
+
+	writel_relaxed(val, base + HISTB_TRNG_CTRL);
+}
+
+static int histb_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;
+	void __iomem *base = priv->base;
+	size_t i;
+
+	for (i = 0; i < max; i += sizeof(u32)) {
+		if (!(readl_relaxed(base + HISTB_TRNG_STAT) & DATA_COUNT)) {
+			if (!wait)
+				break;
+			if (histb_trng_wait(rng)) {
+				pr_err("failed to generate random number, generated %zu\n",
+				       i);
+				if (i)
+					break;
+				return -ETIMEDOUT;
+			}
+		}
+		*(u32 *) (data + i) = readl_relaxed(base + HISTB_TRNG_NUMBER);
+	}
+
+	return i;
+}
+
+static unsigned int histb_trng_get_depth(struct hwrng *rng)
+{
+	struct histb_trng_priv *priv = (struct histb_trng_priv *) rng->priv;
+	void __iomem *base = priv->base;
+	u32 val = readl_relaxed(base + HISTB_TRNG_CTRL);
+
+	return (val & POST_PROCESS_DEPTH) >> 8;
+}
+
+static ssize_t
+depth_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hwrng *rng = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", histb_trng_get_depth(rng));
+}
+
+static ssize_t
+depth_store(struct device *dev, struct device_attribute *attr,
+	    const char *buf, size_t count)
+{
+	struct hwrng *rng = dev_get_drvdata(dev);
+	unsigned int depth;
+
+	if (kstrtouint(buf, 0, &depth))
+		return -ERANGE;
+
+	histb_trng_init(rng, depth);
+	return count;
+}
+
+static DEVICE_ATTR_RW(depth);
+
+static struct attribute *histb_trng_attrs[] = {
+	&dev_attr_depth.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(histb_trng);
+
+static int histb_trng_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct hwrng *rng;
+	struct histb_trng_priv *priv;
+	int ret;
+
+	rng = devm_kzalloc(dev, sizeof(*rng), GFP_KERNEL);
+	if (!rng)
+		return -ENOMEM;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return -ENOMEM;
+
+	rng->priv = (unsigned long) priv;
+
+	histb_trng_init(rng, 144);
+	if (histb_trng_wait(rng))
+		return -ENODEV;
+
+	rng->name = KBUILD_MODNAME;
+	rng->read = histb_trng_read;
+
+	ret = devm_hwrng_register(dev, rng);
+	if (ret) {
+		dev_err(dev, "failed to register %s (%d)\n", rng->name, ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, rng);
+	dev_set_drvdata(dev, rng);
+	return 0;
+}
+
+static const struct of_device_id histb_trng_of_match[] = {
+	{ .compatible = "hisilicon,histb-trng", },
+	{ }
+};
+
+static struct platform_driver histb_trng_driver = {
+	.probe = histb_trng_probe,
+	.driver = {
+		.name = "histb-trng",
+		.of_match_table = histb_trng_of_match,
+		.dev_groups = histb_trng_groups,
+	},
+};
+
+module_platform_driver(histb_trng_driver);
+
+MODULE_DESCRIPTION("HiSTB True RNG");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("David Yang <mmyangfl@gmail.com>");