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