diff --git a/sys/dev/clk/starfive/jh7110_clk_stg.c b/sys/dev/clk/starfive/jh7110_clk_stg.c --- a/sys/dev/clk/starfive/jh7110_clk_stg.c +++ b/sys/dev/clk/starfive/jh7110_clk_stg.c @@ -52,6 +52,9 @@ static const char *pcie0_apb_p[] = { "apb_bus" }; static const char *pcie1_apb_p[] = { "apb_bus" }; +static const char *sec_ahb_p[] = { "stg_axiahb" }; +static const char *sec_misc_ahb_p[] = { "stg_axiahb" }; + static const char *usb0_lpm_p[] = { "osc" }; static const char *usb0_stb_p[] = { "osc" }; static const char *usb0_apb_p[] = { "apb_bus" }; @@ -86,6 +89,9 @@ JH7110_GATE(JH7110_STGCLK_PCIE_SLV_MAIN, "pcie_slv_main", pcie_slv_main_p), + JH7110_GATE(JH7110_STGCLK_SEC_AHB, "sec_ahb", sec_ahb_p), + JH7110_GATE(JH7110_STGCLK_SEC_MISC_AHB, "sec_misc_ahb", sec_misc_ahb_p), + JH7110_GATEDIV(JH7110_STGCLK_E2_RTC, "e2_rtc", e2_rtc_p, 24), JH7110_GATE(JH7110_STGCLK_E2_CORE, "e2_core", e2_core_p), JH7110_GATE(JH7110_STGCLK_E2_DBG, "e2_dbg", e2_dbg_p), diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -387,6 +387,7 @@ [RANDOM_PURE_QUALCOMM] = "PURE_QUALCOMM", [RANDOM_PURE_ARMV8] = "PURE_ARMV8", [RANDOM_PURE_ARM_TRNG] = "PURE_ARM_TRNG", + [RANDOM_PURE_STARFIVE_TRNG] = "PURE_STARFIVE_TRNG", /* "ENTROPYSOURCE" */ }; diff --git a/sys/riscv/starfive/files.starfive b/sys/riscv/starfive/files.starfive --- a/sys/riscv/starfive/files.starfive +++ b/sys/riscv/starfive/files.starfive @@ -4,5 +4,6 @@ dev/clk/starfive/jh7110_clk_sys.c standard dev/clk/starfive/jh7110_clk_stg.c standard dev/mmc/host/dwmmc_starfive.c optional dwmmc_starfive fdt +riscv/starfive/jh7110_trng.c optional !random_loadable fdt riscv/starfive/starfive_syscon.c standard diff --git a/sys/riscv/starfive/jh7110_trng.c b/sys/riscv/starfive/jh7110_trng.c new file mode 100644 --- /dev/null +++ b/sys/riscv/starfive/jh7110_trng.c @@ -0,0 +1,205 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Jari Sihvola + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* Registers */ +#define JH7110_TRNG_CTRL 0x0000 +#define CTRL_GEN_RAND 0x1 +#define CTRL_RESEED 0x2 +#define JH7110_TRNG_STAT 0x0004 +#define STAT_SEEDING_DONE (1 << 9) +#define JH7110_TRNG_MODE 0x000c +#define MODE_256BIT (1 << 3) +#define JH7110_TRNG_ISTAT 0x0014 +#define ISTAT_RAND_DONE (1 << 0) +#define ISTAT_LFSR_LOCKUP (1 << 4) +/* There is eight adjacent 32-bit registers for random data */ +#define JH7110_TRNG_DATA 0x0020 +#define DATA_REGS 8 +#define DATA_BYTESIZE (DATA_REGS * sizeof(uint32_t)) + +struct jh7110_trng_softc { + device_t dev; + struct resource *mem_res; + struct callout trngto; + clk_t clk_hclk; + clk_t clk_ahb; + hwreset_t rst; +}; + +static struct ofw_compat_data compat_data[] = { + {"starfive,jh7110-trng", 1}, + {NULL, 0} +}; + +#define RD4(sc, reg) bus_read_4((sc)->mem_res, (reg)) +#define WR4(sc, reg, val) bus_write_4((sc)->mem_res, (reg), (val)) + +static int +jh7110_trng_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "StarFive JH7110 TRNG"); + + return (BUS_PROBE_DEFAULT); +} + +static void +jh7110_trng_harvest(void *arg) +{ + struct jh7110_trng_softc *sc = arg; + uint32_t val, buf[DATA_REGS]; + int i; + + val = RD4(sc, JH7110_TRNG_STAT); + if (val & STAT_SEEDING_DONE) { + val = RD4(sc, JH7110_TRNG_ISTAT); + if (val & ISTAT_RAND_DONE) { + WR4(sc, JH7110_TRNG_ISTAT, ISTAT_RAND_DONE); + + for (i = 0; i != DATA_REGS; i++) + buf[i] = RD4(sc, JH7110_TRNG_DATA + + i * sizeof(uint32_t)); + + random_harvest_queue(buf, DATA_BYTESIZE, + RANDOM_PURE_STARFIVE_TRNG); + } + if (val & ISTAT_LFSR_LOCKUP) + WR4(sc, JH7110_TRNG_CTRL, CTRL_RESEED); + else + WR4(sc, JH7110_TRNG_CTRL, CTRL_GEN_RAND); + } + callout_reset(&sc->trngto, hz, jh7110_trng_harvest, sc); +} + +static int +jh7110_trng_detach(device_t dev) +{ + struct jh7110_trng_softc *sc; + + sc = device_get_softc(dev); + + callout_drain(&sc->trngto); + + if (sc->mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); + + if (sc->clk_hclk != NULL) + clk_release(sc->clk_hclk); + if (sc->clk_ahb != NULL) + clk_release(sc->clk_ahb); + + hwreset_release(sc->rst); + + return (0); +} + +static int +jh7110_trng_attach(device_t dev) +{ + struct jh7110_trng_softc *sc; + uint32_t val; + int rid; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->clk_hclk = NULL; + sc->clk_ahb = NULL; + + /* Initialize callout */ + callout_init(&sc->trngto, CALLOUT_MPSAFE); + + /* Allocate memory resources */ + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->mem_res == NULL) { + jh7110_trng_detach(dev); + return (ENXIO); + } + + /* Get and enable clocks */ + if (clk_get_by_ofw_name(dev, 0, "hclk", &sc->clk_hclk) != 0) { + device_printf(dev, "could not get hclk clock\n"); + sc->clk_hclk = NULL; + return (ENXIO); + } + if (clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb) != 0) { + device_printf(dev, "could not get ahb clock\n"); + sc->clk_ahb = NULL; + return (ENXIO); + } + if (clk_enable(sc->clk_hclk) != 0) { + device_printf(dev, "could not enable hclk clock\n"); + return (ENXIO); + } + if (clk_enable(sc->clk_ahb) != 0) { + device_printf(dev, "could not enable ahb clock\n"); + return (ENXIO); + } + + /* Get and de-assert reset */ + if (hwreset_get_by_ofw_idx(dev, 0, 0, &sc->rst) != 0) { + device_printf(dev, "could not get reset\n"); + return (ENXIO); + } + if (hwreset_deassert(sc->rst) != 0) { + device_printf(dev, "could not deassert reset\n"); + return (ENXIO); + } + + /* Clear register ISTAT */ + val = RD4(sc, JH7110_TRNG_ISTAT); + WR4(sc, JH7110_TRNG_ISTAT, val); + + /* Set 256 bit mode */ + WR4(sc, JH7110_TRNG_MODE, MODE_256BIT); + + /* Start harvesting */ + WR4(sc, JH7110_TRNG_CTRL, CTRL_RESEED); + callout_reset(&sc->trngto, hz, jh7110_trng_harvest, sc); + jh7110_trng_harvest(sc); + + return (0); +} + +static device_method_t jh7110_trng_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jh7110_trng_probe), + DEVMETHOD(device_attach, jh7110_trng_attach), + DEVMETHOD(device_detach, jh7110_trng_detach), + + DEVMETHOD_END +}; + +static driver_t jh7110_trng_driver = { + "jh7110trng", + jh7110_trng_methods, + sizeof(struct jh7110_trng_softc) +}; + +DRIVER_MODULE(jh7110_trng, simplebus, jh7110_trng_driver, 0, 0); +MODULE_VERSION(jh7110_trng, 1); +MODULE_DEPEND(jh7110_trng, randomdev, 1, 1, 1); diff --git a/sys/sys/random.h b/sys/sys/random.h --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -104,6 +104,7 @@ RANDOM_PURE_QUALCOMM, RANDOM_PURE_ARMV8, RANDOM_PURE_ARM_TRNG, + RANDOM_PURE_STARFIVE_TRNG, ENTROPYSOURCE }; _Static_assert(ENTROPYSOURCE <= 32,