1*084d57f7Sriastradh /* $NetBSD: meson_rng.c,v 1.5 2022/03/19 11:36:43 riastradh Exp $ */
2912cfa14Sjmcneill
3912cfa14Sjmcneill /*-
4912cfa14Sjmcneill * Copyright (c) 2015-2019 Jared D. McNeill <jmcneill@invisible.ca>
5912cfa14Sjmcneill * All rights reserved.
6912cfa14Sjmcneill *
7912cfa14Sjmcneill * Redistribution and use in source and binary forms, with or without
8912cfa14Sjmcneill * modification, are permitted provided that the following conditions
9912cfa14Sjmcneill * are met:
10912cfa14Sjmcneill * 1. Redistributions of source code must retain the above copyright
11912cfa14Sjmcneill * notice, this list of conditions and the following disclaimer.
12912cfa14Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
13912cfa14Sjmcneill * notice, this list of conditions and the following disclaimer in the
14912cfa14Sjmcneill * documentation and/or other materials provided with the distribution.
15912cfa14Sjmcneill *
16912cfa14Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17912cfa14Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18912cfa14Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19912cfa14Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20912cfa14Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21912cfa14Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22912cfa14Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23912cfa14Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24912cfa14Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25912cfa14Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26912cfa14Sjmcneill * SUCH DAMAGE.
27912cfa14Sjmcneill */
28912cfa14Sjmcneill
29912cfa14Sjmcneill #include <sys/cdefs.h>
30*084d57f7Sriastradh __KERNEL_RCSID(0, "$NetBSD: meson_rng.c,v 1.5 2022/03/19 11:36:43 riastradh Exp $");
31912cfa14Sjmcneill
32912cfa14Sjmcneill #include <sys/param.h>
33912cfa14Sjmcneill #include <sys/bus.h>
34912cfa14Sjmcneill #include <sys/device.h>
35912cfa14Sjmcneill #include <sys/systm.h>
36912cfa14Sjmcneill #include <sys/kernel.h>
37912cfa14Sjmcneill #include <sys/mutex.h>
38912cfa14Sjmcneill #include <sys/rndsource.h>
39912cfa14Sjmcneill
40912cfa14Sjmcneill #include <dev/fdt/fdtvar.h>
41912cfa14Sjmcneill
42912cfa14Sjmcneill static int meson_rng_match(device_t, cfdata_t, void *);
43912cfa14Sjmcneill static void meson_rng_attach(device_t, device_t, void *);
44912cfa14Sjmcneill
45912cfa14Sjmcneill static void meson_rng_get(size_t, void *);
46912cfa14Sjmcneill
47912cfa14Sjmcneill struct meson_rng_softc {
48912cfa14Sjmcneill device_t sc_dev;
49912cfa14Sjmcneill bus_space_tag_t sc_bst;
50912cfa14Sjmcneill bus_space_handle_t sc_bsh;
51912cfa14Sjmcneill
52912cfa14Sjmcneill krndsource_t sc_rndsource;
53912cfa14Sjmcneill };
54912cfa14Sjmcneill
556e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
566e54367aSthorpej { .compat = "amlogic,meson-rng" },
576e54367aSthorpej DEVICE_COMPAT_EOL
58912cfa14Sjmcneill };
59912cfa14Sjmcneill
60912cfa14Sjmcneill CFATTACH_DECL_NEW(meson_rng, sizeof(struct meson_rng_softc),
61912cfa14Sjmcneill meson_rng_match, meson_rng_attach, NULL, NULL);
62912cfa14Sjmcneill
63912cfa14Sjmcneill static int
meson_rng_match(device_t parent,cfdata_t cf,void * aux)64912cfa14Sjmcneill meson_rng_match(device_t parent, cfdata_t cf, void *aux)
65912cfa14Sjmcneill {
66912cfa14Sjmcneill struct fdt_attach_args * const faa = aux;
67912cfa14Sjmcneill
686e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
69912cfa14Sjmcneill }
70912cfa14Sjmcneill
71912cfa14Sjmcneill static void
meson_rng_attach(device_t parent,device_t self,void * aux)72912cfa14Sjmcneill meson_rng_attach(device_t parent, device_t self, void *aux)
73912cfa14Sjmcneill {
74912cfa14Sjmcneill struct meson_rng_softc * const sc = device_private(self);
75912cfa14Sjmcneill struct fdt_attach_args * const faa = aux;
76912cfa14Sjmcneill const int phandle = faa->faa_phandle;
77912cfa14Sjmcneill struct clk *clk;
78912cfa14Sjmcneill bus_addr_t addr;
79912cfa14Sjmcneill bus_size_t size;
80912cfa14Sjmcneill
81912cfa14Sjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
82912cfa14Sjmcneill aprint_error(": couldn't get registers\n");
83912cfa14Sjmcneill return;
84912cfa14Sjmcneill }
85912cfa14Sjmcneill
86912cfa14Sjmcneill sc->sc_dev = self;
87912cfa14Sjmcneill sc->sc_bst = faa->faa_bst;
88912cfa14Sjmcneill if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
89912cfa14Sjmcneill aprint_error(": couldn't map registers\n");
90912cfa14Sjmcneill return;
91912cfa14Sjmcneill }
92912cfa14Sjmcneill
93813b0337Sjmcneill /* Core clock is optional */
94912cfa14Sjmcneill clk = fdtbus_clock_get(phandle, "core");
95813b0337Sjmcneill if (clk != NULL && clk_enable(clk) != 0) {
96912cfa14Sjmcneill aprint_error(": couldn't enable core clock\n");
97912cfa14Sjmcneill return;
98912cfa14Sjmcneill }
99912cfa14Sjmcneill
100912cfa14Sjmcneill aprint_naive("\n");
101912cfa14Sjmcneill aprint_normal(": Hardware RNG\n");
102912cfa14Sjmcneill
103912cfa14Sjmcneill rndsource_setcb(&sc->sc_rndsource, meson_rng_get, sc);
104912cfa14Sjmcneill rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG,
105912cfa14Sjmcneill RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB);
106912cfa14Sjmcneill }
107912cfa14Sjmcneill
108912cfa14Sjmcneill static void
meson_rng_get(size_t bytes_wanted,void * priv)109912cfa14Sjmcneill meson_rng_get(size_t bytes_wanted, void *priv)
110912cfa14Sjmcneill {
111912cfa14Sjmcneill struct meson_rng_softc * const sc = priv;
112813b0337Sjmcneill uint32_t data;
113912cfa14Sjmcneill
114912cfa14Sjmcneill while (bytes_wanted) {
115813b0337Sjmcneill data = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 0);
116813b0337Sjmcneill rnd_add_data_sync(&sc->sc_rndsource, &data, sizeof(data),
117912cfa14Sjmcneill sizeof(data) * NBBY);
118912cfa14Sjmcneill bytes_wanted -= MIN(bytes_wanted, sizeof(data));
119912cfa14Sjmcneill }
120813b0337Sjmcneill explicit_memset(&data, 0, sizeof(data));
121912cfa14Sjmcneill }
122