]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/meta-ti-glsdk.git/blob - recipes-kernel/linux/linux-am335x-psp-3.2/0006-am33x-Create-driver-for-TRNG-crypto-module.patch
linux-omap-psp: Update commit
[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
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)
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)
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)
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)
122 +#define        RNG_REG_SOFT_RESET              0x1FF0
123 +#define        RNG_REG_SOFTRESET               (1 << 0)
125 +#define        RNG_REG_IRQ_EOI                 0x1FF4
126 +#define        RNG_REG_IRQ_EOI_PULSE_INT_CLEAR (1 << 0)
128 +#define        RNG_REG_IRQSTATUS               0x1FF8
129 +#define        RNG_REG_IRQSTATUS_IRQ_EN        (1 << 0)
132 +static void __iomem *rng_base;
133 +static struct clk *rng_fck;
134 +static struct platform_device *rng_dev;
136 +#define trng_read(reg)                                         \
137 +({                                                             \
138 +       u32 __val;                                              \
139 +       __val = __raw_readl(rng_base + RNG_REG_##reg);          \
140 +})
142 +#define trng_write(val, reg)                                   \
143 +({                                                             \
144 +       __raw_writel((val), rng_base + RNG_REG_##reg);          \
145 +})
147 +static int omap4_rng_data_read(struct hwrng *rng, void *buf, size_t max, bool wait)
148 +{
149 +       int res, i;
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 +       }
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);
169 +               trng_write(RNG_REG_INTACK_RDY, INTACK);
171 +               res = 2  * sizeof(u32);
172 +       }
173 +       return res;
174 +}
176 +static struct hwrng omap4_rng_ops = {
177 +       .name           = "omap4",
178 +       .read           = omap4_rng_data_read,
179 +};
181 +static int __devinit omap4_rng_probe(struct platform_device *pdev)
182 +{
183 +       struct resource *res;
184 +       int ret;
185 +       u32 reg;
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;
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);
202 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
203 +       if (!res) {
204 +               ret = -ENOENT;
205 +               goto err_region;
206 +       }
208 +       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
209 +               ret = -EBUSY;
210 +               goto err_region;
211 +       }
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 +       }
220 +       ret = hwrng_register(&omap4_rng_ops);
221 +       if (ret)
222 +               goto err_register;
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));
229 +       rng_dev = pdev;
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 +       }
237 +       return 0;
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 +}
250 +static int __exit omap4_rng_remove(struct platform_device *pdev)
251 +{
252 +       struct resource *res = dev_get_drvdata(&pdev->dev);
254 +       hwrng_unregister(&omap4_rng_ops);
256 +       trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
258 +       iounmap(rng_base);
260 +       clk_disable(rng_fck);
261 +       clk_put(rng_fck);
262 +       release_mem_region(res->start, resource_size(res));
263 +       rng_base = NULL;
265 +       return 0;
266 +}
268 +#ifdef CONFIG_PM
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);
274 +       return 0;
275 +}
277 +static int omap4_rng_resume(struct platform_device *pdev)
278 +{
279 +       trng_write(trng_read(CONTROL) | RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
281 +       return 0;
282 +}
284 +#else
286 +#define        omap4_rng_suspend       NULL
287 +#define        omap4_rng_resume        NULL
289 +#endif
291 +/* work with hotplug and coldplug */
292 +MODULE_ALIAS("platform:omap4_rng");
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 +};
305 +static int __init omap4_rng_init(void)
306 +{
307 +       if (!cpu_is_am33xx()  || omap_type() != OMAP2_DEVICE_TYPE_GP)
308 +               return -ENODEV;
310 +       return platform_driver_register(&omap4_rng_driver);
311 +}
313 +static void __exit omap4_rng_exit(void)
314 +{
315 +       platform_driver_unregister(&omap4_rng_driver);
316 +}
318 +module_init(omap4_rng_init);
319 +module_exit(omap4_rng_exit);
321 +MODULE_LICENSE("GPL");
322 +MODULE_DESCRIPTION("AM33X TRNG driver");
323 --
324 1.7.0.4