1010 * Krzysztof Kozłowski <krzk@kernel.org>
1111 */
1212
13+ #include <linux/arm-smccc.h>
1314#include <linux/clk.h>
1415#include <linux/crypto.h>
1516#include <linux/delay.h>
2223#include <linux/mod_devicetable.h>
2324#include <linux/platform_device.h>
2425#include <linux/pm_runtime.h>
26+ #include <linux/property.h>
2527
2628#define EXYNOS_TRNG_CLKDIV 0x0
2729
4446#define EXYNOS_TRNG_FIFO_LEN 8
4547#define EXYNOS_TRNG_CLOCK_RATE 500000
4648
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+
4773struct exynos_trng_dev {
4874 struct device * dev ;
4975 void __iomem * mem ;
5076 struct clk * clk ; /* operating clock */
5177 struct clk * pclk ; /* bus clock */
5278 struct hwrng rng ;
79+ unsigned long flags ;
5380};
5481
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 )
5784{
5885 struct exynos_trng_dev * trng = (struct exynos_trng_dev * )rng -> priv ;
5986 int val ;
@@ -70,7 +97,40 @@ static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max,
7097 return max ;
7198}
7299
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 )
74134{
75135 struct exynos_trng_dev * trng = (struct exynos_trng_dev * )rng -> priv ;
76136 unsigned long sss_rate ;
@@ -103,6 +163,24 @@ static int exynos_trng_init(struct hwrng *rng)
103163 return 0 ;
104164}
105165
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+
106184static int exynos_trng_probe (struct platform_device * pdev )
107185{
108186 struct exynos_trng_dev * trng ;
@@ -112,21 +190,29 @@ static int exynos_trng_probe(struct platform_device *pdev)
112190 if (!trng )
113191 return ret ;
114192
193+ platform_set_drvdata (pdev , trng );
194+ trng -> dev = & pdev -> dev ;
195+
196+ trng -> flags = (unsigned long )device_get_match_data (& pdev -> dev );
197+
115198 trng -> rng .name = devm_kstrdup (& pdev -> dev , dev_name (& pdev -> dev ),
116199 GFP_KERNEL );
117200 if (!trng -> rng .name )
118201 return ret ;
119202
120- trng -> rng .init = exynos_trng_init ;
121- trng -> rng .read = exynos_trng_do_read ;
122203 trng -> rng .priv = (unsigned long )trng ;
123204
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 ;
126211
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+ }
130216
131217 pm_runtime_enable (& pdev -> dev );
132218 ret = pm_runtime_resume_and_get (& pdev -> dev );
@@ -170,19 +256,39 @@ static int exynos_trng_probe(struct platform_device *pdev)
170256
171257static void exynos_trng_remove (struct platform_device * pdev )
172258{
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+
173268 pm_runtime_put_sync (& pdev -> dev );
174269 pm_runtime_disable (& pdev -> dev );
175270}
176271
177272static int exynos_trng_suspend (struct device * dev )
178273{
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+
179284 pm_runtime_put_sync (dev );
180285
181286 return 0 ;
182287}
183288
184289static int exynos_trng_resume (struct device * dev )
185290{
291+ struct exynos_trng_dev * trng = dev_get_drvdata (dev );
186292 int ret ;
187293
188294 ret = pm_runtime_resume_and_get (dev );
@@ -191,6 +297,20 @@ static int exynos_trng_resume(struct device *dev)
191297 return ret ;
192298 }
193299
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+
194314 return 0 ;
195315}
196316
0 commit comments