summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch')
-rw-r--r--recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch324
1 files changed, 324 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch
new file mode 100644
index 00000000..7d0023aa
--- /dev/null
+++ b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch
@@ -0,0 +1,324 @@
1From d56c0ab935577ef32ffdf23a62d2e1cecc391730 Mon Sep 17 00:00:00 2001
2From: Greg Turner <gregturner@ti.com>
3Date: Thu, 17 May 2012 15:11:26 -0500
4Subject: [PATCH 6/8] am33x: Create driver for TRNG crypto module
5
6This is the initial version of the driver for the TRNG crypto module for a GP version of OMAP4 derivative SOC's such as AM335x.
7
8Signed-off-by: Greg Turner <gregturner@ti.com>
9---
10 drivers/char/hw_random/omap4-rng.c | 303 ++++++++++++++++++++++++++++++++++++
11 1 files changed, 303 insertions(+), 0 deletions(-)
12 create mode 100755 drivers/char/hw_random/omap4-rng.c
13
14diff --git a/drivers/char/hw_random/omap4-rng.c b/drivers/char/hw_random/omap4-rng.c
15new file mode 100755
16index 0000000..523ec63
17--- /dev/null
18+++ b/drivers/char/hw_random/omap4-rng.c
19@@ -0,0 +1,303 @@
20+/*
21+ * drivers/char/hw_random/omap4-rng.c
22+ *
23+ * Copyright (c) 2012 Texas Instruments
24+ * TRNG driver for OMAP4 derivatives (AM33x, etc) - Herman Schuurman <herman@ti.com>
25+ *
26+ * derived from omap-rng.c.
27+ *
28+ * Author: Deepak Saxena <dsaxena@plexity.net>
29+ *
30+ * Copyright 2005 (c) MontaVista Software, Inc.
31+ *
32+ * Mostly based on original driver:
33+ *
34+ * Copyright (C) 2005 Nokia Corporation
35+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
36+ *
37+ * This file is licensed under the terms of the GNU General Public
38+ * License version 2. This program is licensed "as is" without any
39+ * warranty of any kind, whether express or implied.
40+ */
41+
42+#include <linux/module.h>
43+#include <linux/init.h>
44+#include <linux/random.h>
45+#include <linux/clk.h>
46+#include <linux/err.h>
47+#include <linux/platform_device.h>
48+#include <linux/hw_random.h>
49+#include <linux/delay.h>
50+
51+#include <mach/hardware.h>
52+#include <asm/io.h>
53+
54+/* ==================================================================== */
55+/** RNG module layout.
56+ */
57+/* ==================================================================== */
58+#define RNG_REG_OUTPUT_L 0x00
59+#define RNG_REG_OUTPUT_H 0x04
60+
61+#define RNG_REG_STATUS 0x08
62+#define RNG_REG_STATUS_NEED_CLK (1 << 31)
63+#define RNG_REG_STATUS_SHUTDOWN_OFLO (1 << 1)
64+#define RNG_REG_STATUS_RDY (1 << 0)
65+
66+#define RNG_REG_IMASK 0x0C
67+#define RNG_REG_IMASK_SHUTDOWN_OFLO (1 << 1)
68+#define RNG_REG_IMASK_RDY (1 << 0)
69+
70+#define RNG_REG_INTACK 0x10
71+#define RNG_REG_INTACK_SHUTDOWN_OFLO (1 << 1)
72+#define RNG_REG_INTACK_RDY (1 << 0)
73+
74+#define RNG_REG_CONTROL 0x14
75+#define RNG_REG_CONTROL_STARTUP_MASK 0xFFFF0000
76+#define RNG_REG_CONTROL_ENABLE_TRNG (1 << 10)
77+#define RNG_REG_CONTROL_NO_LFSR_FB (1 << 2)
78+
79+#define RNG_REG_CONFIG 0x18
80+#define RNG_REG_CONFIG_MAX_REFILL_MASK 0xFFFF0000
81+#define RNG_REG_CONFIG_SAMPLE_DIV 0x00000F00
82+#define RNG_REG_CONFIG_MIN_REFILL_MASK 0x000000FF
83+
84+#define RNG_REG_ALARMCNT 0x1C
85+#define RNG_REG_ALARMCNT_SHTDWN_MASK 0x3F000000
86+#define RNG_REG_ALARMCNT_SD_THLD_MASK 0x001F0000
87+#define RNG_REG_ALARMCNT_ALM_THLD_MASK 0x000000FF
88+
89+#define RNG_REG_FROENABLE 0x20
90+#define RNG_REG_FRODETUNE 0x24
91+#define RNG_REG_ALARMMASK 0x28
92+#define RNG_REG_ALARMSTOP 0x2C
93+#define RNG_REG_LFSR_L 0x30
94+#define RNG_REG_LFSR_M 0x34
95+#define RNG_REG_LFSR_H 0x38
96+#define RNG_REG_COUNT 0x3C
97+#define RNG_REG_TEST 0x40
98+
99+#define RNG_REG_OPTIONS 0x78
100+#define RNG_REG_OPTIONS_NUM_FROS_MASK 0x00000FC0
101+
102+#define RNG_REG_EIP_REV 0x7C
103+#define RNG_REG_STATUS_EN 0x1FD8
104+#define RNG_REG_STATUS_EN_SHUTDOWN_OFLO (1 << 1)
105+#define RNG_REG_STATUS_EN_RDY (1 << 0)
106+
107+#define RNG_REG_REV 0x1FE0
108+#define RNG_REG_REV_X_MAJOR_MASK (0x0F << 4)
109+#define RNG_REG_REV_Y_MINOR_MASK (0x0F << 0)
110+
111+#define RNG_REG_SYSCFG 0x1FE4
112+#define RNG_REG_SYSCFG_SIDLEMODE_MASK (3 << 3)
113+#define RNG_REG_SYSCFG_SIDLEMODE_FORCE (0 << 3)
114+#define RNG_REG_SYSCFG_SIDLEMODE_NO (1 << 3)
115+#define RNG_REG_SYSCFG_SIDLEMODE_SMART (2 << 3)
116+#define RNG_REG_SYSCFG_AUTOIDLE (1 << 0)
117+
118+#define RNG_REG_STATUS_SET 0x1FEC
119+#define RNG_REG_STATUS_SET_SHUTDOWN_OFLO (1 << 1)
120+#define RNG_REG_STATUS_SET_RDY (1 << 0)
121+
122+#define RNG_REG_SOFT_RESET 0x1FF0
123+#define RNG_REG_SOFTRESET (1 << 0)
124+
125+#define RNG_REG_IRQ_EOI 0x1FF4
126+#define RNG_REG_IRQ_EOI_PULSE_INT_CLEAR (1 << 0)
127+
128+#define RNG_REG_IRQSTATUS 0x1FF8
129+#define RNG_REG_IRQSTATUS_IRQ_EN (1 << 0)
130+
131+
132+static void __iomem *rng_base;
133+static struct clk *rng_fck;
134+static struct platform_device *rng_dev;
135+
136+#define trng_read(reg) \
137+({ \
138+ u32 __val; \
139+ __val = __raw_readl(rng_base + RNG_REG_##reg); \
140+})
141+
142+#define trng_write(val, reg) \
143+({ \
144+ __raw_writel((val), rng_base + RNG_REG_##reg); \
145+})
146+
147+static int omap4_rng_data_read(struct hwrng *rng, void *buf, size_t max, bool wait)
148+{
149+ int res, i;
150+
151+ for (i = 0; i < 20; i++) {
152+ res = trng_read(STATUS) & RNG_REG_STATUS_RDY;
153+ if (res || !wait)
154+ break;
155+ /* RNG produces data fast enough (2+ MBit/sec, even
156+ * during "rngtest" loads, that these delays don't
157+ * seem to trigger. We *could* use the RNG IRQ, but
158+ * that'd be higher overhead ... so why bother?
159+ */
160+ udelay(10);
161+ }
162+
163+ /* If we have data waiting, collect it... */
164+ if (res) {
165+ *(u32 *)buf = trng_read(OUTPUT_L);
166+ buf += sizeof(u32);
167+ *(u32 *)buf = trng_read(OUTPUT_H);
168+
169+ trng_write(RNG_REG_INTACK_RDY, INTACK);
170+
171+ res = 2 * sizeof(u32);
172+ }
173+ return res;
174+}
175+
176+static struct hwrng omap4_rng_ops = {
177+ .name = "omap4",
178+ .read = omap4_rng_data_read,
179+};
180+
181+static int __devinit omap4_rng_probe(struct platform_device *pdev)
182+{
183+ struct resource *res;
184+ int ret;
185+ u32 reg;
186+
187+ /*
188+ * A bit ugly, and it will never actually happen but there can
189+ * be only one RNG and this catches any bork
190+ */
191+ if (rng_dev)
192+ return -EBUSY;
193+
194+ rng_fck = clk_get(&pdev->dev, "rng_fck");
195+ if (IS_ERR(rng_fck)) {
196+ dev_err(&pdev->dev, "Could not get rng_fck\n");
197+ ret = PTR_ERR(rng_fck);
198+ return ret;
199+ } else
200+ clk_enable(rng_fck);
201+
202+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
203+ if (!res) {
204+ ret = -ENOENT;
205+ goto err_region;
206+ }
207+
208+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
209+ ret = -EBUSY;
210+ goto err_region;
211+ }
212+
213+ dev_set_drvdata(&pdev->dev, res);
214+ rng_base = ioremap(res->start, resource_size(res));
215+ if (!rng_base) {
216+ ret = -ENOMEM;
217+ goto err_ioremap;
218+ }
219+
220+ ret = hwrng_register(&omap4_rng_ops);
221+ if (ret)
222+ goto err_register;
223+
224+ reg = trng_read(REV);
225+ dev_info(&pdev->dev, "OMAP4 Random Number Generator ver. %u.%02u\n",
226+ ((reg & RNG_REG_REV_X_MAJOR_MASK) >> 4),
227+ (reg & RNG_REG_REV_Y_MINOR_MASK));
228+
229+ rng_dev = pdev;
230+
231+ /* start TRNG if not running yet */
232+ if (!(trng_read(CONTROL) & RNG_REG_CONTROL_ENABLE_TRNG)) {
233+ trng_write(0x00220021, CONFIG);
234+ trng_write(0x00210400, CONTROL);
235+ }
236+
237+ return 0;
238+
239+err_register:
240+ iounmap(rng_base);
241+ rng_base = NULL;
242+err_ioremap:
243+ release_mem_region(res->start, resource_size(res));
244+err_region:
245+ clk_disable(rng_fck);
246+ clk_put(rng_fck);
247+ return ret;
248+}
249+
250+static int __exit omap4_rng_remove(struct platform_device *pdev)
251+{
252+ struct resource *res = dev_get_drvdata(&pdev->dev);
253+
254+ hwrng_unregister(&omap4_rng_ops);
255+
256+ trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
257+
258+ iounmap(rng_base);
259+
260+ clk_disable(rng_fck);
261+ clk_put(rng_fck);
262+ release_mem_region(res->start, resource_size(res));
263+ rng_base = NULL;
264+
265+ return 0;
266+}
267+
268+#ifdef CONFIG_PM
269+
270+static int omap4_rng_suspend(struct platform_device *pdev, pm_message_t message)
271+{
272+ trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
273+
274+ return 0;
275+}
276+
277+static int omap4_rng_resume(struct platform_device *pdev)
278+{
279+ trng_write(trng_read(CONTROL) | RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
280+
281+ return 0;
282+}
283+
284+#else
285+
286+#define omap4_rng_suspend NULL
287+#define omap4_rng_resume NULL
288+
289+#endif
290+
291+/* work with hotplug and coldplug */
292+MODULE_ALIAS("platform:omap4_rng");
293+
294+static struct platform_driver omap4_rng_driver = {
295+ .driver = {
296+ .name = "omap4_rng",
297+ .owner = THIS_MODULE,
298+ },
299+ .probe = omap4_rng_probe,
300+ .remove = __exit_p(omap4_rng_remove),
301+ .suspend = omap4_rng_suspend,
302+ .resume = omap4_rng_resume
303+};
304+
305+static int __init omap4_rng_init(void)
306+{
307+ if (!cpu_is_am33xx() || omap_type() != OMAP2_DEVICE_TYPE_GP)
308+ return -ENODEV;
309+
310+ return platform_driver_register(&omap4_rng_driver);
311+}
312+
313+static void __exit omap4_rng_exit(void)
314+{
315+ platform_driver_unregister(&omap4_rng_driver);
316+}
317+
318+module_init(omap4_rng_init);
319+module_exit(omap4_rng_exit);
320+
321+MODULE_LICENSE("GPL");
322+MODULE_DESCRIPTION("AM33X TRNG driver");
323--
3241.7.0.4