forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hwrng: OMAP3 ROM Random Number Generator support
This driver provides kernel-side support for the Random Number Generator hardware found on OMAP34xx processors. This driver comes from Maemo 2.6.28 kernel and was tested on Nokia RX-51. It is platform device because it needs board specific function for smc calls. Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Juha Yrjola <[email protected]> Acked-by: Tony Lindgren <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
- Loading branch information
Showing
3 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
* omap3-rom-rng.c - RNG driver for TI OMAP3 CPU family | ||
* | ||
* Copyright (C) 2009 Nokia Corporation | ||
* Author: Juha Yrjola <[email protected]> | ||
* | ||
* Copyright (C) 2013 Pali Rohár <[email protected]> | ||
* | ||
* 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. | ||
*/ | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#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> | ||
|
||
#define RNG_RESET 0x01 | ||
#define RNG_GEN_PRNG_HW_INIT 0x02 | ||
#define RNG_GEN_HW 0x08 | ||
|
||
/* param1: ptr, param2: count, param3: flag */ | ||
static u32 (*omap3_rom_rng_call)(u32, u32, u32); | ||
|
||
static struct timer_list idle_timer; | ||
static int rng_idle; | ||
static struct clk *rng_clk; | ||
|
||
static void omap3_rom_rng_idle(unsigned long data) | ||
{ | ||
int r; | ||
|
||
r = omap3_rom_rng_call(0, 0, RNG_RESET); | ||
if (r != 0) { | ||
pr_err("reset failed: %d\n", r); | ||
return; | ||
} | ||
clk_disable_unprepare(rng_clk); | ||
rng_idle = 1; | ||
} | ||
|
||
static int omap3_rom_rng_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 = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT); | ||
if (r != 0) { | ||
clk_disable_unprepare(rng_clk); | ||
pr_err("HW init failed: %d\n", r); | ||
return -EIO; | ||
} | ||
rng_idle = 0; | ||
} | ||
|
||
ptr = virt_to_phys(buf); | ||
r = omap3_rom_rng_call(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_rng_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) | ||
{ | ||
pr_info("initializing\n"); | ||
|
||
omap3_rom_rng_call = pdev->dev.platform_data; | ||
if (!omap3_rom_rng_call) { | ||
pr_err("omap3_rom_rng_call is NULL\n"); | ||
return -EINVAL; | ||
} | ||
|
||
setup_timer(&idle_timer, omap3_rom_rng_idle, 0); | ||
rng_clk = clk_get(&pdev->dev, "ick"); | ||
if (IS_ERR(rng_clk)) { | ||
pr_err("unable to get RNG clock\n"); | ||
return PTR_ERR(rng_clk); | ||
} | ||
|
||
/* Leave the RNG in reset state. */ | ||
clk_prepare_enable(rng_clk); | ||
omap3_rom_rng_idle(0); | ||
|
||
return hwrng_register(&omap3_rom_rng_ops); | ||
} | ||
|
||
static int omap3_rom_rng_remove(struct platform_device *pdev) | ||
{ | ||
hwrng_unregister(&omap3_rom_rng_ops); | ||
clk_disable_unprepare(rng_clk); | ||
clk_put(rng_clk); | ||
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_AUTHOR("Pali Rohár <[email protected]>"); | ||
MODULE_LICENSE("GPL"); |