blob: bc4e192b4b408a4a537246a17b6362cf6b659ff0 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/platform_device.h>
4#include <linux/of.h>
5#include <linux/clk-provider.h>
6#include <linux/clk.h>
7#include <linux/cputype.h>
8#include <linux/hw_random.h>
9#include <linux/io.h>
10#include <linux/slab.h>
11#include <linux/sched.h>
12#include <linux/fs.h>
13#include <linux/delay.h>
14
15#include "asr-geu.h"
16
17#define SAMPLE_UDELAY (6)
18
19static inline u32 rng_readl(struct asr_geu_rng *hwrng, u32 offset)
20{
21 struct asr_geu_dev *geu_dd = dev_get_drvdata(hwrng->dev);
22
23 return readl(geu_dd->io_base + offset);
24}
25
26static inline void rng_writel(struct asr_geu_rng *hwrng, u32 val,
27 u32 offset)
28{
29 struct asr_geu_dev *geu_dd = dev_get_drvdata(hwrng->dev);
30
31 writel(val, geu_dd->io_base + offset);
32}
33
34#if defined(CONFIG_CPU_ASR1901)
35static void asr_rng_clr_fifo(struct asr_geu_rng *hwrng)
36{
37 u32 val;
38 val = rng_readl(hwrng, GEU_SQU_RNG_CTRL);
39 val |= RNG_FIFO_CLR;
40 rng_writel(hwrng, val, GEU_SQU_RNG_CTRL);
41}
42#endif
43
44static int asr_rng_init(struct hwrng *rng)
45{
46 u32 val;
47 struct asr_geu_rng *hwrng = (struct asr_geu_rng *)rng->priv;
48
49 val = rng_readl(hwrng, GEU_RNG_CTRL);
50 if ((val & GEU_RNG_EN) == GEU_RNG_EN)
51 return 0;
52
53 #if !defined(CONFIG_CPU_ASR1901)
54 #if defined (CONFIG_CPU_ASR1903)
55 if (!cpu_is_asr1903_z1()) {
56 writel(hwrng->rn_saved, hwrng->seed_base + 0x0);
57 writel(jiffies & 0xFFFFFFFF, hwrng->seed_base + 0x4);
58 }
59 #else
60 rng_writel(hwrng, jiffies & 0xFFFFFFFF, GEU_RNG_SEED_HI);
61 rng_writel(hwrng, hwrng->rn_saved, GEU_RNG_SEED_LO);
62 #endif
63 #endif
64
65 val |= GEU_RNG_EN; /* enable hardware random generator */
66 rng_writel(hwrng, val, GEU_RNG_CTRL);
67 usleep_range(70, 80);
68
69 return 0;
70}
71
72static int asr_rng_disable(struct asr_geu_rng *hwrng)
73{
74 u32 val;
75
76 val = rng_readl(hwrng, GEU_RNG_CTRL);
77 val &= ~GEU_RNG_EN;
78 rng_writel(hwrng, val, GEU_RNG_CTRL);
79
80 return 0;
81}
82
83static int asr_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
84{
85 int timeout = max / 4 + 1;
86 unsigned int val, random = 0;
87 u32 *data = (u32 *)buf;
88 size_t read = 0;
89
90 struct asr_geu_rng *hwrng = (struct asr_geu_rng *)rng->priv;
91 struct asr_geu_dev *geu_dd = dev_get_drvdata(hwrng->dev);
92 struct asr_geu_ops *geu_ops = geu_dd->geu_ops;
93
94 geu_ops->dev_get(geu_dd);
95
96 asr_rng_init(rng);
97
98 random = hwrng->rn_saved;
99 while (read < max) {
100 val = rng_readl(hwrng, GEU_RNG_GEN);
101 #if defined(CONFIG_CPU_ASR1901)
102 asr_rng_clr_fifo(hwrng);
103 #endif
104 if (val == random || val == 0) {
105 if (wait) {
106 udelay(SAMPLE_UDELAY);
107 if (timeout-- == 0) {
108 geu_ops->dev_put(geu_dd);
109 return read;
110 }
111 } else {
112 geu_ops->dev_put(geu_dd);
113 return 0;
114 }
115 } else {
116 *data = random = val;
117 data++;
118 read += 4;
119 }
120 }
121
122 asr_rng_disable(hwrng);
123
124 hwrng->rn_saved = random;
125 geu_ops->dev_put(geu_dd);
126
127 return read;
128}
129
130static struct hwrng asr_rng = {
131 .name = "asr",
132 .init = asr_rng_init,
133 .read = asr_rng_read,
134 .quality = 1000,
135};
136
137int asr_geu_rng_register(struct asr_geu_dev *geu_dd)
138{
139 int err = 0;
140 struct asr_geu_rng *prng;
141
142 prng = &geu_dd->asr_rng;
143 prng->rn_saved = 0xdeadbeef;
144 prng->hwrng = &asr_rng;
145 prng->io_base = geu_dd->io_base;
146 prng->dev = geu_dd->dev;
147#ifdef CONFIG_CPU_ASR1903
148 prng->seed_base = ioremap_nocache(ASR1903_RNG_SEED, 0x10);
149#endif
150
151 asr_rng.priv = (unsigned long)prng;
152
153 err = hwrng_register(&asr_rng);
154 if (err) {
155 dev_err(prng->dev, "failed to register asr_rng!\n");
156 return err;
157 }
158
159 return 0;
160}
161EXPORT_SYMBOL_GPL(asr_geu_rng_register);
162
163int asr_geu_rng_unregister(struct asr_geu_dev *geu_dd)
164{
165 struct asr_geu_rng *prng = &geu_dd->asr_rng;
166
167#ifdef CONFIG_CPU_ASR1903
168 iounmap(prng->seed_base);
169#endif
170
171 hwrng_unregister(prng->hwrng);
172
173 return 0;
174}
175EXPORT_SYMBOL_GPL(asr_geu_rng_unregister);
176
177MODULE_LICENSE("GPL");
178MODULE_AUTHOR("Yu Zhang <yuzhang@asrmicro.com>");
179MODULE_DESCRIPTION("ASR H/W RNG driver");