1
2
3
4
5
6
7
8
9
10
11#include <linux/hw_random.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/io.h>
15#include <linux/platform_device.h>
16#include <linux/clk.h>
17#include <linux/pm_runtime.h>
18#include <linux/err.h>
19#include <linux/regmap.h>
20#include <linux/mfd/syscon.h>
21#include <linux/of.h>
22#include <linux/of_address.h>
23#include <linux/delay.h>
24
25#define SA_CMD_STATUS_OFS 0x8
26
27
28#define SA_CMD_STATUS_REG_TRNG_ENABLE BIT(3)
29
30
31#define TRNG_CNTL_REG_TRNG_ENABLE BIT(10)
32
33
34#define TRNG_STATUS_REG_READY BIT(0)
35
36
37#define TRNG_INTACK_REG_READY BIT(0)
38
39
40
41
42
43
44#define TRNG_DEF_STARTUP_CYCLES 0
45#define TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT 16
46
47
48
49
50
51
52#define TRNG_DEF_MIN_REFILL_CYCLES 1
53#define TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT 0
54
55
56
57
58
59
60#define TRNG_DEF_MAX_REFILL_CYCLES 0
61#define TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT 16
62
63
64#define TRNG_DEF_CLK_DIV_CYCLES 0
65#define TRNG_CFG_REG_SAMPLE_DIV_SHIFT 8
66
67
68#define SA_MAX_RNG_DATA_RETRIES 5
69
70#define SA_RNG_DATA_RETRY_DELAY 5
71
72struct trng_regs {
73 u32 output_l;
74 u32 output_h;
75 u32 status;
76 u32 intmask;
77 u32 intack;
78 u32 control;
79 u32 config;
80};
81
82struct ks_sa_rng {
83 struct device *dev;
84 struct hwrng rng;
85 struct clk *clk;
86 struct regmap *regmap_cfg;
87 struct trng_regs *reg_rng;
88};
89
90static int ks_sa_rng_init(struct hwrng *rng)
91{
92 u32 value;
93 struct device *dev = (struct device *)rng->priv;
94 struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
95
96
97 regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
98 SA_CMD_STATUS_REG_TRNG_ENABLE,
99 SA_CMD_STATUS_REG_TRNG_ENABLE);
100
101
102 writel(0, &ks_sa_rng->reg_rng->control);
103 value = TRNG_DEF_STARTUP_CYCLES << TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT;
104 writel(value, &ks_sa_rng->reg_rng->control);
105
106 value = (TRNG_DEF_MIN_REFILL_CYCLES <<
107 TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT) |
108 (TRNG_DEF_MAX_REFILL_CYCLES <<
109 TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT) |
110 (TRNG_DEF_CLK_DIV_CYCLES <<
111 TRNG_CFG_REG_SAMPLE_DIV_SHIFT);
112
113 writel(value, &ks_sa_rng->reg_rng->config);
114
115
116 writel(0, &ks_sa_rng->reg_rng->intmask);
117
118
119 value = readl(&ks_sa_rng->reg_rng->control);
120 value |= TRNG_CNTL_REG_TRNG_ENABLE;
121 writel(value, &ks_sa_rng->reg_rng->control);
122
123 return 0;
124}
125
126static void ks_sa_rng_cleanup(struct hwrng *rng)
127{
128 struct device *dev = (struct device *)rng->priv;
129 struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
130
131
132 writel(0, &ks_sa_rng->reg_rng->control);
133 regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
134 SA_CMD_STATUS_REG_TRNG_ENABLE, 0);
135}
136
137static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)
138{
139 struct device *dev = (struct device *)rng->priv;
140 struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
141
142
143 data[0] = readl(&ks_sa_rng->reg_rng->output_l);
144 data[1] = readl(&ks_sa_rng->reg_rng->output_h);
145
146 writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
147
148 return sizeof(u32) * 2;
149}
150
151static int ks_sa_rng_data_present(struct hwrng *rng, int wait)
152{
153 struct device *dev = (struct device *)rng->priv;
154 struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
155
156 u32 ready;
157 int j;
158
159 for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
160 ready = readl(&ks_sa_rng->reg_rng->status);
161 ready &= TRNG_STATUS_REG_READY;
162
163 if (ready || !wait)
164 break;
165
166 udelay(SA_RNG_DATA_RETRY_DELAY);
167 }
168
169 return ready;
170}
171
172static int ks_sa_rng_probe(struct platform_device *pdev)
173{
174 struct ks_sa_rng *ks_sa_rng;
175 struct device *dev = &pdev->dev;
176 int ret;
177 struct resource *mem;
178
179 ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL);
180 if (!ks_sa_rng)
181 return -ENOMEM;
182
183 ks_sa_rng->dev = dev;
184 ks_sa_rng->rng = (struct hwrng) {
185 .name = "ks_sa_hwrng",
186 .init = ks_sa_rng_init,
187 .data_read = ks_sa_rng_data_read,
188 .data_present = ks_sa_rng_data_present,
189 .cleanup = ks_sa_rng_cleanup,
190 };
191 ks_sa_rng->rng.priv = (unsigned long)dev;
192
193 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
194 ks_sa_rng->reg_rng = devm_ioremap_resource(dev, mem);
195 if (IS_ERR(ks_sa_rng->reg_rng))
196 return PTR_ERR(ks_sa_rng->reg_rng);
197
198 ks_sa_rng->regmap_cfg =
199 syscon_regmap_lookup_by_phandle(dev->of_node,
200 "ti,syscon-sa-cfg");
201
202 if (IS_ERR(ks_sa_rng->regmap_cfg)) {
203 dev_err(dev, "syscon_node_to_regmap failed\n");
204 return -EINVAL;
205 }
206
207 pm_runtime_enable(dev);
208 ret = pm_runtime_get_sync(dev);
209 if (ret < 0) {
210 dev_err(dev, "Failed to enable SA power-domain\n");
211 pm_runtime_disable(dev);
212 return ret;
213 }
214
215 platform_set_drvdata(pdev, ks_sa_rng);
216
217 return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng);
218}
219
220static int ks_sa_rng_remove(struct platform_device *pdev)
221{
222 pm_runtime_put_sync(&pdev->dev);
223 pm_runtime_disable(&pdev->dev);
224
225 return 0;
226}
227
228static const struct of_device_id ks_sa_rng_dt_match[] = {
229 {
230 .compatible = "ti,keystone-rng",
231 },
232 { },
233};
234MODULE_DEVICE_TABLE(of, ks_sa_rng_dt_match);
235
236static struct platform_driver ks_sa_rng_driver = {
237 .driver = {
238 .name = "ks-sa-rng",
239 .of_match_table = ks_sa_rng_dt_match,
240 },
241 .probe = ks_sa_rng_probe,
242 .remove = ks_sa_rng_remove,
243};
244
245module_platform_driver(ks_sa_rng_driver);
246
247MODULE_DESCRIPTION("Keystone NETCP SA H/W Random Number Generator driver");
248MODULE_AUTHOR("Vitaly Andrianov <vitalya@ti.com>");
249MODULE_LICENSE("GPL");
250