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.yrjola@xxxxxxxxxxxxx> + * + * 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 *) ≈ + 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.rohar@xxxxxxxxx
Attachment:
signature.asc
Description: This is a digitally signed message part.