diff options
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.patch | 324 |
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 @@ | |||
1 | From d56c0ab935577ef32ffdf23a62d2e1cecc391730 Mon Sep 17 00:00:00 2001 | ||
2 | From: Greg Turner <gregturner@ti.com> | ||
3 | Date: Thu, 17 May 2012 15:11:26 -0500 | ||
4 | Subject: [PATCH 6/8] am33x: Create driver for TRNG crypto module | ||
5 | |||
6 | This 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 | |||
8 | Signed-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 | |||
14 | diff --git a/drivers/char/hw_random/omap4-rng.c b/drivers/char/hw_random/omap4-rng.c | ||
15 | new file mode 100755 | ||
16 | index 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 | -- | ||
324 | 1.7.0.4 | ||