[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-am335x-psp-3.2 / 0006-am33x-Create-driver-for-TRNG-crypto-module.patch
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
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.
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
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