[PATCH] hwrng: add support for picoxcell TRNG
Jamie Iles
jamie at jamieiles.com
Fri Jan 14 11:10:48 EST 2011
This driver adds support for the True Random Number Generator in
the Picochip PC3X3 and later devices.
Cc: Matt Mackall <mpm at selenic.com>
Cc: Herbert Xu <herbert at gondor.apana.org.au>
Signed-off-by: Jamie Iles <jamie at jamieiles.com>
---
ARCH_PICOXCELL machine support patches have been posted the ARM mailing
lists for review (with another revision to follow soon).
drivers/char/hw_random/Kconfig | 12 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/picoxcell-rng.c | 175 ++++++++++++++++++++++++++++++++
3 files changed, 188 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/hw_random/picoxcell-rng.c
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index d31483c..beecd1c 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -198,3 +198,15 @@ config HW_RANDOM_NOMADIK
module will be called nomadik-rng.
If unsure, say Y.
+
+config HW_RANDOM_PICOXCELL
+ tristate "Picochip picoXcell true random number generator support"
+ depends on HW_RANDOM && ARCH_PICOXCELL && PICOXCELL_PC3X3
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Picochip PC3x3 and later devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called picoxcell-rng.
+
+ If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 4273308..3db4eb8 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
+obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c
new file mode 100644
index 0000000..e750056
--- /dev/null
+++ b/drivers/char/hw_random/picoxcell-rng.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * All enquiries to support at picochip.com
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define DATA_REG_OFFSET 0x0200
+#define CSR_REG_OFFSET 0x0278
+#define CSR_OUT_EMPTY_MASK (1 << 24)
+#define TAI_REG_OFFSET 0x0380
+
+static void __iomem *rng_base;
+static struct clk *rng_clk;
+
+/*
+ * Get some random data from the random number generator. The hw_random core
+ * layer provides us with locking. We can't rely on data being word aligned
+ * though so we'll need to do a memcpy.
+ */
+static int picoxcell_trng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ u32 __iomem *csr = rng_base + CSR_REG_OFFSET;
+ int data_avail = !(__raw_readl(csr) & CSR_OUT_EMPTY_MASK);
+ u32 data;
+
+ if (!data_avail && !wait)
+ return 0;
+
+ /* Wait for some data to become available. */
+ while (!data_avail) {
+ data_avail = !(__raw_readl(csr) & CSR_OUT_EMPTY_MASK);
+ cpu_relax();
+ }
+
+ data = __raw_readl(rng_base + DATA_REG_OFFSET);
+ memcpy(buf, &data, min(max, sizeof(data)));
+
+ return sizeof(data);
+}
+
+static struct hwrng picoxcell_trng = {
+ .name = "picoxcell",
+ .read = picoxcell_trng_read,
+};
+
+/*
+ * Take the random number generator out of reset and make sure the interrupts
+ * are masked. We shouldn't need to get large amounts of random bytes so just
+ * poll the status register. The hardware generates 32 bits every 320ns so we
+ * shouldn't have to wait long enough to warrant waiting for an IRQ.
+ */
+static void picoxcell_trng_start(void)
+{
+ __raw_writel(0, rng_base + TAI_REG_OFFSET);
+ __raw_writel(0, rng_base + CSR_REG_OFFSET);
+}
+
+static int picoxcell_trng_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!mem) {
+ dev_warn(&pdev->dev, "no memory resource\n");
+ return -ENOMEM;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
+ "picoxcell_trng")) {
+ dev_warn(&pdev->dev, "unable to request io mem\n");
+ return -EBUSY;
+ }
+
+ rng_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!rng_base) {
+ dev_warn(&pdev->dev, "unable to remap io mem\n");
+ return -ENOMEM;
+ }
+
+ rng_clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rng_clk)) {
+ dev_warn(&pdev->dev, "no clk\n");
+ return PTR_ERR(rng_clk);
+ }
+
+ ret = clk_enable(rng_clk);
+ if (ret) {
+ dev_warn(&pdev->dev, "unable to enable clk\n");
+ goto err_enable;
+ }
+
+ picoxcell_trng_start();
+ ret = hwrng_register(&picoxcell_trng);
+ if (ret)
+ goto err_register;
+
+ dev_info(&pdev->dev, "pixoxcell random number generator active\n");
+
+ return 0;
+
+err_register:
+ clk_disable(rng_clk);
+err_enable:
+ clk_put(rng_clk);
+
+ return ret;
+}
+
+static int __devexit picoxcell_trng_remove(struct platform_device *pdev)
+{
+ hwrng_unregister(&picoxcell_trng);
+ clk_disable(rng_clk);
+ clk_put(rng_clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int picoxcell_trng_suspend(struct device *dev)
+{
+ clk_disable(rng_clk);
+
+ return 0;
+}
+
+static int picoxcell_trng_resume(struct device *dev)
+{
+ return clk_enable(rng_clk);
+}
+
+static const struct dev_pm_ops picoxcell_trng_pm_ops = {
+ .suspend = picoxcell_trng_suspend,
+ .resume = picoxcell_trng_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct platform_driver picoxcell_trng_driver = {
+ .probe = picoxcell_trng_probe,
+ .remove = __devexit_p(picoxcell_trng_remove),
+ .driver = {
+ .name = "picoxcell-trng",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &picoxcell_trng_pm_ops,
+#endif /* CONFIG_PM */
+ },
+};
+
+static int __init picoxcell_trng_init(void)
+{
+ return platform_driver_register(&picoxcell_trng_driver);
+}
+module_init(picoxcell_trng_init);
+
+static void __exit picoxcell_trng_exit(void)
+{
+ platform_driver_unregister(&picoxcell_trng_driver);
+}
+module_exit(picoxcell_trng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("Picochip picoXcell TRNG driver");
--
1.7.3.4
More information about the linux-arm-kernel
mailing list