[PATCH linux dev-4.13 v1 2/2] hw_random: npcm: add NPCM7xx random number generator
Tomer Maimon
tmaimon77 at gmail.com
Thu Jan 4 20:51:46 AEDT 2018
Add Nuvoton BMC NPCM7xx random number generator driver.
Signed-off-by: Tomer Maimon <tmaimon77 at gmail.com>
---
drivers/char/hw_random/Kconfig | 13 +++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/npcm7xx-rng.c | 203 +++++++++++++++++++++++++++++++++++
3 files changed, 217 insertions(+)
create mode 100644 drivers/char/hw_random/npcm7xx-rng.c
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 1b223c32a8ae..e7ba0cb04744 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -180,6 +180,19 @@ config HW_RANDOM_OMAP
If unsure, say Y.
+config HW_RANDOM_NPCM7XX
+ tristate "NPCM7XX Random Number Generator support"
+ depends on HW_RANDOM && ARCH_NPCM7XX
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on npcm7xx processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called npcm7xx-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_OMAP3_ROM
tristate "OMAP3 ROM Random Number Generator support"
depends on ARCH_OMAP3
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b085975ec1d2..c612f1a4bd76 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -37,3 +37,4 @@ 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_S390) += s390-trng.o
+obj-$(CONFIG_HW_RANDOM_NPCM7XX) += npcm7xx-rng.o
diff --git a/drivers/char/hw_random/npcm7xx-rng.c b/drivers/char/hw_random/npcm7xx-rng.c
new file mode 100644
index 000000000000..b881e61c5a14
--- /dev/null
+++ b/drivers/char/hw_random/npcm7xx-rng.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2014-2017 Nuvoton Technology corporation.
+ *
+ * Released under the GPLv2 only.
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/delay.h>
+#include <linux/of_irq.h>
+
+#define RNGCS_REG 0x00 /* Control and status register */
+#define RNGD_REG 0x04 /* DATA register */
+#define RNGTST_REG 0x08 /* TEST register */
+
+#define RNG_CLK_SET (0x06 << 2) /* 20-25 MHz */
+#define RNG_DATA_VALID (0x01 << 1)
+#define RNG_ENABLE 0x01
+
+#define RNG_DEBUG
+
+static void __iomem *rng_base;
+static struct platform_device *rng_dev;
+
+static inline u32 npcm750_rng_read_reg(int reg)
+{
+ return __raw_readb(rng_base + reg);
+}
+
+static inline void npcm750_rng_write_reg(int reg, u32 val)
+{
+ __raw_writeb(val, rng_base + reg);
+}
+
+static int npcm750_rng_data_present(struct hwrng *rng, int wait)
+{
+ int data, i;
+
+ for (i = 0; i < 20; i++) {
+ data = (npcm750_rng_read_reg(RNGCS_REG) & RNG_DATA_VALID) ?
+ 1 : 0;
+ if (data || !wait)
+ break;
+ /* RNG produces data fast enough (2+ MBit/sec, even
+ * during "rngtest" loads, that these delays don't
+ * seem to trigger. We *could* use the RNG IRQ, but
+ * that'd be higher overhead ... so why bother?
+ */
+ udelay(10);
+ }
+
+ return data;
+}
+
+static int npcm750_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ *data = npcm750_rng_read_reg(RNGD_REG);
+
+ return 1;
+}
+
+static struct hwrng npcm750_rng_ops = {
+ .name = "npcm750",
+ .data_present = npcm750_rng_data_present,
+ .data_read = npcm750_rng_data_read,
+};
+
+static int npcm750_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ /*
+ * A bit ugly, and it will never actually happen but there can
+ * be only one RNG and this catches any bork
+ */
+ if (rng_dev)
+ return -EBUSY;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ ret = -ENOENT;
+ goto err_region;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ ret = -EBUSY;
+ goto err_region;
+ }
+
+ dev_set_drvdata(&pdev->dev, res);
+ rng_base = ioremap(res->start, resource_size(res));
+ if (!rng_base) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ret = hwrng_register(&npcm750_rng_ops);
+ if (ret)
+ goto err_register;
+
+ npcm750_rng_write_reg(RNGTST_REG, 0x02);
+ npcm750_rng_write_reg(RNGCS_REG, RNG_CLK_SET | RNG_ENABLE);
+
+ rng_dev = pdev;
+
+#ifdef RNG_DEBUG
+ mdelay(10);
+ pr_info("RNG-Random Number Generator 0x%x\n",
+ npcm750_rng_read_reg(RNGD_REG));
+#else
+ pr_info("RNG-Random Number Generator\n");
+#endif
+
+ return 0;
+
+err_register:
+ iounmap(rng_base);
+ rng_base = NULL;
+err_ioremap:
+ release_mem_region(res->start, resource_size(res));
+err_region:
+
+ return ret;
+}
+
+static int __exit npcm750_rng_remove(struct platform_device *pdev)
+{
+ struct resource *res = dev_get_drvdata(&pdev->dev);
+
+ hwrng_unregister(&npcm750_rng_ops);
+ npcm750_rng_write_reg(RNGCS_REG, 0x0);
+ iounmap(rng_base);
+ release_mem_region(res->start, resource_size(res));
+
+ rng_base = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int npcm750_rng_suspend(struct platform_device *pdev,
+ pm_message_t message)
+{
+ u32 val;
+
+ val = npcm750_rng_read_reg(RNGCS_REG);
+ val &= 0xfffffffe;
+ npcm750_rng_write_reg(RNGCS_REG, val);
+ return 0;
+}
+
+static int npcm750_rng_resume(struct platform_device *pdev)
+{
+ u32 val;
+
+ val = npcm750_rng_read_reg(RNGCS_REG);
+ val |= 0x00000001;
+ npcm750_rng_write_reg(RNGCS_REG, val);
+ return 0;
+}
+
+#else
+
+#define npcm750_rng_suspend NULL
+#define npcm750_rng_resume NULL
+
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:npcm750-rng");
+
+static const struct of_device_id rng_dt_id[] = {
+ { .compatible = "nuvoton,npcm750-rng", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rng_dt_id);
+
+static struct platform_driver npcm750_rng_driver = {
+ .driver = {
+ .name = "npcm750-rng",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rng_dt_id),
+ },
+ .probe = npcm750_rng_probe,
+ .remove = __exit_p(npcm750_rng_remove),
+ .suspend = npcm750_rng_suspend,
+ .resume = npcm750_rng_resume
+};
+
+module_platform_driver(npcm750_rng_driver);
+
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");
--
2.14.1
More information about the openbmc
mailing list