xref: /linux/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
1 #include "sun4i-ss.h"
2 
3 int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
4 		       unsigned int slen)
5 {
6 	struct sun4i_ss_alg_template *algt;
7 	struct rng_alg *alg = crypto_rng_alg(tfm);
8 
9 	algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
10 	memcpy(algt->ss->seed, seed, slen);
11 
12 	return 0;
13 }
14 
15 int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
16 			   unsigned int slen, u8 *dst, unsigned int dlen)
17 {
18 	struct sun4i_ss_alg_template *algt;
19 	struct rng_alg *alg = crypto_rng_alg(tfm);
20 	int i, err;
21 	u32 v;
22 	u32 *data = (u32 *)dst;
23 	const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
24 	size_t len;
25 	struct sun4i_ss_ctx *ss;
26 	unsigned int todo = (dlen / 4) * 4;
27 
28 	algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
29 	ss = algt->ss;
30 
31 	err = pm_runtime_get_sync(ss->dev);
32 	if (err < 0)
33 		return err;
34 
35 	spin_lock_bh(&ss->slock);
36 
37 	writel(mode, ss->base + SS_CTL);
38 
39 	while (todo > 0) {
40 		/* write the seed */
41 		for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
42 			writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
43 
44 		/* Read the random data */
45 		len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
46 		readsl(ss->base + SS_TXFIFO, data, len / 4);
47 		data += len / 4;
48 		todo -= len;
49 
50 		/* Update the seed */
51 		for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
52 			v = readl(ss->base + SS_KEY0 + i * 4);
53 			ss->seed[i] = v;
54 		}
55 	}
56 
57 	writel(0, ss->base + SS_CTL);
58 	spin_unlock_bh(&ss->slock);
59 
60 	pm_runtime_put(ss->dev);
61 
62 	return 0;
63 }
64