2 * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * All enquiries to support@picochip.com
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/hw_random.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
19 #define DATA_REG_OFFSET 0x0200
20 #define CSR_REG_OFFSET 0x0278
21 #define CSR_OUT_EMPTY_MASK (1 << 24)
22 #define CSR_FAULT_MASK (1 << 1)
23 #define TRNG_BLOCK_RESET_MASK (1 << 0)
24 #define TAI_REG_OFFSET 0x0380
27 * The maximum amount of time in microseconds to spend waiting for data if the
28 * core wants us to wait. The TRNG should generate 32 bits every 320ns so a
29 * timeout of 20us seems reasonable. The TRNG does builtin tests of the data
30 * for randomness so we can't always assume there is data present.
32 #define PICO_TRNG_TIMEOUT 20
34 static void __iomem
*rng_base
;
35 static struct clk
*rng_clk
;
36 static struct device
*rng_dev
;
38 static inline u32
picoxcell_trng_read_csr(void)
40 return __raw_readl(rng_base
+ CSR_REG_OFFSET
);
43 static inline bool picoxcell_trng_is_empty(void)
45 return picoxcell_trng_read_csr() & CSR_OUT_EMPTY_MASK
;
49 * Take the random number generator out of reset and make sure the interrupts
50 * are masked. We shouldn't need to get large amounts of random bytes so just
51 * poll the status register. The hardware generates 32 bits every 320ns so we
52 * shouldn't have to wait long enough to warrant waiting for an IRQ.
54 static void picoxcell_trng_start(void)
56 __raw_writel(0, rng_base
+ TAI_REG_OFFSET
);
57 __raw_writel(0, rng_base
+ CSR_REG_OFFSET
);
60 static void picoxcell_trng_reset(void)
62 __raw_writel(TRNG_BLOCK_RESET_MASK
, rng_base
+ CSR_REG_OFFSET
);
63 __raw_writel(TRNG_BLOCK_RESET_MASK
, rng_base
+ TAI_REG_OFFSET
);
64 picoxcell_trng_start();
68 * Get some random data from the random number generator. The hw_random core
69 * layer provides us with locking.
71 static int picoxcell_trng_read(struct hwrng
*rng
, void *buf
, size_t max
,
76 /* Wait for some data to become available. */
77 for (i
= 0; i
< PICO_TRNG_TIMEOUT
&& picoxcell_trng_is_empty(); ++i
) {
84 if (picoxcell_trng_read_csr() & CSR_FAULT_MASK
) {
85 dev_err(rng_dev
, "fault detected, resetting TRNG\n");
86 picoxcell_trng_reset();
90 if (i
== PICO_TRNG_TIMEOUT
)
93 *(u32
*)buf
= __raw_readl(rng_base
+ DATA_REG_OFFSET
);
97 static struct hwrng picoxcell_trng
= {
99 .read
= picoxcell_trng_read
,
102 static int picoxcell_trng_probe(struct platform_device
*pdev
)
105 struct resource
*mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
108 dev_warn(&pdev
->dev
, "no memory resource\n");
112 if (!devm_request_mem_region(&pdev
->dev
, mem
->start
, resource_size(mem
),
114 dev_warn(&pdev
->dev
, "unable to request io mem\n");
118 rng_base
= devm_ioremap(&pdev
->dev
, mem
->start
, resource_size(mem
));
120 dev_warn(&pdev
->dev
, "unable to remap io mem\n");
124 rng_clk
= clk_get(&pdev
->dev
, NULL
);
125 if (IS_ERR(rng_clk
)) {
126 dev_warn(&pdev
->dev
, "no clk\n");
127 return PTR_ERR(rng_clk
);
130 ret
= clk_enable(rng_clk
);
132 dev_warn(&pdev
->dev
, "unable to enable clk\n");
136 picoxcell_trng_start();
137 ret
= hwrng_register(&picoxcell_trng
);
141 rng_dev
= &pdev
->dev
;
142 dev_info(&pdev
->dev
, "pixoxcell random number generator active\n");
147 clk_disable(rng_clk
);
154 static int picoxcell_trng_remove(struct platform_device
*pdev
)
156 hwrng_unregister(&picoxcell_trng
);
157 clk_disable(rng_clk
);
164 static int picoxcell_trng_suspend(struct device
*dev
)
166 clk_disable(rng_clk
);
171 static int picoxcell_trng_resume(struct device
*dev
)
173 return clk_enable(rng_clk
);
176 static const struct dev_pm_ops picoxcell_trng_pm_ops
= {
177 .suspend
= picoxcell_trng_suspend
,
178 .resume
= picoxcell_trng_resume
,
180 #endif /* CONFIG_PM */
182 static struct platform_driver picoxcell_trng_driver
= {
183 .probe
= picoxcell_trng_probe
,
184 .remove
= picoxcell_trng_remove
,
186 .name
= "picoxcell-trng",
187 .owner
= THIS_MODULE
,
189 .pm
= &picoxcell_trng_pm_ops
,
190 #endif /* CONFIG_PM */
194 module_platform_driver(picoxcell_trng_driver
);
196 MODULE_LICENSE("GPL");
197 MODULE_AUTHOR("Jamie Iles");
198 MODULE_DESCRIPTION("Picochip picoXcell TRNG driver");