aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorLokesh Vutla <lokeshvutla@ti.com>2013-08-05 10:47:23 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2013-08-09 02:39:48 -0400
commite83872c989fb704748956c0bf1b69874a35492c6 (patch)
tree0c79da645911df9ef3575ecd92fb28db43de785d /drivers/char
parent674ee08f28f32032c40c6a9d5376edf4158bfbbc (diff)
hwrng: omap - Add OMAP4 TRNG support
Add support for OMAP4 version of TRNG module that is present on OMAP4, AM33xx and OMAP5 SoCs. The modules have several differences including register offsets, output size, triggering rng and how configuring FROs. To handle these differences, a platform_data structure is defined and contains routine pointers, register offsets. OMAP2 specific routines are prefixed with 'omap2_' and OMAP4 specific routines are prefixed with 'omap4_'. Note: Few Hard coded values are from the TI AM33xx SDK. Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hw_random/Kconfig6
-rw-r--r--drivers/char/hw_random/omap-rng.c352
2 files changed, 305 insertions, 53 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 2f9dbf7568fb..5d7be1d65d92 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -153,12 +153,12 @@ config HW_RANDOM_IXP4XX
153 153
154config HW_RANDOM_OMAP 154config HW_RANDOM_OMAP
155 tristate "OMAP Random Number Generator support" 155 tristate "OMAP Random Number Generator support"
156 depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2) 156 depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
157 default HW_RANDOM 157 default HW_RANDOM
158 ---help--- 158 ---help---
159 This driver provides kernel-side support for the Random Number 159 This driver provides kernel-side support for the Random Number
160 Generator hardware found on OMAP16xx and OMAP24xx multimedia 160 Generator hardware found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx
161 processors. 161 multimedia processors.
162 162
163 To compile this driver as a module, choose M here: the 163 To compile this driver as a module, choose M here: the
164 module will be called omap-rng. 164 module will be called omap-rng.
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 3076c9de7a02..f3f71425e7e2 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -27,57 +27,138 @@
27#include <linux/of.h> 27#include <linux/of.h>
28#include <linux/of_device.h> 28#include <linux/of_device.h>
29#include <linux/of_address.h> 29#include <linux/of_address.h>
30#include <linux/interrupt.h>
30 31
31#include <asm/io.h> 32#include <asm/io.h>
32 33
33#define RNG_OUT_REG 0x00 /* Output register */ 34#define RNG_REG_STATUS_RDY (1 << 0)
34#define RNG_STAT_REG 0x04 /* Status register 35
35 [0] = STAT_BUSY */ 36#define RNG_REG_INTACK_RDY_MASK (1 << 0)
36#define RNG_ALARM_REG 0x24 /* Alarm register 37#define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK (1 << 1)
37 [7:0] = ALARM_COUNTER */ 38#define RNG_SHUTDOWN_OFLO_MASK (1 << 1)
38#define RNG_CONFIG_REG 0x28 /* Configuration register 39
39 [11:6] = RESET_COUNT 40#define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16
40 [5:3] = RING2_DELAY 41#define RNG_CONTROL_STARTUP_CYCLES_MASK (0xffff << 16)
41 [2:0] = RING1_DELAY */ 42#define RNG_CONTROL_ENABLE_TRNG_SHIFT 10
42#define RNG_REV_REG 0x3c /* Revision register 43#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
43 [7:0] = REV_NB */ 44
44#define RNG_MASK_REG 0x40 /* Mask and reset register 45#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16
45 [2] = IT_EN 46#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK (0xffff << 16)
46 [1] = SOFTRESET 47#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0
47 [0] = AUTOIDLE */ 48#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK (0xff << 0)
48#define RNG_SYSSTATUS 0x44 /* System status 49
49 [0] = RESETDONE */ 50#define RNG_CONTROL_STARTUP_CYCLES 0xff
51#define RNG_CONFIG_MIN_REFIL_CYCLES 0x21
52#define RNG_CONFIG_MAX_REFIL_CYCLES 0x22
53
54#define RNG_ALARMCNT_ALARM_TH_SHIFT 0x0
55#define RNG_ALARMCNT_ALARM_TH_MASK (0xff << 0)
56#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16
57#define RNG_ALARMCNT_SHUTDOWN_TH_MASK (0x1f << 16)
58#define RNG_ALARM_THRESHOLD 0xff
59#define RNG_SHUTDOWN_THRESHOLD 0x4
60
61#define RNG_REG_FROENABLE_MASK 0xffffff
62#define RNG_REG_FRODETUNE_MASK 0xffffff
63
64#define OMAP2_RNG_OUTPUT_SIZE 0x4
65#define OMAP4_RNG_OUTPUT_SIZE 0x8
66
67enum {
68 RNG_OUTPUT_L_REG = 0,
69 RNG_OUTPUT_H_REG,
70 RNG_STATUS_REG,
71 RNG_INTMASK_REG,
72 RNG_INTACK_REG,
73 RNG_CONTROL_REG,
74 RNG_CONFIG_REG,
75 RNG_ALARMCNT_REG,
76 RNG_FROENABLE_REG,
77 RNG_FRODETUNE_REG,
78 RNG_ALARMMASK_REG,
79 RNG_ALARMSTOP_REG,
80 RNG_REV_REG,
81 RNG_SYSCONFIG_REG,
82};
83
84static const u16 reg_map_omap2[] = {
85 [RNG_OUTPUT_L_REG] = 0x0,
86 [RNG_STATUS_REG] = 0x4,
87 [RNG_CONFIG_REG] = 0x28,
88 [RNG_REV_REG] = 0x3c,
89 [RNG_SYSCONFIG_REG] = 0x40,
90};
91
92static const u16 reg_map_omap4[] = {
93 [RNG_OUTPUT_L_REG] = 0x0,
94 [RNG_OUTPUT_H_REG] = 0x4,
95 [RNG_STATUS_REG] = 0x8,
96 [RNG_INTMASK_REG] = 0xc,
97 [RNG_INTACK_REG] = 0x10,
98 [RNG_CONTROL_REG] = 0x14,
99 [RNG_CONFIG_REG] = 0x18,
100 [RNG_ALARMCNT_REG] = 0x1c,
101 [RNG_FROENABLE_REG] = 0x20,
102 [RNG_FRODETUNE_REG] = 0x24,
103 [RNG_ALARMMASK_REG] = 0x28,
104 [RNG_ALARMSTOP_REG] = 0x2c,
105 [RNG_REV_REG] = 0x1FE0,
106 [RNG_SYSCONFIG_REG] = 0x1FE4,
107};
50 108
109struct omap_rng_dev;
51/** 110/**
52 * struct omap_rng_private_data - RNG IP block-specific data 111 * struct omap_rng_pdata - RNG IP block-specific data
53 * @base: virtual address of the beginning of the RNG IP block registers 112 * @regs: Pointer to the register offsets structure.
54 * @mem_res: struct resource * for the IP block registers physical memory 113 * @data_size: No. of bytes in RNG output.
114 * @data_present: Callback to determine if data is available.
115 * @init: Callback for IP specific initialization sequence.
116 * @cleanup: Callback for IP specific cleanup sequence.
55 */ 117 */
56struct omap_rng_private_data { 118struct omap_rng_pdata {
57 void __iomem *base; 119 u16 *regs;
58 struct resource *mem_res; 120 u32 data_size;
121 u32 (*data_present)(struct omap_rng_dev *priv);
122 int (*init)(struct omap_rng_dev *priv);
123 void (*cleanup)(struct omap_rng_dev *priv);
59}; 124};
60 125
61static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg) 126struct omap_rng_dev {
127 void __iomem *base;
128 struct device *dev;
129 const struct omap_rng_pdata *pdata;
130};
131
132static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)
133{
134 return __raw_readl(priv->base + priv->pdata->regs[reg]);
135}
136
137static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg,
138 u32 val)
62{ 139{
63 return __raw_readl(priv->base + reg); 140 __raw_writel(val, priv->base + priv->pdata->regs[reg]);
64} 141}
65 142
66static inline void omap_rng_write_reg(struct omap_rng_private_data *priv, 143static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv)
67 int reg, u32 val)
68{ 144{
69 __raw_writel(val, priv->base + reg); 145 return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1;
146}
147
148static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv)
149{
150 return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY;
70} 151}
71 152
72static int omap_rng_data_present(struct hwrng *rng, int wait) 153static int omap_rng_data_present(struct hwrng *rng, int wait)
73{ 154{
74 struct omap_rng_private_data *priv; 155 struct omap_rng_dev *priv;
75 int data, i; 156 int data, i;
76 157
77 priv = (struct omap_rng_private_data *)rng->priv; 158 priv = (struct omap_rng_dev *)rng->priv;
78 159
79 for (i = 0; i < 20; i++) { 160 for (i = 0; i < 20; i++) {
80 data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1; 161 data = priv->pdata->data_present(priv);
81 if (data || !wait) 162 if (data || !wait)
82 break; 163 break;
83 /* RNG produces data fast enough (2+ MBit/sec, even 164 /* RNG produces data fast enough (2+ MBit/sec, even
@@ -92,36 +173,202 @@ static int omap_rng_data_present(struct hwrng *rng, int wait)
92 173
93static int omap_rng_data_read(struct hwrng *rng, u32 *data) 174static int omap_rng_data_read(struct hwrng *rng, u32 *data)
94{ 175{
95 struct omap_rng_private_data *priv; 176 struct omap_rng_dev *priv;
177 u32 data_size, i;
178
179 priv = (struct omap_rng_dev *)rng->priv;
180 data_size = priv->pdata->data_size;
181
182 for (i = 0; i < data_size / sizeof(u32); i++)
183 data[i] = omap_rng_read(priv, RNG_OUTPUT_L_REG + i);
184
185 if (priv->pdata->regs[RNG_INTACK_REG])
186 omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
187 return data_size;
188}
189
190static int omap4_rng_init(struct omap_rng_dev *priv)
191{
192 u32 val;
193
194 /* Return if RNG is already running. */
195 if (omap_rng_read(priv, RNG_CONFIG_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)
196 return 0;
197
198 val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
199 val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
200 omap_rng_write(priv, RNG_CONFIG_REG, val);
201
202 omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0);
203 omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK);
204 val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;
205 val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;
206 omap_rng_write(priv, RNG_ALARMCNT_REG, val);
207
208 val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
209 val |= RNG_CONTROL_ENABLE_TRNG_MASK;
210 omap_rng_write(priv, RNG_CONTROL_REG, val);
211
212 return 0;
213}
214
215static void omap4_rng_cleanup(struct omap_rng_dev *priv)
216{
217 int val;
218
219 val = omap_rng_read(priv, RNG_CONTROL_REG);
220 val &= ~RNG_CONTROL_ENABLE_TRNG_MASK;
221 omap_rng_write(priv, RNG_CONFIG_REG, val);
222}
223
224static int omap2_rng_init(struct omap_rng_dev *priv)
225{
226 omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1);
227 return 0;
228}
229
230static void omap2_rng_cleanup(struct omap_rng_dev *priv)
231{
232 omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0);
233}
234
235static int omap_rng_init(struct hwrng *rng)
236{
237 struct omap_rng_dev *priv;
238
239 priv = (struct omap_rng_dev *)rng->priv;
240 return priv->pdata->init(priv);
241}
242
243static void omap_rng_cleanup(struct hwrng *rng)
244{
245 struct omap_rng_dev *priv;
246
247 priv = (struct omap_rng_dev *)rng->priv;
248 priv->pdata->cleanup(priv);
249}
250
251static irqreturn_t omap4_rng_irq(int irq, void *dev_id)
252{
253 struct omap_rng_dev *priv = dev_id;
254 u32 fro_detune, fro_enable;
255
256 /*
257 * Interrupt raised by a fro shutdown threshold, do the following:
258 * 1. Clear the alarm events.
259 * 2. De tune the FROs which are shutdown.
260 * 3. Re enable the shutdown FROs.
261 */
262 omap_rng_write(priv, RNG_ALARMMASK_REG, 0x0);
263 omap_rng_write(priv, RNG_ALARMSTOP_REG, 0x0);
264
265 fro_enable = omap_rng_read(priv, RNG_FROENABLE_REG);
266 fro_detune = ~fro_enable & RNG_REG_FRODETUNE_MASK;
267 fro_detune = fro_detune | omap_rng_read(priv, RNG_FRODETUNE_REG);
268 fro_enable = RNG_REG_FROENABLE_MASK;
96 269
97 priv = (struct omap_rng_private_data *)rng->priv; 270 omap_rng_write(priv, RNG_FRODETUNE_REG, fro_detune);
271 omap_rng_write(priv, RNG_FROENABLE_REG, fro_enable);
98 272
99 *data = omap_rng_read_reg(priv, RNG_OUT_REG); 273 omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_SHUTDOWN_OFLO_MASK);
100 274
101 return sizeof(u32); 275 return IRQ_HANDLED;
102} 276}
103 277
104static struct hwrng omap_rng_ops = { 278static struct hwrng omap_rng_ops = {
105 .name = "omap", 279 .name = "omap",
106 .data_present = omap_rng_data_present, 280 .data_present = omap_rng_data_present,
107 .data_read = omap_rng_data_read, 281 .data_read = omap_rng_data_read,
282 .init = omap_rng_init,
283 .cleanup = omap_rng_cleanup,
284};
285
286static struct omap_rng_pdata omap2_rng_pdata = {
287 .regs = (u16 *)reg_map_omap2,
288 .data_size = OMAP2_RNG_OUTPUT_SIZE,
289 .data_present = omap2_rng_data_present,
290 .init = omap2_rng_init,
291 .cleanup = omap2_rng_cleanup,
108}; 292};
109 293
110#if defined(CONFIG_OF) 294#if defined(CONFIG_OF)
295static struct omap_rng_pdata omap4_rng_pdata = {
296 .regs = (u16 *)reg_map_omap4,
297 .data_size = OMAP4_RNG_OUTPUT_SIZE,
298 .data_present = omap4_rng_data_present,
299 .init = omap4_rng_init,
300 .cleanup = omap4_rng_cleanup,
301};
302
111static const struct of_device_id omap_rng_of_match[] = { 303static const struct of_device_id omap_rng_of_match[] = {
112 { .compatible = "ti,omap2-rng" }, 304 {
305 .compatible = "ti,omap2-rng",
306 .data = &omap2_rng_pdata,
307 },
308 {
309 .compatible = "ti,omap4-rng",
310 .data = &omap4_rng_pdata,
311 },
113 {}, 312 {},
114}; 313};
115MODULE_DEVICE_TABLE(of, omap_rng_of_match); 314MODULE_DEVICE_TABLE(of, omap_rng_of_match);
315
316static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
317 struct platform_device *pdev)
318{
319 const struct of_device_id *match;
320 struct device *dev = &pdev->dev;
321 int irq, err;
322
323 match = of_match_device(of_match_ptr(omap_rng_of_match), dev);
324 if (!match) {
325 dev_err(dev, "no compatible OF match\n");
326 return -EINVAL;
327 }
328 priv->pdata = match->data;
329
330 if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) {
331 irq = platform_get_irq(pdev, 0);
332 if (irq < 0) {
333 dev_err(dev, "%s: error getting IRQ resource - %d\n",
334 __func__, irq);
335 return irq;
336 }
337
338 err = devm_request_irq(dev, irq, omap4_rng_irq,
339 IRQF_TRIGGER_NONE, dev_name(dev), priv);
340 if (err) {
341 dev_err(dev, "unable to request irq %d, err = %d\n",
342 irq, err);
343 return err;
344 }
345 omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK);
346 }
347 return 0;
348}
349#else
350static int of_get_omap_rng_device_details(struct omap_rng_dev *omap_rng,
351 struct platform_device *pdev)
352{
353 return -EINVAL;
354}
116#endif 355#endif
117 356
357static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng)
358{
359 /* Only OMAP2/3 can be non-DT */
360 omap_rng->pdata = &omap2_rng_pdata;
361 return 0;
362}
363
118static int omap_rng_probe(struct platform_device *pdev) 364static int omap_rng_probe(struct platform_device *pdev)
119{ 365{
120 struct omap_rng_private_data *priv; 366 struct omap_rng_dev *priv;
367 struct resource *res;
368 struct device *dev = &pdev->dev;
121 int ret; 369 int ret;
122 370
123 priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_rng_private_data), 371 priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL);
124 GFP_KERNEL);
125 if (!priv) { 372 if (!priv) {
126 dev_err(&pdev->dev, "could not allocate memory\n"); 373 dev_err(&pdev->dev, "could not allocate memory\n");
127 return -ENOMEM; 374 return -ENOMEM;
@@ -129,9 +376,10 @@ static int omap_rng_probe(struct platform_device *pdev)
129 376
130 omap_rng_ops.priv = (unsigned long)priv; 377 omap_rng_ops.priv = (unsigned long)priv;
131 platform_set_drvdata(pdev, priv); 378 platform_set_drvdata(pdev, priv);
379 priv->dev = dev;
132 380
133 priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 381 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
134 priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res); 382 priv->base = devm_ioremap_resource(dev, res);
135 if (IS_ERR(priv->base)) { 383 if (IS_ERR(priv->base)) {
136 ret = PTR_ERR(priv->base); 384 ret = PTR_ERR(priv->base);
137 goto err_ioremap; 385 goto err_ioremap;
@@ -140,14 +388,17 @@ static int omap_rng_probe(struct platform_device *pdev)
140 pm_runtime_enable(&pdev->dev); 388 pm_runtime_enable(&pdev->dev);
141 pm_runtime_get_sync(&pdev->dev); 389 pm_runtime_get_sync(&pdev->dev);
142 390
391 ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
392 get_omap_rng_device_details(priv);
393 if (ret)
394 goto err_ioremap;
395
143 ret = hwrng_register(&omap_rng_ops); 396 ret = hwrng_register(&omap_rng_ops);
144 if (ret) 397 if (ret)
145 goto err_register; 398 goto err_register;
146 399
147 dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", 400 dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n",
148 omap_rng_read_reg(priv, RNG_REV_REG)); 401 omap_rng_read(priv, RNG_REV_REG));
149
150 omap_rng_write_reg(priv, RNG_MASK_REG, 0x1);
151 402
152 return 0; 403 return 0;
153 404
@@ -155,16 +406,17 @@ err_register:
155 priv->base = NULL; 406 priv->base = NULL;
156 pm_runtime_disable(&pdev->dev); 407 pm_runtime_disable(&pdev->dev);
157err_ioremap: 408err_ioremap:
409 dev_err(dev, "initialization failed.\n");
158 return ret; 410 return ret;
159} 411}
160 412
161static int __exit omap_rng_remove(struct platform_device *pdev) 413static int __exit omap_rng_remove(struct platform_device *pdev)
162{ 414{
163 struct omap_rng_private_data *priv = platform_get_drvdata(pdev); 415 struct omap_rng_dev *priv = platform_get_drvdata(pdev);
164 416
165 hwrng_unregister(&omap_rng_ops); 417 hwrng_unregister(&omap_rng_ops);
166 418
167 omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); 419 priv->pdata->cleanup(priv);
168 420
169 pm_runtime_put_sync(&pdev->dev); 421 pm_runtime_put_sync(&pdev->dev);
170 pm_runtime_disable(&pdev->dev); 422 pm_runtime_disable(&pdev->dev);
@@ -176,9 +428,9 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
176 428
177static int omap_rng_suspend(struct device *dev) 429static int omap_rng_suspend(struct device *dev)
178{ 430{
179 struct omap_rng_private_data *priv = dev_get_drvdata(dev); 431 struct omap_rng_dev *priv = dev_get_drvdata(dev);
180 432
181 omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); 433 priv->pdata->cleanup(priv);
182 pm_runtime_put_sync(dev); 434 pm_runtime_put_sync(dev);
183 435
184 return 0; 436 return 0;
@@ -186,10 +438,10 @@ static int omap_rng_suspend(struct device *dev)
186 438
187static int omap_rng_resume(struct device *dev) 439static int omap_rng_resume(struct device *dev)
188{ 440{
189 struct omap_rng_private_data *priv = dev_get_drvdata(dev); 441 struct omap_rng_dev *priv = dev_get_drvdata(dev);
190 442
191 pm_runtime_get_sync(dev); 443 pm_runtime_get_sync(dev);
192 omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); 444 priv->pdata->init(priv);
193 445
194 return 0; 446 return 0;
195} 447}