Page MenuHomeFreeBSD

D42638.id130216.diff
No OneTemporary

D42638.id130216.diff

diff --git a/arm64/rockchip/rk_rng.c b/arm64/rockchip/rk_rng.c
new file mode 100644
--- /dev/null
+++ b/arm64/rockchip/rk_rng.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2023 titusm titus@edc.ro
+ *
+ * based on $OpenBSD: rkrng.c,v 1.5 2023/04/14 01:11:32 dlg Exp $
+ * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/random.h>
+#include <sys/selinfo.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/random/randomdev.h>
+#include <dev/random/random_harvestq.h>
+
+static device_attach_t rk_rng_attach;
+static device_detach_t rk_rng_detach;
+static device_probe_t rk_rng_probe;
+
+/* V1 */
+#define RNG_V1_CTRL 0x0008
+#define RNG_V1_CTRL_START (1 << 8)
+#define RNG_V1_CTRL2 0x0200
+#define RNG_V1_CTRL2_OSC_ENABLE (1 << 16)
+#define RNG_V1_DATA0 0x0204
+
+/* True Random Number Generator (TRNG) */
+#define RNG_V2_RST_CTL 0x0004
+#define RNG_V2_RST_CTL_SW_RNG_RESET (0x1U << 1)
+#define RNG_V2_CTL 0x0400
+#define RNG_V2_CTL_RNG_START (0x1U << 0)
+#define RNG_V2_CTL_RNG_ENABLE (0x1U << 1)
+#define RNG_V2_CTL_RING_SEL_MASK (0x3U << 2)
+#define RNG_V2_CTL_RING_SEL_SLOWEST (0x0U << 2)
+#define RNG_V2_CTL_RING_SEL_SLOW (0x1U << 2)
+#define RNG_V2_CTL_RING_SEL_FAST (0x2U << 2)
+#define RNG_V2_CTL_RING_SEL_FASTEST (0x3U << 2)
+#define RNG_V2_CTL_RNG_LEN_MASK (0x3U << 4)
+#define RNG_V2_CTL_RNG_LEN_64 (0x0U << 4)
+#define RNG_V2_CTL_RNG_LEN_128 (0x1U << 4)
+#define RNG_V2_CTL_RNG_LEN_192 (0x2U << 4)
+#define RNG_V2_CTL_RNG_LEN_256 (0x3U << 4)
+#define RNG_V2_SAMPLE_CNT 0x0404
+#define RNG_V2_DATA0 0x0410
+
+#define RNG_DWORDS 8
+#define RNG_CALLOUT_TICKS (hz * 4)
+#define RNG_TIMEOUT_TICKS 100
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->sc_res[0], (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->sc_res[0], (_r))
+
+#if 0
+ #define dprintf(dev, format, arg...) device_printf(dev, "%s: " format, __func__, arg)
+#else
+ #define dprintf(dev, format, arg...)
+#endif
+
+static struct resource_spec rk_rng_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+
+struct rk_rng_softc {
+ device_t sc_dev;
+ struct resource *sc_res[1];
+ struct rk_rng_conf * sc_conf;
+ struct callout sc_rngto;
+ uint8_t sc_pstat;
+ uint8_t sc_wdog;
+};
+
+struct rk_rng_conf {
+ unsigned int ver;
+ const char *name;
+ uint32_t (*on)(struct rk_rng_softc *sc);
+ void (*off)(struct rk_rng_softc *sc);
+ bus_size_t data_out;
+};
+
+enum RK_RNG_PSTAT {
+ RK_RNG_STOPPED = 0,
+ RK_RNG_STARTING,
+ RK_RNG_STARTED
+ };
+
+static uint32_t rk_rng_v1_on(struct rk_rng_softc *);
+static void rk_rng_v1_off(struct rk_rng_softc *);
+
+static const struct rk_rng_conf rkv1_conf = {
+ .ver = 1,
+ .name = "Rockchip RNG v1",
+ .on = rk_rng_v1_on,
+ .off = rk_rng_v1_off,
+ .data_out = RNG_V1_DATA0,
+};
+
+static uint32_t rk_rng_v2_on(struct rk_rng_softc *);
+static void rk_rng_v2_off(struct rk_rng_softc *);
+
+static const struct rk_rng_conf rkv2_conf = {
+ .ver = 2,
+ .name = "Rockchip RNG v2",
+ .on = rk_rng_v2_on,
+ .off = rk_rng_v2_off,
+ .data_out = RNG_V2_DATA0,
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"rockchip,cryptov1-rng", (uintptr_t)&rkv1_conf},
+ {"rockchip,cryptov2-rng", (uintptr_t)&rkv2_conf},
+ {NULL, 0}
+};
+
+static uint32_t
+rk_rng_v1_on(struct rk_rng_softc *sc)
+{
+ if(sc->sc_pstat == RK_RNG_STOPPED) {
+ WR4(sc, RNG_V1_CTRL2, RNG_V1_CTRL2_OSC_ENABLE |100);
+ WR4(sc, RNG_V1_CTRL, (RNG_V1_CTRL_START << 16) | RNG_V1_CTRL_START);
+ sc->sc_pstat = RK_RNG_STARTING;
+ } else {
+ sc->sc_pstat = (RD4(sc, RNG_V1_CTRL) & RNG_V1_CTRL_START) ?
+ RK_RNG_STARTING : RK_RNG_STARTED;
+ }
+ return (sc->sc_pstat);
+}
+
+
+
+static void
+rk_rng_v1_off(struct rk_rng_softc *sc)
+{
+ WR4(sc, RNG_V1_CTRL, (RNG_V1_CTRL_START << 16) | 0);
+ sc->sc_pstat = RK_RNG_STOPPED;
+}
+
+static uint32_t
+rk_rng_v2_on(struct rk_rng_softc *sc)
+{
+ uint32_t mask, val;
+
+ if(sc->sc_pstat == RK_RNG_STOPPED) {
+ mask = RNG_V2_CTL_RNG_START | RNG_V2_CTL_RNG_ENABLE |
+ RNG_V2_CTL_RING_SEL_MASK | RNG_V2_CTL_RNG_LEN_MASK;
+ val = RNG_V2_CTL_RNG_START | RNG_V2_CTL_RNG_ENABLE |
+ RNG_V2_CTL_RING_SEL_SLOW | RNG_V2_CTL_RNG_LEN_256;
+ WR4(sc, RNG_V2_SAMPLE_CNT, 100);
+ WR4(sc, RNG_V2_CTL, (mask << 16) | val);
+ sc->sc_pstat = RK_RNG_STARTING;
+ } else {
+ sc->sc_pstat = (RD4(sc, RNG_V2_CTL) & RNG_V2_CTL_RNG_START) ?
+ RK_RNG_STARTING : RK_RNG_STARTED;
+
+ }
+ return (sc->sc_pstat);
+}
+
+
+static void
+rk_rng_v2_off(struct rk_rng_softc *sc)
+{
+ uint32_t val = RNG_V2_CTL_RNG_START | RNG_V2_CTL_RNG_ENABLE;
+
+ WR4(sc, RNG_V2_CTL, (val << 16) | 0);
+ sc->sc_pstat = RK_RNG_STOPPED;
+}
+
+
+
+static void
+rk_rng_harvest(void *arg)
+{
+ struct rk_rng_softc *sc = arg;
+ uint32_t reg, buf[RNG_DWORDS];
+
+ if(sc->sc_wdog > RNG_TIMEOUT_TICKS) {
+ sc->sc_wdog = 0;
+ dprintf(sc->sc_dev, "watchdog timeout after %d tries\n", RNG_TIMEOUT_TICKS);
+ goto out;
+ }
+
+ if(sc->sc_conf->on(sc) != RK_RNG_STARTED) {
+ sc->sc_wdog++;
+ callout_reset_sbt(&sc->sc_rngto, SBT_1US * 100, 0, rk_rng_harvest, sc, 0);
+ return;
+ }
+
+ for(reg = 0; reg < RNG_DWORDS;reg++) {
+ buf[reg] = RD4(sc, (sc->sc_conf->data_out + (reg << 2)));
+ dprintf(sc->sc_dev, "reg[%d] => %08x\n", reg, buf[reg]);
+ }
+ random_harvest_queue(buf, sizeof(buf), RANDOM_PURE_BROADCOM);
+
+out:
+ sc->sc_wdog = 0;
+ sc->sc_conf->off(sc);
+ callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, rk_rng_harvest, sc);
+}
+
+
+static int
+rk_rng_probe(device_t dev)
+{
+ struct rk_rng_conf *compat;
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ compat = (struct rk_rng_conf *) ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ if (!compat)
+ return (ENXIO);
+
+ device_set_desc(dev, compat->name);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rk_rng_attach(device_t dev)
+{
+ struct rk_rng_softc *sc;
+ int error = 0, i, ncells;
+ clk_t clk;
+ hwreset_t hwreset = NULL;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ sc->sc_conf = (struct rk_rng_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ if(!sc->sc_conf) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ if (bus_alloc_resources(dev, rk_rng_spec, sc->sc_res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ node = ofw_bus_get_node(dev);
+
+ if (OF_hasprop(node, "assigned-clocks")) {
+ error = clk_set_assigned(dev, node);
+ if(error) {
+ device_printf(dev, "Could not set assigned clocks\n");
+ goto fail;
+ }
+ }
+
+ error = ofw_bus_parse_xref_list_get_length(node, "clocks",
+ "#clock-cells", &ncells);
+ if (error != 0 || ncells < 2) {
+ device_printf(dev, "couldn't find enough clocks\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ for(i = 0;i < ncells;i++) {
+ error = clk_get_by_ofw_index(dev, node, i, &clk);
+ if(error) {
+ device_printf(dev, "Could not get clock #%d\n", i);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = clk_enable(clk);
+ if(error) {
+ device_printf(dev, "Could not enable clock #%s\n", clk_get_name(clk));
+ error = ENXIO;
+ goto fail;
+ }
+ }
+
+ error = hwreset_get_by_ofw_name(dev, node, "reset", &hwreset);
+ if (error != 0 && error != ENOENT) {
+ device_printf(dev, "Cannot get 'reset' reset\n");
+ error = ENXIO;
+ /* goto fail;*/
+ }
+
+ if (hwreset != NULL) {
+ error = hwreset_deassert(hwreset);
+ if (error != 0) {
+ device_printf(dev, "Cannot deassert reset\n");
+ goto fail;
+ }
+ }
+
+ /* Initialize callout */
+ callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
+ callout_reset(&sc->sc_rngto, hz, rk_rng_harvest, sc);
+
+ return (0);
+fail:
+ return (error);
+}
+
+static int
+rk_rng_detach(device_t dev)
+{
+ struct rk_rng_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ /* Stop the RNG */
+ if(sc->sc_pstat != RK_RNG_STOPPED)
+ sc->sc_conf->off(sc);
+ /* Drain the callout it */
+ callout_drain(&sc->sc_rngto);
+
+ /* Release memory resource */
+ if (sc->sc_res[0] != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_res[0]);
+
+ return (0);
+}
+
+static device_method_t rk_rng_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rk_rng_probe),
+ DEVMETHOD(device_attach, rk_rng_attach),
+ DEVMETHOD(device_detach, rk_rng_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t rk_rng_driver = {
+ "rkrng",
+ rk_rng_methods,
+ sizeof(struct rk_rng_softc)
+};
+
+DRIVER_MODULE(rk_rng, simplebus, rk_rng_driver, 0, 0);
+DRIVER_MODULE(rk_rng, ofwbus, rk_rng_driver, 0, 0);
+MODULE_VERSION(rk_rng, 1);
+MODULE_DEPEND(rk_rng, randomdev, 1, 1, 1);

File Metadata

Mime Type
text/plain
Expires
Mon, May 18, 5:42 AM (10 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33234721
Default Alt Text
D42638.id130216.diff (10 KB)

Event Timeline