xref: /openbsd-src/sys/arch/riscv64/dev/stfrng.c (revision 009ac9880fffef6cf30783fc4a5e6a9ae7295205)
1 /*	$OpenBSD: stfrng.c,v 1.1 2023/09/23 18:29:55 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/timeout.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28 #include <dev/ofw/ofw_clock.h>
29 
30 /* Registers */
31 #define RNG_CTRL		0x0000
32 #define  RNG_CTRL_RANDOMIZE	0x1
33 #define  RNG_CTRL_RESEED	0x2
34 #define RNG_STAT		0x0004
35 #define  RNG_STAT_SEEDED	(1 << 9)
36 #define RNG_MODE		0x000c
37 #define  RNG_MODE_R256		(1 << 3)
38 #define RNG_ISTAT		0x0014
39 #define  RNG_ISTAT_RAND_RDY	(1 << 0)
40 #define  RNG_ISTAT_LFSR_LOCKUP	(1 << 4)
41 #define RNG_DATA0		0x0020
42 #define RNG_DATA1		0x0024
43 #define RNG_DATA2		0x0028
44 #define RNG_DATA3		0x002c
45 #define RNG_DATA4		0x0030
46 #define RNG_DATA5		0x0034
47 #define RNG_DATA6		0x0038
48 #define RNG_DATA7		0x003c
49 
50 #define HREAD4(sc, reg)							\
51 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
52 #define HWRITE4(sc, reg, val)						\
53 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
54 
55 struct stfrng_softc {
56 	struct device		sc_dev;
57 	bus_space_tag_t		sc_iot;
58 	bus_space_handle_t	sc_ioh;
59 
60 	struct timeout		sc_to;
61 };
62 
63 int	stfrng_match(struct device *, void *, void *);
64 void	stfrng_attach(struct device *, struct device *, void *);
65 
66 const struct cfattach	stfrng_ca = {
67 	sizeof (struct stfrng_softc), stfrng_match, stfrng_attach
68 };
69 
70 struct cfdriver stfrng_cd = {
71 	NULL, "stfrng", DV_DULL
72 };
73 
74 void	stfrng_rnd(void *);
75 
76 int
stfrng_match(struct device * parent,void * match,void * aux)77 stfrng_match(struct device *parent, void *match, void *aux)
78 {
79 	struct fdt_attach_args *faa = aux;
80 
81 	return OF_is_compatible(faa->fa_node, "starfive,jh7110-trng");
82 }
83 
84 void
stfrng_attach(struct device * parent,struct device * self,void * aux)85 stfrng_attach(struct device *parent, struct device *self, void *aux)
86 {
87 	struct stfrng_softc *sc = (struct stfrng_softc *)self;
88 	struct fdt_attach_args *faa = aux;
89 
90 	if (faa->fa_nreg < 1) {
91 		printf(": no registers\n");
92 		return;
93 	}
94 
95 	sc->sc_iot = faa->fa_iot;
96 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
97 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
98 		printf(": can't map registers\n");
99 		return;
100 	}
101 
102 	printf("\n");
103 
104 	clock_enable(faa->fa_node, "hclk");
105 	clock_enable(faa->fa_node, "ahb");
106 	reset_deassert(faa->fa_node, NULL);
107 
108 	/* Clear all interrupts. */
109 	HWRITE4(sc, RNG_ISTAT, 0xffffffff);
110 
111 	HWRITE4(sc, RNG_MODE, RNG_MODE_R256);
112 	HWRITE4(sc, RNG_CTRL, RNG_CTRL_RESEED);
113 
114 	timeout_set(&sc->sc_to, stfrng_rnd, sc);
115 	stfrng_rnd(sc);
116 }
117 
118 void
stfrng_rnd(void * arg)119 stfrng_rnd(void *arg)
120 {
121 	struct stfrng_softc *sc = arg;
122 	uint32_t stat, istat;
123 
124 	stat = HREAD4(sc, RNG_STAT);
125 	if (stat & RNG_STAT_SEEDED) {
126 		istat = HREAD4(sc, RNG_ISTAT);
127 		if (istat & RNG_ISTAT_RAND_RDY) {
128 			HWRITE4(sc, RNG_ISTAT, RNG_ISTAT_RAND_RDY);
129 			enqueue_randomness(HREAD4(sc, RNG_DATA0));
130 			enqueue_randomness(HREAD4(sc, RNG_DATA1));
131 			enqueue_randomness(HREAD4(sc, RNG_DATA2));
132 			enqueue_randomness(HREAD4(sc, RNG_DATA3));
133 			enqueue_randomness(HREAD4(sc, RNG_DATA4));
134 			enqueue_randomness(HREAD4(sc, RNG_DATA5));
135 			enqueue_randomness(HREAD4(sc, RNG_DATA6));
136 			enqueue_randomness(HREAD4(sc, RNG_DATA7));
137 		}
138 
139 		if (istat & RNG_ISTAT_LFSR_LOCKUP)
140 			HWRITE4(sc, RNG_CTRL, RNG_CTRL_RESEED);
141 		else
142 			HWRITE4(sc, RNG_CTRL, RNG_CTRL_RANDOMIZE);
143 	}
144 
145 	timeout_add_sec(&sc->sc_to, 1);
146 }
147