10
10
* Krzysztof Kozłowski <[email protected] >
11
11
*/
12
12
13
+ #include <linux/arm-smccc.h>
13
14
#include <linux/clk.h>
14
15
#include <linux/crypto.h>
15
16
#include <linux/delay.h>
22
23
#include <linux/mod_devicetable.h>
23
24
#include <linux/platform_device.h>
24
25
#include <linux/pm_runtime.h>
26
+ #include <linux/property.h>
25
27
26
28
#define EXYNOS_TRNG_CLKDIV 0x0
27
29
44
46
#define EXYNOS_TRNG_FIFO_LEN 8
45
47
#define EXYNOS_TRNG_CLOCK_RATE 500000
46
48
49
+ /* Driver feature flags */
50
+ #define EXYNOS_SMC BIT(0)
51
+
52
+ #define EXYNOS_SMC_CALL_VAL (func_num ) \
53
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
54
+ ARM_SMCCC_SMC_32, \
55
+ ARM_SMCCC_OWNER_SIP, \
56
+ func_num)
57
+
58
+ /* SMC command for DTRNG access */
59
+ #define SMC_CMD_RANDOM EXYNOS_SMC_CALL_VAL(0x1012)
60
+
61
+ /* SMC_CMD_RANDOM: arguments */
62
+ #define HWRNG_INIT 0x0
63
+ #define HWRNG_EXIT 0x1
64
+ #define HWRNG_GET_DATA 0x2
65
+ #define HWRNG_RESUME 0x3
66
+
67
+ /* SMC_CMD_RANDOM: return values */
68
+ #define HWRNG_RET_OK 0x0
69
+ #define HWRNG_RET_RETRY_ERROR 0x2
70
+
71
+ #define HWRNG_MAX_TRIES 100
72
+
47
73
struct exynos_trng_dev {
48
74
struct device * dev ;
49
75
void __iomem * mem ;
50
76
struct clk * clk ; /* operating clock */
51
77
struct clk * pclk ; /* bus clock */
52
78
struct hwrng rng ;
79
+ unsigned long flags ;
53
80
};
54
81
55
- static int exynos_trng_do_read (struct hwrng * rng , void * data , size_t max ,
56
- bool wait )
82
+ static int exynos_trng_do_read_reg (struct hwrng * rng , void * data , size_t max ,
83
+ bool wait )
57
84
{
58
85
struct exynos_trng_dev * trng = (struct exynos_trng_dev * )rng -> priv ;
59
86
int val ;
@@ -70,7 +97,40 @@ static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max,
70
97
return max ;
71
98
}
72
99
73
- static int exynos_trng_init (struct hwrng * rng )
100
+ static int exynos_trng_do_read_smc (struct hwrng * rng , void * data , size_t max ,
101
+ bool wait )
102
+ {
103
+ struct arm_smccc_res res ;
104
+ unsigned int copied = 0 ;
105
+ u32 * buf = data ;
106
+ int tries = 0 ;
107
+
108
+ while (copied < max ) {
109
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_GET_DATA , 0 , 0 , 0 , 0 , 0 , 0 ,
110
+ & res );
111
+ switch (res .a0 ) {
112
+ case HWRNG_RET_OK :
113
+ * buf ++ = res .a2 ;
114
+ * buf ++ = res .a3 ;
115
+ copied += 8 ;
116
+ tries = 0 ;
117
+ break ;
118
+ case HWRNG_RET_RETRY_ERROR :
119
+ if (!wait )
120
+ return copied ;
121
+ if (++ tries >= HWRNG_MAX_TRIES )
122
+ return copied ;
123
+ cond_resched ();
124
+ break ;
125
+ default :
126
+ return - EIO ;
127
+ }
128
+ }
129
+
130
+ return copied ;
131
+ }
132
+
133
+ static int exynos_trng_init_reg (struct hwrng * rng )
74
134
{
75
135
struct exynos_trng_dev * trng = (struct exynos_trng_dev * )rng -> priv ;
76
136
unsigned long sss_rate ;
@@ -103,6 +163,24 @@ static int exynos_trng_init(struct hwrng *rng)
103
163
return 0 ;
104
164
}
105
165
166
+ static int exynos_trng_init_smc (struct hwrng * rng )
167
+ {
168
+ struct exynos_trng_dev * trng = (struct exynos_trng_dev * )rng -> priv ;
169
+ struct arm_smccc_res res ;
170
+ int ret = 0 ;
171
+
172
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_INIT , 0 , 0 , 0 , 0 , 0 , 0 , & res );
173
+ if (res .a0 != HWRNG_RET_OK ) {
174
+ dev_err (trng -> dev , "SMC command for TRNG init failed (%d)\n" ,
175
+ (int )res .a0 );
176
+ ret = - EIO ;
177
+ }
178
+ if ((int )res .a0 == -1 )
179
+ dev_info (trng -> dev , "Make sure LDFW is loaded by your BL\n" );
180
+
181
+ return ret ;
182
+ }
183
+
106
184
static int exynos_trng_probe (struct platform_device * pdev )
107
185
{
108
186
struct exynos_trng_dev * trng ;
@@ -112,21 +190,29 @@ static int exynos_trng_probe(struct platform_device *pdev)
112
190
if (!trng )
113
191
return ret ;
114
192
193
+ platform_set_drvdata (pdev , trng );
194
+ trng -> dev = & pdev -> dev ;
195
+
196
+ trng -> flags = (unsigned long )device_get_match_data (& pdev -> dev );
197
+
115
198
trng -> rng .name = devm_kstrdup (& pdev -> dev , dev_name (& pdev -> dev ),
116
199
GFP_KERNEL );
117
200
if (!trng -> rng .name )
118
201
return ret ;
119
202
120
- trng -> rng .init = exynos_trng_init ;
121
- trng -> rng .read = exynos_trng_do_read ;
122
203
trng -> rng .priv = (unsigned long )trng ;
123
204
124
- platform_set_drvdata (pdev , trng );
125
- trng -> dev = & pdev -> dev ;
205
+ if (trng -> flags & EXYNOS_SMC ) {
206
+ trng -> rng .init = exynos_trng_init_smc ;
207
+ trng -> rng .read = exynos_trng_do_read_smc ;
208
+ } else {
209
+ trng -> rng .init = exynos_trng_init_reg ;
210
+ trng -> rng .read = exynos_trng_do_read_reg ;
126
211
127
- trng -> mem = devm_platform_ioremap_resource (pdev , 0 );
128
- if (IS_ERR (trng -> mem ))
129
- return PTR_ERR (trng -> mem );
212
+ trng -> mem = devm_platform_ioremap_resource (pdev , 0 );
213
+ if (IS_ERR (trng -> mem ))
214
+ return PTR_ERR (trng -> mem );
215
+ }
130
216
131
217
pm_runtime_enable (& pdev -> dev );
132
218
ret = pm_runtime_resume_and_get (& pdev -> dev );
@@ -170,19 +256,39 @@ static int exynos_trng_probe(struct platform_device *pdev)
170
256
171
257
static void exynos_trng_remove (struct platform_device * pdev )
172
258
{
259
+ struct exynos_trng_dev * trng = platform_get_drvdata (pdev );
260
+
261
+ if (trng -> flags & EXYNOS_SMC ) {
262
+ struct arm_smccc_res res ;
263
+
264
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_EXIT , 0 , 0 , 0 , 0 , 0 , 0 ,
265
+ & res );
266
+ }
267
+
173
268
pm_runtime_put_sync (& pdev -> dev );
174
269
pm_runtime_disable (& pdev -> dev );
175
270
}
176
271
177
272
static int exynos_trng_suspend (struct device * dev )
178
273
{
274
+ struct exynos_trng_dev * trng = dev_get_drvdata (dev );
275
+ struct arm_smccc_res res ;
276
+
277
+ if (trng -> flags & EXYNOS_SMC ) {
278
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_EXIT , 0 , 0 , 0 , 0 , 0 , 0 ,
279
+ & res );
280
+ if (res .a0 != HWRNG_RET_OK )
281
+ return - EIO ;
282
+ }
283
+
179
284
pm_runtime_put_sync (dev );
180
285
181
286
return 0 ;
182
287
}
183
288
184
289
static int exynos_trng_resume (struct device * dev )
185
290
{
291
+ struct exynos_trng_dev * trng = dev_get_drvdata (dev );
186
292
int ret ;
187
293
188
294
ret = pm_runtime_resume_and_get (dev );
@@ -191,6 +297,20 @@ static int exynos_trng_resume(struct device *dev)
191
297
return ret ;
192
298
}
193
299
300
+ if (trng -> flags & EXYNOS_SMC ) {
301
+ struct arm_smccc_res res ;
302
+
303
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_RESUME , 0 , 0 , 0 , 0 , 0 , 0 ,
304
+ & res );
305
+ if (res .a0 != HWRNG_RET_OK )
306
+ return - EIO ;
307
+
308
+ arm_smccc_smc (SMC_CMD_RANDOM , HWRNG_INIT , 0 , 0 , 0 , 0 , 0 , 0 ,
309
+ & res );
310
+ if (res .a0 != HWRNG_RET_OK )
311
+ return - EIO ;
312
+ }
313
+
194
314
return 0 ;
195
315
}
196
316
0 commit comments