Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc85b25e authored by Alessandro Rubini's avatar Alessandro Rubini Committed by Herbert Xu
Browse files

hwrng: nomadik - Add hardware RNG driver



The hardware random number generator by ST is used in both the Nomadik
8815 SoC and the U8500. It returns 16 bits every 400ns with automatic
delay if a read is issued too early. It depends on PLAT_NOMADIK.

Signed-off-by: default avatarAlessandro Rubini <rubini@unipv.it>
Acked-by: default avatarAndrea Gallo <andrea.gallo@stericsson.com>
Acked-by: default avatarMatt Mackall <mpm@selenic.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 55639353
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -186,3 +186,15 @@ config HW_RANDOM_MXC_RNGA
	  module will be called mxc-rnga.

	  If unsure, say Y.

config HW_RANDOM_NOMADIK
	tristate "ST-Ericsson Nomadik Random Number Generator support"
	depends on HW_RANDOM && PLAT_NOMADIK
	---help---
	  This driver provides kernel-side support for the Random Number
	  Generator hardware found on ST-Ericsson SoCs (8815 and 8500).

	  To compile this driver as a module, choose M here: the
	  module will be called nomadik-rng.

	  If unsure, say Y.
+1 −0
Original line number Diff line number Diff line
@@ -18,3 +18,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
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
+103 −0
Original line number Diff line number Diff line
/*
 * Nomadik RNG support
 *  Copyright 2009 Alessandro Rubini
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/hw_random.h>
#include <linux/io.h>

static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
	void __iomem *base = (void __iomem *)rng->priv;

	/*
	 * The register is 32 bits and gives 16 random bits (low half).
	 * A subsequent read will delay the core for 400ns, so we just read
	 * once and accept the very unlikely very small delay, even if wait==0.
	 */
	*(u16 *)data = __raw_readl(base + 8) & 0xffff;
	return 2;
}

/* we have at most one RNG per machine, granted */
static struct hwrng nmk_rng = {
	.name		= "nomadik",
	.read		= nmk_rng_read,
};

static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id)
{
	void __iomem *base;
	int ret;

	ret = amba_request_regions(dev, dev->dev.init_name);
	if (ret)
		return ret;
	ret = -ENOMEM;
	base = ioremap(dev->res.start, resource_size(&dev->res));
	if (!base)
		goto out_release;
	nmk_rng.priv = (unsigned long)base;
	ret = hwrng_register(&nmk_rng);
	if (ret)
		goto out_unmap;
	return 0;

out_unmap:
	iounmap(base);
out_release:
	amba_release_regions(dev);
	return ret;
}

static int nmk_rng_remove(struct amba_device *dev)
{
	void __iomem *base = (void __iomem *)nmk_rng.priv;
	hwrng_unregister(&nmk_rng);
	iounmap(base);
	amba_release_regions(dev);
	return 0;
}

static struct amba_id nmk_rng_ids[] = {
	{
		.id	= 0x000805e1,
		.mask	= 0x000fffff, /* top bits are rev and cfg: accept all */
	},
	{0, 0},
};

static struct amba_driver nmk_rng_driver = {
	.drv = {
		.owner = THIS_MODULE,
		.name = "rng",
		},
	.probe = nmk_rng_probe,
	.remove = nmk_rng_remove,
	.id_table = nmk_rng_ids,
};

static int __init nmk_rng_init(void)
{
	return amba_driver_register(&nmk_rng_driver);
}

static void __devexit nmk_rng_exit(void)
{
	amba_driver_unregister(&nmk_rng_driver);
}

module_init(nmk_rng_init);
module_exit(nmk_rng_exit);

MODULE_LICENSE("GPL");