hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/char/hw_random/imx-rngc.c
....@@ -1,15 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * RNG driver for Freescale RNGC
34 *
45 * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
56 * Copyright (C) 2017 Martin Kaiser <martin@kaiser.cx>
6
- *
7
- * The code contained herein is licensed under the GNU General Public
8
- * License. You may obtain a copy of the GNU General Public License
9
- * Version 2 or later at the following locations:
10
- *
11
- * http://www.opensource.org/licenses/gpl-license.html
12
- * http://www.gnu.org/copyleft/gpl.html
137 */
148
159 #include <linux/module.h>
....@@ -24,11 +18,21 @@
2418 #include <linux/completion.h>
2519 #include <linux/io.h>
2620
21
+#define RNGC_VER_ID 0x0000
2722 #define RNGC_COMMAND 0x0004
2823 #define RNGC_CONTROL 0x0008
2924 #define RNGC_STATUS 0x000C
3025 #define RNGC_ERROR 0x0010
3126 #define RNGC_FIFO 0x0014
27
+
28
+/* the fields in the ver id register */
29
+#define RNGC_TYPE_SHIFT 28
30
+#define RNGC_VER_MAJ_SHIFT 8
31
+
32
+/* the rng_type field */
33
+#define RNGC_TYPE_RNGB 0x1
34
+#define RNGC_TYPE_RNGC 0x2
35
+
3236
3337 #define RNGC_CMD_CLR_ERR 0x00000020
3438 #define RNGC_CMD_CLR_INT 0x00000010
....@@ -37,6 +41,7 @@
3741
3842 #define RNGC_CTRL_MASK_ERROR 0x00000040
3943 #define RNGC_CTRL_MASK_DONE 0x00000020
44
+#define RNGC_CTRL_AUTO_SEED 0x00000010
4045
4146 #define RNGC_STATUS_ERROR 0x00010000
4247 #define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00
....@@ -106,17 +111,11 @@
106111 writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);
107112
108113 ret = wait_for_completion_timeout(&rngc->rng_op_done, RNGC_TIMEOUT);
109
- if (!ret) {
110
- imx_rngc_irq_mask_clear(rngc);
114
+ imx_rngc_irq_mask_clear(rngc);
115
+ if (!ret)
111116 return -ETIMEDOUT;
112
- }
113117
114
- if (rngc->err_reg != 0) {
115
- imx_rngc_irq_mask_clear(rngc);
116
- return -EIO;
117
- }
118
-
119
- return 0;
118
+ return rngc->err_reg ? -EIO : 0;
120119 }
121120
122121 static int imx_rngc_read(struct hwrng *rng, void *data, size_t max, bool wait)
....@@ -173,17 +172,17 @@
173172 static int imx_rngc_init(struct hwrng *rng)
174173 {
175174 struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
176
- u32 cmd;
175
+ u32 cmd, ctrl;
177176 int ret;
178177
179178 /* clear error */
180179 cmd = readl(rngc->base + RNGC_COMMAND);
181180 writel(cmd | RNGC_CMD_CLR_ERR, rngc->base + RNGC_COMMAND);
182181
182
+ imx_rngc_irq_unmask(rngc);
183
+
183184 /* create seed, repeat while there is some statistical error */
184185 do {
185
- imx_rngc_irq_unmask(rngc);
186
-
187186 /* seed creation */
188187 cmd = readl(rngc->base + RNGC_COMMAND);
189188 writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND);
....@@ -192,28 +191,57 @@
192191 RNGC_TIMEOUT);
193192
194193 if (!ret) {
195
- imx_rngc_irq_mask_clear(rngc);
196
- return -ETIMEDOUT;
194
+ ret = -ETIMEDOUT;
195
+ goto err;
197196 }
198197
199198 } while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR);
200199
201
- return rngc->err_reg ? -EIO : 0;
200
+ if (rngc->err_reg) {
201
+ ret = -EIO;
202
+ goto err;
203
+ }
204
+
205
+ /*
206
+ * enable automatic seeding, the rngc creates a new seed automatically
207
+ * after serving 2^20 random 160-bit words
208
+ */
209
+ ctrl = readl(rngc->base + RNGC_CONTROL);
210
+ ctrl |= RNGC_CTRL_AUTO_SEED;
211
+ writel(ctrl, rngc->base + RNGC_CONTROL);
212
+
213
+ /*
214
+ * if initialisation was successful, we keep the interrupt
215
+ * unmasked until imx_rngc_cleanup is called
216
+ * we mask the interrupt ourselves if we return an error
217
+ */
218
+ return 0;
219
+
220
+err:
221
+ imx_rngc_irq_mask_clear(rngc);
222
+ return ret;
223
+}
224
+
225
+static void imx_rngc_cleanup(struct hwrng *rng)
226
+{
227
+ struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
228
+
229
+ imx_rngc_irq_mask_clear(rngc);
202230 }
203231
204232 static int imx_rngc_probe(struct platform_device *pdev)
205233 {
206234 struct imx_rngc *rngc;
207
- struct resource *res;
208235 int ret;
209236 int irq;
237
+ u32 ver_id;
238
+ u8 rng_type;
210239
211240 rngc = devm_kzalloc(&pdev->dev, sizeof(*rngc), GFP_KERNEL);
212241 if (!rngc)
213242 return -ENOMEM;
214243
215
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
216
- rngc->base = devm_ioremap_resource(&pdev->dev, res);
244
+ rngc->base = devm_platform_ioremap_resource(pdev, 0);
217245 if (IS_ERR(rngc->base))
218246 return PTR_ERR(rngc->base);
219247
....@@ -233,10 +261,14 @@
233261 if (ret)
234262 return ret;
235263
236
- ret = devm_request_irq(&pdev->dev,
237
- irq, imx_rngc_irq, 0, pdev->name, (void *)rngc);
238
- if (ret) {
239
- dev_err(rngc->dev, "Can't get interrupt working.\n");
264
+ ver_id = readl(rngc->base + RNGC_VER_ID);
265
+ rng_type = ver_id >> RNGC_TYPE_SHIFT;
266
+ /*
267
+ * This driver supports only RNGC and RNGB. (There's a different
268
+ * driver for RNGA.)
269
+ */
270
+ if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) {
271
+ ret = -ENODEV;
240272 goto err;
241273 }
242274
....@@ -245,27 +277,39 @@
245277 rngc->rng.name = pdev->name;
246278 rngc->rng.init = imx_rngc_init;
247279 rngc->rng.read = imx_rngc_read;
280
+ rngc->rng.cleanup = imx_rngc_cleanup;
281
+ rngc->rng.quality = 19;
248282
249283 rngc->dev = &pdev->dev;
250284 platform_set_drvdata(pdev, rngc);
251285
252286 imx_rngc_irq_mask_clear(rngc);
253287
288
+ ret = devm_request_irq(&pdev->dev,
289
+ irq, imx_rngc_irq, 0, pdev->name, (void *)rngc);
290
+ if (ret) {
291
+ dev_err(rngc->dev, "Can't get interrupt working.\n");
292
+ return ret;
293
+ }
294
+
254295 if (self_test) {
255296 ret = imx_rngc_self_test(rngc);
256297 if (ret) {
257
- dev_err(rngc->dev, "FSL RNGC self test failed.\n");
298
+ dev_err(rngc->dev, "self test failed\n");
258299 goto err;
259300 }
260301 }
261302
262303 ret = hwrng_register(&rngc->rng);
263304 if (ret) {
264
- dev_err(&pdev->dev, "FSL RNGC registering failed (%d)\n", ret);
305
+ dev_err(&pdev->dev, "hwrng registration failed\n");
265306 goto err;
266307 }
267308
268
- dev_info(&pdev->dev, "Freescale RNGC registered.\n");
309
+ dev_info(&pdev->dev,
310
+ "Freescale RNG%c registered (HW revision %d.%02d)\n",
311
+ rng_type == RNGC_TYPE_RNGB ? 'B' : 'C',
312
+ (ver_id >> RNGC_VER_MAJ_SHIFT) & 0xff, ver_id & 0xff);
269313 return 0;
270314
271315 err: