This driver provides kernel-side support for the Random Number
Generator hardware found on OMAP34xx processors.

This driver is included in Maemo 2.6.28 kernel used on Nokia N900.

I fixed driver to work with 3.8 kernel and added platform_driver
code to autoload it on omap3 devices.

diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 626f3ea..48e40f3 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -446,6 +446,18 @@ static void omap_init_mcspi(void)
 static inline void omap_init_mcspi(void) {}
 #endif
 
+static struct platform_device omap3_rom_rng_device = {
+       .name           = "omap3-rom-rng",
+       .id             = -1,
+};
+
+static void omap_init_rom_rng(void)
+{
+       if (!cpu_is_omap34xx() || omap_type() == OMAP2_DEVICE_TYPE_GP)
+               return;
+       platform_device_register(&omap3_rom_rng_device);
+}
+
 /**
  * omap_init_rng - bind the RNG hwmod to the RNG omap_device
  *
@@ -727,6 +739,7 @@ static int __init omap2_init_devices(void)
        }
        omap_init_sti();
        omap_init_rng();
+       omap_init_rom_rng();
        omap_init_sham();
        omap_init_aes();
        omap_init_vout();
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index c5a0262..2d51db6 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -153,6 +153,19 @@ config HW_RANDOM_OMAP
 
          If unsure, say Y.
 
+config HW_RANDOM_OMAP3_ROM
+       tristate "OMAP3 ROM Random Number Generator support"
+       depends on HW_RANDOM && ARCH_OMAP3
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on OMAP34xx processors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called omap3-rom-rng.
+
+         If unsure, say Y.
+
 config HW_RANDOM_OCTEON
        tristate "Octeon Random Number Generator support"
        depends on HW_RANDOM && CPU_CAVIUM_OCTEON
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 1fd7eec..d227cd6 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -15,6 +15,8 @@ n2-rng-y := n2-drv.o n2-asm.o
 obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
 obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
+omap3-rom-rng-y := omap3-rom-drv.o omap3-rom-asm.o
 obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
 obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
 obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
diff --git a/drivers/char/hw_random/omap3-rom-asm.S 
b/drivers/char/hw_random/omap3-rom-asm.S
new file mode 100644
index 0000000..ce82e16
--- /dev/null
+++ b/drivers/char/hw_random/omap3-rom-asm.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(omap3_rng_call_rom_asm)
+       .arch_extension sec
+       stmfd   sp!, {r4-r12, lr}
+       stmfd   sp!, {r0-r3}
+       bl      v7_flush_dcache_all
+       ldmfd   sp!, {r0-r3}
+       mov     r6, #0xff
+       mov     r12, r0
+       smc     #1
+       mov     r12, r0
+       bl      v7_flush_dcache_all
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 0
+       mov     r0, r12
+       ldmfd   sp!, {r4-r12, pc}
diff --git a/drivers/char/hw_random/omap3-rom-drv.c 
b/drivers/char/hw_random/omap3-rom-drv.c
new file mode 100644
index 0000000..4e2c0ff
--- /dev/null
+++ b/drivers/char/hw_random/omap3-rom-drv.c
@@ -0,0 +1,167 @@
+/*
+ * omap3-rom-drv.c - RNG driver for TI OMAP3 CPU family
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrj...@solidboot.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/hw_random.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include "../../../arch/arm/mach-omap2/soc.h"
+
+#define SEC_HAL_RNG_GENERATE           29
+#define RNG_RESET                      0x01
+#define RNG_GEN_PRNG_HW_INIT           0x02
+#define RNG_GEN_HW                     0x08
+
+static const char *omap3_rom_rng_name = "OMAP3 ROM RNG";
+
+extern u32 omap3_rng_call_rom_asm(u32 id, u32 proc, u32 flags, u32 va_ptr);
+
+static int call_sec_rom(u32 appl_id, u32 proc_id, u32 flag, ...)
+{
+       va_list ap;
+       u32 ret;
+       u32 val;
+
+       va_start(ap, flag);
+       val = *(u32 *) &ap;
+       local_irq_disable();
+       local_fiq_disable();
+       ret = omap3_rng_call_rom_asm(appl_id, proc_id, flag,
+                                    (u32) virt_to_phys((void *) val));
+       local_fiq_enable();
+       local_irq_enable();
+       va_end(ap);
+
+       return ret;
+}
+
+static struct timer_list idle_timer;
+static int rng_idle;
+static struct clk *rng_clk;
+
+static void omap3_rom_idle_rng(unsigned long data)
+{
+       int r;
+
+       r = call_sec_rom(SEC_HAL_RNG_GENERATE, 0, 0, 3, NULL, 0,
+                        RNG_RESET);
+       if (r != 0) {
+               printk(KERN_ERR "%s: reset failed: %d\n",
+                      omap3_rom_rng_name, r);
+               return;
+       }
+       clk_disable_unprepare(rng_clk);
+       rng_idle = 1;
+}
+
+static int omap3_rom_get_random(void *buf, unsigned int count)
+{
+       u32 r;
+       u32 ptr;
+
+       del_timer_sync(&idle_timer);
+       if (rng_idle) {
+               clk_prepare_enable(rng_clk);
+               r = call_sec_rom(SEC_HAL_RNG_GENERATE, 0, 0, 3, NULL, 0,
+                                RNG_GEN_PRNG_HW_INIT);
+               if (r != 0) {
+                       clk_disable_unprepare(rng_clk);
+                       printk(KERN_ERR "%s: HW init failed: %d\n",
+                              omap3_rom_rng_name, r);
+                       return -EIO;
+               }
+               rng_idle = 0;
+       }
+
+       ptr = virt_to_phys(buf);
+       r = call_sec_rom(SEC_HAL_RNG_GENERATE, 0, 0, 3, ptr,
+                        count, RNG_GEN_HW);
+       mod_timer(&idle_timer, jiffies + msecs_to_jiffies(500));
+       if (r != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int omap3_rom_rng_data_present(struct hwrng *rng, int wait)
+{
+       return 1;
+}
+
+static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       int r;
+
+       r = omap3_rom_get_random(data, 4);
+       if (r < 0)
+               return r;
+       return 4;
+}
+
+static struct hwrng omap3_rom_rng_ops = {
+       .name           = "omap3-rom",
+       .data_present   = omap3_rom_rng_data_present,
+       .data_read      = omap3_rom_rng_data_read,
+};
+
+static int omap3_rom_rng_probe(struct platform_device *pdev)
+{
+       printk(KERN_INFO "%s: initializing\n", omap3_rom_rng_name);
+       if (!cpu_is_omap34xx()) {
+               printk(KERN_ERR "%s: currently supports only OMAP34xx CPUs\n",
+                      omap3_rom_rng_name);
+               return -ENODEV;
+       }
+       if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
+               printk(KERN_ERR "%s: GP OMAPs not supported\n",
+                      omap3_rom_rng_name);
+               return -ENODEV;
+       }
+
+       setup_timer(&idle_timer, omap3_rom_idle_rng, 0);
+       rng_clk = clk_get_sys("omap_rng", "ick");
+       if (IS_ERR(rng_clk)) {
+               printk(KERN_ERR "%s: unable to get RNG clock\n",
+                      omap3_rom_rng_name);
+               return IS_ERR(rng_clk);
+       }
+
+       /* Leave the RNG in reset state. */
+       clk_prepare_enable(rng_clk);
+       omap3_rom_idle_rng(0);
+
+       return hwrng_register(&omap3_rom_rng_ops);
+}
+
+static int omap3_rom_rng_remove(struct platform_device *pdev)
+{
+       hwrng_unregister(&omap3_rom_rng_ops);
+       return 0;
+}
+
+static struct platform_driver omap3_rom_rng_driver = {
+       .driver = {
+               .name           = "omap3-rom-rng",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = omap3_rom_rng_probe,
+       .remove         = omap3_rom_rng_remove,
+};
+
+module_platform_driver(omap3_rom_rng_driver);
+
+MODULE_ALIAS("platform:omap3-rom-rng");
+MODULE_AUTHOR("Juha Yrjola");
+MODULE_LICENSE("GPL");

-- 
Pali Rohár
pali.ro...@gmail.com

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to