diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -82,6 +82,7 @@ # EXT_RESOURCES pseudo devices options EXT_RESOURCES device clk +device hwreset device syscon device syscon_power device riscv_syscon diff --git a/sys/riscv/sifive/sifive_prci.c b/sys/riscv/sifive/sifive_prci.c --- a/sys/riscv/sifive/sifive_prci.c +++ b/sys/riscv/sifive/sifive_prci.c @@ -54,6 +54,7 @@ #include #include "clkdev_if.h" +#include "hwreset_if.h" static struct resource_spec prci_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, @@ -69,6 +70,8 @@ struct resource *res; bus_space_tag_t bst; bus_space_handle_t bsh; + + int nresets; }; struct prci_clk_pll_sc { @@ -94,6 +97,9 @@ #define PRCI_PLL_DIVQ_MASK 0x38000 #define PRCI_PLL_DIVQ_SHIFT 15 +/* Called devicesresetreg on the FU540 */ +#define PRCI_DEVICES_RESET_N 0x28 + #define PRCI_READ(_sc, _reg) \ bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg)) #define PRCI_WRITE(_sc, _reg, _val) \ @@ -155,6 +161,7 @@ struct prci_div_def *div_clks; struct prci_gate_def *gate_clks; struct clk_fixed_def *tlclk_def; + int nresets; }; /* FU540 clock numbers */ @@ -191,6 +198,7 @@ struct prci_config fu540_prci_config = { .pll_clks = fu540_pll_clks, .tlclk_def = &fu540_tlclk_def, + .nresets = 6, }; /* FU740 clock numbers */ @@ -254,6 +262,7 @@ .div_clks = fu740_div_clks, .gate_clks = fu740_gate_clks, .tlclk_def = &fu740_tlclk_def, + .nresets = 7, }; static struct ofw_compat_data compat_data[] = { @@ -547,6 +556,8 @@ if (error) panic("Couldn't finalise clock domain"); + sc->nresets = cfg->nresets; + return (0); fail1: @@ -616,6 +627,48 @@ PRCI_UNLOCK(sc); } +static int +prci_reset_assert(device_t dev, intptr_t id, bool reset) +{ + struct prci_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + if (id >= sc->nresets) + return (ENXIO); + + PRCI_LOCK(sc); + reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N); + if (reset) + reg &= ~(1u << id); + else + reg |= (1u << id); + PRCI_WRITE(sc, PRCI_DEVICES_RESET_N, reg); + PRCI_UNLOCK(sc); + + return (0); +} + +static int +prci_reset_is_asserted(device_t dev, intptr_t id, bool *reset) +{ + struct prci_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + if (id >= sc->nresets) + return (ENXIO); + + PRCI_LOCK(sc); + reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N); + *reset = (reg & (1u << id)) == 0; + PRCI_UNLOCK(sc); + + return (0); +} + static device_method_t prci_methods[] = { DEVMETHOD(device_probe, prci_probe), DEVMETHOD(device_attach, prci_attach), @@ -627,6 +680,10 @@ DEVMETHOD(clkdev_device_lock, prci_device_lock), DEVMETHOD(clkdev_device_unlock, prci_device_unlock), + /* Reset interface */ + DEVMETHOD(hwreset_assert, prci_reset_assert), + DEVMETHOD(hwreset_is_asserted, prci_reset_is_asserted), + DEVMETHOD_END };