JZ4780 SoC pseudo random number generator driver using crypto framework.
Adding a delay before reading RNG data and disabling RNG after reading
data was suggested by Jeffery Walton.
Tested-by: Mathieu Malaterre
Suggested-by: Jeffrey Walton
Signed-off-by: PrasannaKumar Muralidharan
---
drivers/crypto/Kconfig | 19 +
drivers/crypto/Makefile | 1 +
drivers/crypto/jz4780-rng.c | 173
3 files changed, 193 insertions(+)
create mode 100644 drivers/crypto/jz4780-rng.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 8fa7e72..8263622 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -614,6 +614,25 @@ config CRYPTO_DEV_IMGTEC_HASH
hardware hash accelerator. Supporting MD5/SHA1/SHA224/SHA256
hashing algorithms.
+config CRYPTO_DEV_JZ4780_RNG
+ tristate "JZ4780 HW pseudo random number generator support"
+ depends on MACH_JZ4780 || COMPILE_TEST
+ depends on HAS_IOMEM
+ select CRYPTO_RNG
+ select REGMAP
+ select SYSCON
+ select MFD_SYSCON
+ ---help---
+ This driver provides kernel-side support through the
+ cryptographic API for the pseudo random number generator
+ hardware found in ingenic JZ4780 and X1000 SoC. MIPS
+ Creator CI20 uses JZ4780 SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jz4780-rng.
+
+ If unsure, say Y.
+
config CRYPTO_DEV_SUN4I_SS
tristate "Support for Allwinner Security System cryptographic
accelerator"
depends on ARCH_SUNXI && !64BIT
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index b12eb3c..3a3d970 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
+obj-$(CONFIG_CRYPTO_DEV_JZ4780_RNG) += jz4780-rng.o
obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/
obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mediatek/
diff --git a/drivers/crypto/jz4780-rng.c b/drivers/crypto/jz4780-rng.c
new file mode 100644
index 000..a03f2a0
--- /dev/null
+++ b/drivers/crypto/jz4780-rng.c
@@ -0,0 +1,173 @@
+/*
+ * jz4780-rng.c - Random Number Generator driver for the jz4780
+ *
+ * Copyright (c) 2017 PrasannaKumar Muralidharan
+ *
+ * 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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#define REG_RNG_CTRL 0xD8
+#define REG_RNG_DATA 0xDC
+
+/* Context for crypto */
+struct jz4780_rng_ctx {
+ struct jz4780_rng *rng;
+};
+
+/* Device associated memory */
+struct jz4780_rng {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static struct jz4780_rng *jz4780_rng;
+
+static int jz4780_rng_readl(struct jz4780_rng *rng, u32 offset)
+{
+ u32 val = 0;
+ int ret;
+
+ ret = regmap_read(rng->regmap, offset, );
+ if (!ret)
+ return val;
+
+ return ret;
+}
+
+static int jz4780_rng_writel(struct jz4780_rng *rng, u32 val, u32 offset)
+{
+ return regmap_write(rng->regmap, offset, val);
+}
+
+static int jz4780_rng_generate(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int dlen)
+{
+ struct jz4780_rng_ctx *ctx = crypto_rng_ctx(tfm);
+ struct jz4780_rng *rng = ctx->rng;
+ u32 data;
+
+ /*
+* JZ4780 Programmers manual says the RNG should not run continuously
+* for more than 1s. So enable RNG, read data and disable it.
+* NOTE: No issue was observed with MIPS creator CI20 board even when
+* RNG ran continuously for longer periods. This is just a precaution.
+*
+* A delay is required so that the current RNG data is not bit shifted
+* version of previous RNG data which could happen if random data is
+* read continuously from this device.
+*/
+ jz4780_rng_writel(rng, 1, REG_RNG_CTRL);
+ do {
+ data = jz4780_rng_readl(rng, REG_RNG_DATA);
+ memcpy((void *)dst, (void *), 4);
+ dlen -= 4;
+ dst += 4;
+ udelay(20);
+ } while (dlen >= 4);
+
+ if (dlen > 0) {
+