Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156902872
D42638.id130216.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D42638.id130216.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D42638: Rockchip RNG
Attached
Detach File
Event Timeline
Log In to Comment