diff --git a/sys/dev/clk/starfive/jh7110_clk.c b/sys/dev/clk/starfive/jh7110_clk.c new file mode 100644 index 000000000000..adb5707b3f64 --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk.c @@ -0,0 +1,277 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Emmanuel Vadot + * Copyright (c) 2022 Mitchell Horne + * Copyright (c) 2024 Jari Sihvola + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include "clkdev_if.h" +#include "hwreset_if.h" + +#define JH7110_DIV_MASK 0xffffff +#define JH7110_MUX_SHIFT 24 +#define JH7110_MUX_MASK 0x3f000000 +#define JH7110_ENABLE_SHIFT 31 + +#define REG_SIZE 4 + +struct jh7110_clk_sc { + uint32_t offset; + uint32_t flags; + uint64_t d_max; + int id; +}; + +#define DIV_ROUND_CLOSEST(n, d) (((n) + (d) / 2) / (d)) + +#define READ4(_sc, _off) \ + bus_read_4(_sc->mem_res, _off) +#define WRITE4(_sc, _off, _val) \ + bus_write_4(_sc->mem_res, _off, _val) + +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +/* Reset functions */ + +int +jh7110_reset_assert(device_t dev, intptr_t id, bool assert) +{ + struct jh7110_clkgen_softc *sc; + uint32_t regvalue, offset, bitmask = 1UL << id % 32; + + sc = device_get_softc(dev); + offset = sc->reset_selector_offset + id / 32 * 4; + + mtx_lock(&sc->mtx); + + regvalue = READ4(sc, offset); + + if (assert) + regvalue |= bitmask; + else + regvalue &= ~bitmask; + WRITE4(sc, offset, regvalue); + + mtx_unlock(&sc->mtx); + + return (0); +} + +int +jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset) +{ + struct jh7110_clkgen_softc *sc; + uint32_t regvalue, offset, bitmask; + + sc = device_get_softc(dev); + offset = sc->reset_status_offset + id / 32 * 4; + + mtx_lock(&sc->mtx); + + regvalue = READ4(sc, offset); + bitmask = 1UL << id % 32; + + mtx_unlock(&sc->mtx); + + *reset = (regvalue & bitmask) == 0; + + return (0); +} + +/* Clock functions */ + +static int +jh7110_clk_init(struct clknode *clk, device_t dev) +{ + struct jh7110_clkgen_softc *sc; + struct jh7110_clk_sc *sc_clk; + uint32_t reg; + int idx = 0; + + sc = device_get_softc(clknode_get_device(clk)); + sc_clk = clknode_get_softc(clk); + + if (sc_clk->flags & JH7110_CLK_HAS_MUX) { + DEVICE_LOCK(clk); + reg = READ4(sc, sc_clk->offset); + DEVICE_UNLOCK(clk); + idx = (reg & JH7110_MUX_MASK) >> JH7110_MUX_SHIFT; + } + + clknode_init_parent_idx(clk, idx); + + return (0); +} + +static int +jh7110_clk_set_gate(struct clknode *clk, bool enable) +{ + struct jh7110_clkgen_softc *sc; + struct jh7110_clk_sc *sc_clk; + uint32_t reg; + + sc = device_get_softc(clknode_get_device(clk)); + sc_clk = clknode_get_softc(clk); + + if ((sc_clk->flags & JH7110_CLK_HAS_GATE) == 0) + return (0); + + DEVICE_LOCK(clk); + + reg = READ4(sc, sc_clk->offset); + if (enable) + reg |= (1 << JH7110_ENABLE_SHIFT); + else + reg &= ~(1 << JH7110_ENABLE_SHIFT); + WRITE4(sc, sc_clk->offset, reg); + + DEVICE_UNLOCK(clk); + + return (0); +} + +static int +jh7110_clk_set_mux(struct clknode *clk, int idx) +{ + struct jh7110_clkgen_softc *sc; + struct jh7110_clk_sc *sc_clk; + uint32_t reg; + + sc = device_get_softc(clknode_get_device(clk)); + sc_clk = clknode_get_softc(clk); + + if ((sc_clk->flags & JH7110_CLK_HAS_MUX) == 0) + return (ENXIO); + + /* Checking index size */ + if ((idx & (JH7110_MUX_MASK >> JH7110_MUX_SHIFT)) != idx) + return (EINVAL); + + DEVICE_LOCK(clk); + + reg = READ4(sc, sc_clk->offset) & ~JH7110_MUX_MASK; + reg |= idx << JH7110_MUX_SHIFT; + WRITE4(sc, sc_clk->offset, reg); + + DEVICE_UNLOCK(clk); + + return (0); +} + +static int +jh7110_clk_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct jh7110_clkgen_softc *sc; + struct jh7110_clk_sc *sc_clk; + uint32_t divisor; + + sc = device_get_softc(clknode_get_device(clk)); + sc_clk = clknode_get_softc(clk); + + /* Returning error here causes panic */ + if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0) + return (0); + + DEVICE_LOCK(clk); + + divisor = READ4(sc, sc_clk->offset) & JH7110_DIV_MASK; + + DEVICE_UNLOCK(clk); + + if (divisor) + *freq = *freq / divisor; + else + *freq = 0; + + return (0); +} + +static int +jh7110_clk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, + int flags, int *done) +{ + struct jh7110_clkgen_softc *sc; + struct jh7110_clk_sc *sc_clk; + uint32_t divisor; + + sc = device_get_softc(clknode_get_device(clk)); + sc_clk = clknode_get_softc(clk); + + if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0) + return (0); + + divisor = MIN(MAX(DIV_ROUND_CLOSEST(fin, *fout), 1UL), sc_clk->d_max); + + if (flags & CLK_SET_DRYRUN) + goto done; + + DEVICE_LOCK(clk); + + divisor |= READ4(sc, sc_clk->offset) & ~JH7110_DIV_MASK; + WRITE4(sc, sc_clk->offset, divisor); + + DEVICE_UNLOCK(clk); + +done: + *fout = divisor; + *done = 1; + + return (0); +} + +static clknode_method_t jh7110_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, jh7110_clk_init), + CLKNODEMETHOD(clknode_set_gate, jh7110_clk_set_gate), + CLKNODEMETHOD(clknode_set_mux, jh7110_clk_set_mux), + CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, jh7110_clk_set_freq), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(jh7110_clknode, jh7110_clknode_class, jh7110_clknode_methods, + sizeof(struct jh7110_clk_sc), clknode_class); + +int +jh7110_clk_register(struct clkdom *clkdom, const struct jh7110_clk_def *clkdef) +{ + struct clknode *clk; + struct jh7110_clk_sc *sc; + + clk = clknode_create(clkdom, &jh7110_clknode_class, &clkdef->clkdef); + if (clk == NULL) + return (-1); + + sc = clknode_get_softc(clk); + + sc->offset = clkdef->clkdef.id * REG_SIZE; + + sc->flags = clkdef->flags; + sc->id = clkdef->clkdef.id; + sc->d_max = clkdef->d_max; + + clknode_register(clkdom, clk); + + return (0); +} diff --git a/sys/dev/clk/starfive/jh7110_clk.h b/sys/dev/clk/starfive/jh7110_clk.h new file mode 100644 index 000000000000..882f82032d44 --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk.h @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Jari Sihvola + */ + +#ifndef _JH7110_CLK_H_ +#define _JH7110_CLK_H_ + +#include + +#define JH7110_CLK_HAS_GATE 0x01 +#define JH7110_CLK_HAS_MUX 0x02 +#define JH7110_CLK_HAS_DIV 0x04 +#define JH7110_CLK_HAS_INV 0x08 + +#define AONCRG_RESET_SELECTOR 0x38 +#define AONCRG_RESET_STATUS 0x3c +#define STGCRG_RESET_SELECTOR 0x74 +#define STGCRG_RESET_STATUS 0x78 +#define SYSCRG_RESET_SELECTOR 0x2f8 +#define SYSCRG_RESET_STATUS 0x308 + +struct jh7110_clkgen_softc { + struct mtx mtx; + struct clkdom *clkdom; + struct resource *mem_res; + uint32_t reset_status_offset; + uint32_t reset_selector_offset; +}; + +struct jh7110_clk_def { + struct clknode_init_def clkdef; + uint32_t offset; + uint32_t flags; + uint64_t d_max; +}; + +#define JH7110_CLK(_idx, _name, _pn, _d_max, _flags) \ +{ \ + .clkdef.id = _idx, \ + .clkdef.name = _name, \ + .clkdef.parent_names = _pn, \ + .clkdef.parent_cnt = nitems(_pn), \ + .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ + .flags = _flags, \ + .d_max = _d_max, \ +} + +#define JH7110_GATE(_idx, _name, _pn) \ + JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_GATE) +#define JH7110_MUX(_idx, _name, _pn) \ + JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_MUX) +#define JH7110_DIV(_idx, _name, _pn, _d_max) \ + JH7110_CLK(_idx, _name, _pn, _d_max, JH7110_CLK_HAS_DIV) +#define JH7110_GATEMUX(_idx, _name, _pn) \ + JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_GATE | \ + JH7110_CLK_HAS_MUX) +#define JH7110_GATEDIV(_idx, _name, _pn, _d_max) \ + JH7110_CLK(_idx, _name, _pn, _d_max, JH7110_CLK_HAS_GATE | \ + JH7110_CLK_HAS_DIV) +#define JH7110_INV(_idx, _name, _pn) \ + JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_INV) + +int jh7110_clk_register(struct clkdom *clkdom, + const struct jh7110_clk_def *clkdef); +int jh7110_ofw_map(struct clkdom *clkdom, uint32_t ncells, phandle_t *cells, + struct clknode **clk); +int jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset); +int jh7110_reset_assert(device_t dev, intptr_t id, bool assert); + +#endif /* _JH7110_CLK_H_ */ diff --git a/sys/dev/clk/starfive/jh7110_clk_aon.c b/sys/dev/clk/starfive/jh7110_clk_aon.c new file mode 100644 index 000000000000..21b15142835e --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk_aon.c @@ -0,0 +1,168 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2016 Michal Meloun + * Copyright (c) 2020 Oskar Holmlund + * Copyright (c) 2024 Jari Sihvola + */ + +/* Clocks for JH7110 AON group. PLL driver must be attached before this. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "clkdev_if.h" +#include "hwreset_if.h" + +static struct ofw_compat_data compat_data[] = { + { "starfive,jh7110-aoncrg", 1 }, + { NULL, 0 } +}; + +static struct resource_spec res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + RESOURCE_SPEC_END +}; + +/* parents */ +static const char *gmac0_axi_p[] = { "stg_axiahb" }; +static const char *gmac0_ahb_p[] = { "stg_axiahb" }; +static const char *gmac0_tx_inv_p[] = { "gmac0_tx" }; +static const char *gmac0_tx_p[] = { "gmac0_gtxclk", "gmac0_rmii_rtx" }; +static const char *gmac0_rmii_rtx_p[] = { "gmac0_rmii_refin" }; + +/* AON clocks */ +static const struct jh7110_clk_def aon_clks[] = { + JH7110_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", gmac0_axi_p), + JH7110_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", gmac0_ahb_p), + JH7110_GATEMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx", gmac0_tx_p), + JH7110_INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", gmac0_tx_inv_p), + JH7110_DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx", + gmac0_rmii_rtx_p, 30), +}; + +static int +jh7110_clk_aon_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 AON clock generator"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jh7110_clk_aon_attach(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + int err; + + sc = device_get_softc(dev); + + sc->reset_status_offset = AONCRG_RESET_STATUS; + sc->reset_selector_offset = AONCRG_RESET_SELECTOR; + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + err = bus_alloc_resources(dev, res_spec, &sc->mem_res); + if (err != 0) { + device_printf(dev, "Couldn't allocate resources, error %d\n", + err); + return (ENXIO); + } + + sc->clkdom = clkdom_create(dev); + if (sc->clkdom == NULL) { + device_printf(dev, "Couldn't create clkdom, error %d\n", err); + return (ENXIO); + } + + for (int i = 0; i < nitems(aon_clks); i++) { + err = jh7110_clk_register(sc->clkdom, &aon_clks[i]); + if (err != 0) { + device_printf(dev, + "Couldn't register clk %s, error %d\n", + aon_clks[i].clkdef.name, err); + return (ENXIO); + } + } + + if (clkdom_finit(sc->clkdom) != 0) + panic("Cannot finalize clkdom initialization\n"); + + if (bootverbose) + clkdom_dump(sc->clkdom); + + hwreset_register_ofw_provider(dev); + + return (0); +} + +static void +jh7110_clk_aon_device_lock(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +static void +jh7110_clk_aon_device_unlock(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static int +jh7110_clk_aon_detach(device_t dev) +{ + /* Detach not supported */ + return (EBUSY); +} + +static device_method_t jh7110_clk_aon_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jh7110_clk_aon_probe), + DEVMETHOD(device_attach, jh7110_clk_aon_attach), + DEVMETHOD(device_detach, jh7110_clk_aon_detach), + + /* clkdev interface */ + DEVMETHOD(clkdev_device_lock, jh7110_clk_aon_device_lock), + DEVMETHOD(clkdev_device_unlock, jh7110_clk_aon_device_unlock), + + /* Reset interface */ + DEVMETHOD(hwreset_assert, jh7110_reset_assert), + DEVMETHOD(hwreset_is_asserted, jh7110_reset_is_asserted), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(jh7110_aon, jh7110_aon_driver, jh7110_clk_aon_methods, + sizeof(struct jh7110_clkgen_softc)); +EARLY_DRIVER_MODULE(jh7110_aon, simplebus, jh7110_aon_driver, 0, 0, + BUS_PASS_BUS + BUS_PASS_ORDER_LATE); +MODULE_VERSION(jh7110_aon, 1); diff --git a/sys/dev/clk/starfive/jh7110_clk_pll.c b/sys/dev/clk/starfive/jh7110_clk_pll.c new file mode 100644 index 000000000000..5882f33984ae --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk_pll.c @@ -0,0 +1,386 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Jari Sihvola + * Copyright (c) 2024 The FreeBSD Foundation + * + * Portions of this software were developed by Mitchell Horne + * under sponsorship from the FreeBSD Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "clkdev_if.h" +#include "syscon_if.h" + +#define JH7110_SYS_SYSCON_SYSCFG24 0x18 +#define JH7110_SYS_SYSCON_SYSCFG28 0x1c +#define JH7110_SYS_SYSCON_SYSCFG32 0x20 +#define JH7110_SYS_SYSCON_SYSCFG36 0x24 +#define JH7110_SYS_SYSCON_SYSCFG40 0x28 +#define JH7110_SYS_SYSCON_SYSCFG44 0x2c +#define JH7110_SYS_SYSCON_SYSCFG48 0x30 +#define JH7110_SYS_SYSCON_SYSCFG52 0x34 + +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +#define PLL_MASK_FILL(sc, id) \ +do { \ + sc->dacpd_mask = PLL## id ##_DACPD_MASK; \ + sc->dsmpd_mask = PLL## id ##_DSMPD_MASK; \ + sc->fbdiv_mask = PLL## id ##_FBDIV_MASK; \ + sc->frac_mask = PLL## id ##_FRAC_MASK; \ + sc->prediv_mask = PLL## id ##_PREDIV_MASK; \ + sc->postdiv1_mask = PLL## id ##_POSTDIV1_MASK; \ +} while (0) + +#define PLL_SHIFT_FILL(sc, id) \ +do { \ + sc->dacpd_shift = PLL## id ##_DACPD_SHIFT; \ + sc->dsmpd_shift = PLL## id ##_DSMPD_SHIFT; \ + sc->fbdiv_shift = PLL## id ##_FBDIV_SHIFT; \ + sc->frac_shift = PLL## id ##_FRAC_SHIFT; \ + sc->prediv_shift = PLL## id ##_PREDIV_SHIFT; \ + sc->postdiv1_shift = PLL## id ##_POSTDIV1_SHIFT; \ +} while (0) + +struct jh7110_clk_pll_softc { + struct mtx mtx; + struct clkdom *clkdom; + struct syscon *syscon; +}; + +struct jh7110_pll_clknode_softc { + uint32_t dacpd_offset; + uint32_t dsmpd_offset; + uint32_t fbdiv_offset; + uint32_t frac_offset; + uint32_t prediv_offset; + uint32_t postdiv1_offset; + + uint32_t dacpd_mask; + uint32_t dsmpd_mask; + uint32_t fbdiv_mask; + uint32_t frac_mask; + uint32_t prediv_mask; + uint32_t postdiv1_mask; + + uint32_t dacpd_shift; + uint32_t dsmpd_shift; + uint32_t fbdiv_shift; + uint32_t frac_shift; + uint32_t prediv_shift; + uint32_t postdiv1_shift; + + const struct jh7110_pll_syscon_value *syscon_arr; + int syscon_nitems; +}; + +static const char *pll_parents[] = { "osc" }; + +static struct jh7110_clk_def pll_out_clks[] = { + { + .clkdef.id = JH7110_PLLCLK_PLL0_OUT, + .clkdef.name = "pll0_out", + .clkdef.parent_names = pll_parents, + .clkdef.parent_cnt = nitems(pll_parents), + .clkdef.flags = CLK_NODE_STATIC_STRINGS, + }, + { + .clkdef.id = JH7110_PLLCLK_PLL1_OUT, + .clkdef.name = "pll1_out", + .clkdef.parent_names = pll_parents, + .clkdef.parent_cnt = nitems(pll_parents), + .clkdef.flags = CLK_NODE_STATIC_STRINGS, + }, + { + .clkdef.id = JH7110_PLLCLK_PLL2_OUT, + .clkdef.name = "pll2_out", + .clkdef.parent_names = pll_parents, + .clkdef.parent_cnt = nitems(pll_parents), + .clkdef.flags = CLK_NODE_STATIC_STRINGS, + }, +}; + +static int jh7110_clk_pll_register(struct clkdom *clkdom, + struct jh7110_clk_def *clkdef); + +static int +jh7110_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct jh7110_clk_pll_softc *sc; + struct jh7110_pll_clknode_softc *clk_sc; + uint32_t dacpd, dsmpd, fbdiv, prediv, postdiv1; + uint64_t frac, fcal = 0; + + sc = device_get_softc(clknode_get_device(clk)); + clk_sc = clknode_get_softc(clk); + + DEVICE_LOCK(clk); + + dacpd = (SYSCON_READ_4(sc->syscon, clk_sc->dacpd_offset) & clk_sc->dacpd_mask) >> + clk_sc->dacpd_shift; + dsmpd = (SYSCON_READ_4(sc->syscon, clk_sc->dsmpd_offset) & clk_sc->dsmpd_mask) >> + clk_sc->dsmpd_shift; + fbdiv = (SYSCON_READ_4(sc->syscon, clk_sc->fbdiv_offset) & clk_sc->fbdiv_mask) >> + clk_sc->fbdiv_shift; + prediv = (SYSCON_READ_4(sc->syscon, clk_sc->prediv_offset) & clk_sc->prediv_mask) >> + clk_sc->prediv_shift; + postdiv1 = (SYSCON_READ_4(sc->syscon, clk_sc->postdiv1_offset) & + clk_sc->postdiv1_mask) >> clk_sc->postdiv1_shift; + frac = (SYSCON_READ_4(sc->syscon, clk_sc->frac_offset) & clk_sc->frac_mask) >> + clk_sc->frac_shift; + + DEVICE_UNLOCK(clk); + + /* dacpd and dsmpd both being 0 entails Fraction Multiple Mode */ + if (dacpd == 0 && dsmpd == 0) + fcal = frac * FRAC_PATR_SIZE / (1 << 24); + + *freq = *freq / FRAC_PATR_SIZE * (fbdiv * FRAC_PATR_SIZE + fcal) / + prediv / (1 << postdiv1); + + return (0); +} + +static int +jh7110_clk_pll_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, + int flags, int *done) +{ + struct jh7110_clk_pll_softc *sc; + struct jh7110_pll_clknode_softc *clk_sc; + const struct jh7110_pll_syscon_value *syscon_val = NULL; + + sc = device_get_softc(clknode_get_device(clk)); + clk_sc = clknode_get_softc(clk); + + for (int i = 0; i != clk_sc->syscon_nitems; i++) { + if (*fout == clk_sc->syscon_arr[i].freq) { + syscon_val = &clk_sc->syscon_arr[i]; + } + } + + if (syscon_val == NULL) { + printf("%s: tried to set an unknown frequency %ju for %s\n", + __func__, *fout, clknode_get_name(clk)); + return (EINVAL); + } + + if ((flags & CLK_SET_DRYRUN) != 0) { + *done = 1; + return (0); + } + + DEVICE_LOCK(clk); + + SYSCON_MODIFY_4(sc->syscon, clk_sc->dacpd_offset, clk_sc->dacpd_mask, + syscon_val->dacpd << clk_sc->dacpd_shift & clk_sc->dacpd_mask); + SYSCON_MODIFY_4(sc->syscon, clk_sc->dsmpd_offset, clk_sc->dsmpd_mask, + syscon_val->dsmpd << clk_sc->dsmpd_shift & clk_sc->dsmpd_mask); + SYSCON_MODIFY_4(sc->syscon, clk_sc->prediv_offset, clk_sc->prediv_mask, + syscon_val->prediv << clk_sc->prediv_shift & clk_sc->prediv_mask); + SYSCON_MODIFY_4(sc->syscon, clk_sc->fbdiv_offset, clk_sc->fbdiv_mask, + syscon_val->fbdiv << clk_sc->fbdiv_shift & clk_sc->fbdiv_mask); + SYSCON_MODIFY_4(sc->syscon, clk_sc->postdiv1_offset, + clk_sc->postdiv1_mask, (syscon_val->postdiv1 >> 1) << + clk_sc->postdiv1_shift & clk_sc->postdiv1_mask); + + if (!syscon_val->dacpd && !syscon_val->dsmpd) { + SYSCON_MODIFY_4(sc->syscon, clk_sc->frac_offset, clk_sc->frac_mask, + syscon_val->frac << clk_sc->frac_shift & clk_sc->frac_mask); + } + + DEVICE_UNLOCK(clk); + + *done = 1; + return (0); +} + +static int +jh7110_clk_pll_init(struct clknode *clk, device_t dev) +{ + clknode_init_parent_idx(clk, 0); + + return (0); +} + +static int +jh7110_clk_pll_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "starfive,jh7110-pll")) + return (ENXIO); + + device_set_desc(dev, "StarFive JH7110 PLL clock generator"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jh7110_clk_pll_attach(device_t dev) +{ + struct jh7110_clk_pll_softc *sc; + int error; + + sc = device_get_softc(dev); + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + sc->clkdom = clkdom_create(dev); + if (sc->clkdom == NULL) { + device_printf(dev, "Couldn't create clkdom\n"); + return (ENXIO); + } + + error = syscon_get_by_ofw_node(dev, OF_parent(ofw_bus_get_node(dev)), + &sc->syscon); + if (error != 0) { + device_printf(dev, "Couldn't get syscon handle of parent\n"); + return (error); + } + + for (int i = 0; i < nitems(pll_out_clks); i++) { + error = jh7110_clk_pll_register(sc->clkdom, &pll_out_clks[i]); + if (error != 0) + device_printf(dev, "Couldn't register clock %s: %d\n", + pll_out_clks[i].clkdef.name, error); + } + + error = clkdom_finit(sc->clkdom); + if (error != 0) { + device_printf(dev, "clkdom_finit() returned %d\n", error); + } + + if (bootverbose) + clkdom_dump(sc->clkdom); + + return (0); +} + +static void +jh7110_clk_pll_device_lock(device_t dev) +{ + struct jh7110_clk_pll_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +static void +jh7110_clk_pll_device_unlock(device_t dev) +{ + struct jh7110_clk_pll_softc *sc; + + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static clknode_method_t jh7110_pllnode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, jh7110_clk_pll_init), + CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_pll_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, jh7110_clk_pll_set_freq), + + CLKNODEMETHOD_END +}; + +static device_method_t jh7110_clk_pll_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jh7110_clk_pll_probe), + DEVMETHOD(device_attach, jh7110_clk_pll_attach), + + /* clkdev interface */ + DEVMETHOD(clkdev_device_lock, jh7110_clk_pll_device_lock), + DEVMETHOD(clkdev_device_unlock, jh7110_clk_pll_device_unlock), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(jh7110_pllnode, jh7110_pllnode_class, jh7110_pllnode_methods, + sizeof(struct jh7110_pll_clknode_softc), clknode_class); +DEFINE_CLASS_0(jh7110_clk_pll, jh7110_clk_pll_driver, jh7110_clk_pll_methods, + sizeof(struct jh7110_clk_pll_softc)); +EARLY_DRIVER_MODULE(jh7110_clk_pll, simplebus, jh7110_clk_pll_driver, 0, 0, + BUS_PASS_BUS + BUS_PASS_ORDER_EARLY); +MODULE_VERSION(jh7110_clk_pll, 1); + +int +jh7110_clk_pll_register(struct clkdom *clkdom, struct jh7110_clk_def *clkdef) +{ + struct clknode *clk = NULL; + struct jh7110_pll_clknode_softc *sc; + + clk = clknode_create(clkdom, &jh7110_pllnode_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + + switch (clkdef->clkdef.id) { + case JH7110_PLLCLK_PLL0_OUT: + sc->syscon_arr = jh7110_pll0_syscon_freq; + sc->syscon_nitems = nitems(jh7110_pll0_syscon_freq); + PLL_MASK_FILL(sc, 0); + PLL_SHIFT_FILL(sc, 0); + sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG24; + sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG24; + sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG28; + sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG32; + sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG36; + sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG32; + break; + case JH7110_PLLCLK_PLL1_OUT: + sc->syscon_arr = jh7110_pll1_syscon_freq; + sc->syscon_nitems = nitems(jh7110_pll1_syscon_freq); + PLL_MASK_FILL(sc, 1); + PLL_SHIFT_FILL(sc, 1); + sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG36; + sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG36; + sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG36; + sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG40; + sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG44; + sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG40; + break; + case JH7110_PLLCLK_PLL2_OUT: + sc->syscon_arr = jh7110_pll2_syscon_freq; + sc->syscon_nitems = nitems(jh7110_pll2_syscon_freq); + PLL_MASK_FILL(sc, 2); + PLL_SHIFT_FILL(sc, 2); + sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG44; + sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG44; + sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG44; + sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG48; + sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG52; + sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG48; + break; + default: + return (EINVAL); + } + + clknode_register(clkdom, clk); + + return (0); +} diff --git a/sys/dev/clk/starfive/jh7110_clk_pll.h b/sys/dev/clk/starfive/jh7110_clk_pll.h new file mode 100644 index 000000000000..700072a4b465 --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk_pll.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: MIT */ +/* + * StarFive JH7110 PLL Clock Generator Driver + * + * Copyright (C) 2022 Xingyu Wu + */ + +#define PLL0_DACPD_SHIFT 24 +#define PLL0_DACPD_MASK 0x1000000 +#define PLL_0_DACPD_SHIFT 24 +#define PLL_0_DACPD_MASK 0x1000000 + +#define PLL0_DSMPD_SHIFT 25 +#define PLL0_DSMPD_MASK 0x2000000 +#define PLL0_FBDIV_SHIFT 0 +#define PLL0_FBDIV_MASK 0xFFF +#define PLL0_FRAC_SHIFT 0 +#define PLL0_FRAC_MASK 0xFFFFFF +#define PLL0_POSTDIV1_SHIFT 28 +#define PLL0_POSTDIV1_MASK 0x30000000 +#define PLL0_PREDIV_SHIFT 0 +#define PLL0_PREDIV_MASK 0x3F + +#define PLL1_DACPD_SHIFT 15 +#define PLL1_DACPD_MASK 0x8000 +#define PLL1_DSMPD_SHIFT 16 +#define PLL1_DSMPD_MASK 0x10000 +#define PLL1_FBDIV_SHIFT 17 +#define PLL1_FBDIV_MASK 0x1FFE0000 +#define PLL1_FRAC_SHIFT 0 +#define PLL1_FRAC_MASK 0xFFFFFF +#define PLL1_POSTDIV1_SHIFT 28 +#define PLL1_POSTDIV1_MASK 0x30000000 +#define PLL1_PREDIV_SHIFT 0 +#define PLL1_PREDIV_MASK 0x3F + +#define PLL2_DACPD_SHIFT 15 +#define PLL2_DACPD_MASK 0x8000 +#define PLL2_DSMPD_SHIFT 16 +#define PLL2_DSMPD_MASK 0x10000 +#define PLL2_FBDIV_SHIFT 17 +#define PLL2_FBDIV_MASK 0x1FFE0000 +#define PLL2_FRAC_SHIFT 0 +#define PLL2_FRAC_MASK 0xFFFFFF +#define PLL2_POSTDIV1_SHIFT 28 +#define PLL2_POSTDIV1_MASK 0x30000000 +#define PLL2_PREDIV_SHIFT 0 +#define PLL2_PREDIV_MASK 0x3F + +#define FRAC_PATR_SIZE 1000 + +struct jh7110_pll_syscon_value { + uint64_t freq; + uint32_t prediv; + uint32_t fbdiv; + uint32_t postdiv1; + uint32_t dacpd; + uint32_t dsmpd; + uint32_t frac; +}; + +enum starfive_pll0_freq_value { + PLL0_FREQ_375_VALUE = 375000000, + PLL0_FREQ_500_VALUE = 500000000, + PLL0_FREQ_625_VALUE = 625000000, + PLL0_FREQ_750_VALUE = 750000000, + PLL0_FREQ_875_VALUE = 875000000, + PLL0_FREQ_1000_VALUE = 1000000000, + PLL0_FREQ_1250_VALUE = 1250000000, + PLL0_FREQ_1375_VALUE = 1375000000, + PLL0_FREQ_1500_VALUE = 1500000000 +}; + +enum starfive_pll0_freq { + PLL0_FREQ_375 = 0, + PLL0_FREQ_500, + PLL0_FREQ_625, + PLL0_FREQ_750, + PLL0_FREQ_875, + PLL0_FREQ_1000, + PLL0_FREQ_1250, + PLL0_FREQ_1375, + PLL0_FREQ_1500, + PLL0_FREQ_MAX = PLL0_FREQ_1500 +}; + +enum starfive_pll1_freq_value { + PLL1_FREQ_1066_VALUE = 1066000000, +}; + +enum starfive_pll1_freq { + PLL1_FREQ_1066 = 0, +}; + +enum starfive_pll2_freq_value { + PLL2_FREQ_1188_VALUE = 1188000000, + PLL2_FREQ_12288_VALUE = 1228800000, +}; + +enum starfive_pll2_freq { + PLL2_FREQ_1188 = 0, + PLL2_FREQ_12288, +}; + +static const struct jh7110_pll_syscon_value + jh7110_pll0_syscon_freq[] = { + [PLL0_FREQ_375] = { + .freq = PLL0_FREQ_375_VALUE, + .prediv = 8, + .fbdiv = 125, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_500] = { + .freq = PLL0_FREQ_500_VALUE, + .prediv = 6, + .fbdiv = 125, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_625] = { + .freq = PLL0_FREQ_625_VALUE, + .prediv = 24, + .fbdiv = 625, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_750] = { + .freq = PLL0_FREQ_750_VALUE, + .prediv = 4, + .fbdiv = 125, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_875] = { + .freq = PLL0_FREQ_875_VALUE, + .prediv = 24, + .fbdiv = 875, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_1000] = { + .freq = PLL0_FREQ_1000_VALUE, + .prediv = 3, + .fbdiv = 125, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_1250] = { + .freq = PLL0_FREQ_1250_VALUE, + .prediv = 12, + .fbdiv = 625, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_1375] = { + .freq = PLL0_FREQ_1375_VALUE, + .prediv = 24, + .fbdiv = 1375, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL0_FREQ_1500] = { + .freq = PLL0_FREQ_1500_VALUE, + .prediv = 2, + .fbdiv = 125, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, +}; + +static const struct jh7110_pll_syscon_value + jh7110_pll1_syscon_freq[] = { + [PLL1_FREQ_1066] = { + .freq = PLL1_FREQ_1066_VALUE, + .prediv = 12, + .fbdiv = 533, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, +}; + +static const struct jh7110_pll_syscon_value + jh7110_pll2_syscon_freq[] = { + [PLL2_FREQ_1188] = { + .freq = PLL2_FREQ_1188_VALUE, + .prediv = 2, + .fbdiv = 99, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, + [PLL2_FREQ_12288] = { + .freq = PLL2_FREQ_12288_VALUE, + .prediv = 5, + .fbdiv = 256, + .postdiv1 = 1, + .dacpd = 1, + .dsmpd = 1, + }, +}; diff --git a/sys/dev/clk/starfive/jh7110_clk_sys.c b/sys/dev/clk/starfive/jh7110_clk_sys.c new file mode 100644 index 000000000000..e7b8aa87c48e --- /dev/null +++ b/sys/dev/clk/starfive/jh7110_clk_sys.c @@ -0,0 +1,261 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2016 Michal Meloun + * Copyright (c) 2020 Oskar Holmlund + * Copyright (c) 2022 Mitchell Horne + * Copyright (c) 2024 Jari Sihvola + */ + +/* Clocks for JH7110 SYS group. PLL driver must be attached before this. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "clkdev_if.h" +#include "hwreset_if.h" + +static struct ofw_compat_data compat_data[] = { + { "starfive,jh7110-syscrg", 1 }, + { NULL, 0 } +}; + +static struct resource_spec res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + RESOURCE_SPEC_END +}; + +/* parents for non-pll SYS clocks */ +static const char *cpu_root_p[] = { "osc", "pll0_out" }; +static const char *cpu_core_p[] = { "cpu_root" }; +static const char *cpu_bus_p[] = { "cpu_core" }; +static const char *perh_root_p[] = { "pll0_out", "pll2_out" }; +static const char *bus_root_p[] = { "osc", "pll2_out" }; + +static const char *apb_bus_p[] = { "stg_axiahb" }; +static const char *apb0_p[] = { "apb_bus" }; +static const char *u0_sys_iomux_apb_p[] = { "apb_bus" }; +static const char *stg_axiahb_p[] = { "axi_cfg0" }; +static const char *ahb0_p[] = { "stg_axiahb" }; +static const char *axi_cfg0_p[] = { "bus_root" }; + +static const char *u0_dw_uart_clk_apb_p[] = { "apb0" }; +static const char *u0_dw_uart_clk_core_p[] = { "osc" }; +static const char *u0_dw_sdio_clk_ahb_p[] = { "ahb0" }; +static const char *u0_dw_sdio_clk_sdcard_p[] = { "axi_cfg0" }; +static const char *u1_dw_uart_clk_apb_p[] = { "apb0" }; +static const char *u1_dw_uart_clk_core_p[] = { "osc" }; +static const char *u1_dw_sdio_clk_ahb_p[] = { "ahb0" }; +static const char *u1_dw_sdio_clk_sdcard_p[] = { "axi_cfg0" }; +static const char *u2_dw_uart_clk_apb_p[] = { "apb0" }; +static const char *u2_dw_uart_clk_core_p[] = { "osc" }; +static const char *u3_dw_uart_clk_apb_p[] = { "apb0" }; +static const char *u3_dw_uart_clk_core_p[] = { "perh_root" }; + +static const char *gmac_src_p[] = { "pll0_out" }; +static const char *gmac_phy_p[] = { "gmac_src" }; +static const char *gmac0_gtxclk_p[] = { "pll0_out" }; +static const char *gmac0_ptp_p[] = { "gmac_src" }; +static const char *gmac0_gtxc_p[] = { "gmac0_gtxclk" }; +static const char *gmac1_gtxclk_p[] = { "pll0_out" }; +static const char *gmac1_gtxc_p[] = { "gmac1_gtxclk" }; +static const char *gmac1_rmii_rtx_p[] = { "gmac1_rmii_refin" }; +static const char *gmac1_axi_p[] = { "stg_axiahb" }; +static const char *gmac1_ahb_p[] = { "ahb0" }; +static const char *gmac1_ptp_p[] = { "gmac_src" }; +static const char *gmac1_tx_inv_p[] = { "gmac1_tx" }; +static const char *gmac1_tx_p[] = { "gmac1_gtxclk", "gmac1_rmii_rtx" }; +static const char *gmac1_rx_p[] = { "gmac1_rgmii_rxin", "gmac1_rmii_rtx" }; +static const char *gmac1_rx_inv_p[] = { "gmac1_rx" }; + +/* non-pll SYS clocks */ +static const struct jh7110_clk_def sys_clks[] = { + JH7110_MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", cpu_root_p), + JH7110_DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", cpu_core_p, 7), + JH7110_DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", cpu_bus_p, 2), + JH7110_GATEDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", perh_root_p, 2), + JH7110_MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", bus_root_p), + + JH7110_GATE(JH7110_SYSCLK_APB0, "apb0", apb0_p), + JH7110_GATE(JH7110_SYSCLK_IOMUX_APB, "u0_sys_iomux_apb", + u0_sys_iomux_apb_p), + JH7110_GATE(JH7110_SYSCLK_UART0_APB, "u0_dw_uart_clk_apb", + u0_dw_uart_clk_apb_p), + JH7110_GATE(JH7110_SYSCLK_UART0_CORE, "u0_dw_uart_clk_core", + u0_dw_uart_clk_core_p), + JH7110_GATE(JH7110_SYSCLK_UART1_APB, "u1_dw_uart_clk_apb", + u1_dw_uart_clk_apb_p), + JH7110_GATE(JH7110_SYSCLK_UART1_CORE, "u1_dw_uart_clk_core", + u1_dw_uart_clk_core_p), + JH7110_GATE(JH7110_SYSCLK_UART2_APB, "u2_dw_uart_clk_apb", + u2_dw_uart_clk_apb_p), + JH7110_GATE(JH7110_SYSCLK_UART2_CORE, "u2_dw_uart_clk_core", + u2_dw_uart_clk_core_p), + JH7110_GATE(JH7110_SYSCLK_UART3_APB, "u3_dw_uart_clk_apb", + u3_dw_uart_clk_apb_p), + JH7110_GATE(JH7110_SYSCLK_UART3_CORE, "u3_dw_uart_clk_core", + u3_dw_uart_clk_core_p), + + JH7110_DIV(JH7110_SYSCLK_AXI_CFG0, "axi_cfg0", axi_cfg0_p, 3), + JH7110_DIV(JH7110_SYSCLK_STG_AXIAHB, "stg_axiahb", stg_axiahb_p, 2), + JH7110_GATE(JH7110_SYSCLK_AHB0, "ahb0", ahb0_p), + JH7110_DIV(JH7110_SYSCLK_APB_BUS, "apb_bus", apb_bus_p, 8), + + JH7110_GATE(JH7110_SYSCLK_SDIO0_AHB, "u0_dw_sdio_clk_ahb", + u0_dw_sdio_clk_ahb_p), + JH7110_GATE(JH7110_SYSCLK_SDIO1_AHB, "u1_dw_sdio_clk_ahb", + u1_dw_sdio_clk_ahb_p), + JH7110_GATEDIV(JH7110_SYSCLK_SDIO0_SDCARD, "u0_dw_sdio_clk_sdcard", + u0_dw_sdio_clk_sdcard_p, 15), + JH7110_GATEDIV(JH7110_SYSCLK_SDIO1_SDCARD, "u1_dw_sdio_clk_sdcard", + u1_dw_sdio_clk_sdcard_p, 15), + + JH7110_DIV(JH7110_SYSCLK_GMAC_SRC, "gmac_src", gmac_src_p, 7), + JH7110_GATEDIV(JH7110_SYSCLK_GMAC0_GTXCLK, "gmac0_gtxclk", + gmac0_gtxclk_p, 15), + JH7110_GATEDIV(JH7110_SYSCLK_GMAC0_PTP, "gmac0_ptp", gmac0_ptp_p, 31), + JH7110_GATEDIV(JH7110_SYSCLK_GMAC_PHY, "gmac_phy", gmac_phy_p, 31), + JH7110_GATE(JH7110_SYSCLK_GMAC0_GTXC, "gmac0_gtxc", gmac0_gtxc_p), + + JH7110_MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", gmac1_rx_p), + JH7110_INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", gmac1_rx_inv_p), + JH7110_GATE(JH7110_SYSCLK_GMAC1_AHB, "gmac1_ahb", gmac1_ahb_p), + JH7110_DIV(JH7110_SYSCLK_GMAC1_GTXCLK, "gmac1_gtxclk", + gmac1_gtxclk_p, 15), + JH7110_GATEMUX(JH7110_SYSCLK_GMAC1_TX, "gmac1_tx", gmac1_tx_p), + JH7110_INV(JH7110_SYSCLK_GMAC1_TX_INV, "gmac1_tx_inv", gmac1_tx_inv_p), + JH7110_GATEDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", gmac1_ptp_p, 31), + JH7110_GATE(JH7110_SYSCLK_GMAC1_AXI, "gmac1_axi", gmac1_axi_p), + JH7110_GATE(JH7110_SYSCLK_GMAC1_GTXC, "gmac1_gtxc", gmac1_gtxc_p), + JH7110_DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", + gmac1_rmii_rtx_p, 30), +}; + +static int +jh7110_clk_sys_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 SYS clock generator"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jh7110_clk_sys_attach(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + int i, error; + + sc = device_get_softc(dev); + + sc->reset_status_offset = SYSCRG_RESET_STATUS; + sc->reset_selector_offset = SYSCRG_RESET_SELECTOR; + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Allocate memory groups */ + error = bus_alloc_resources(dev, res_spec, &sc->mem_res); + if (error != 0) { + device_printf(dev, "Couldn't allocate resources, error %d\n", + error); + return (ENXIO); + } + + /* Create clock domain */ + sc->clkdom = clkdom_create(dev); + if (sc->clkdom == NULL) { + device_printf(dev, "Couldn't create clkdom\n"); + return (ENXIO); + } + + /* Register clocks */ + for (i = 0; i < nitems(sys_clks); i++) { + error = jh7110_clk_register(sc->clkdom, &sys_clks[i]); + if (error != 0) { + device_printf(dev, "Couldn't register clock %s: %d\n", + sys_clks[i].clkdef.name, error); + return (ENXIO); + } + } + + if (clkdom_finit(sc->clkdom) != 0) + panic("Cannot finalize clkdom initialization\n"); + + if (bootverbose) + clkdom_dump(sc->clkdom); + + hwreset_register_ofw_provider(dev); + + return (0); +} + +static int +jh7110_clk_sys_detach(device_t dev) +{ + /* Detach not supported */ + return (EBUSY); +} + +static void +jh7110_clk_sys_device_lock(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +static void +jh7110_clk_sys_device_unlock(device_t dev) +{ + struct jh7110_clkgen_softc *sc; + + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static device_method_t jh7110_clk_sys_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jh7110_clk_sys_probe), + DEVMETHOD(device_attach, jh7110_clk_sys_attach), + DEVMETHOD(device_detach, jh7110_clk_sys_detach), + + /* clkdev interface */ + DEVMETHOD(clkdev_device_lock, jh7110_clk_sys_device_lock), + DEVMETHOD(clkdev_device_unlock, jh7110_clk_sys_device_unlock), + + /* Reset interface */ + DEVMETHOD(hwreset_assert, jh7110_reset_assert), + DEVMETHOD(hwreset_is_asserted, jh7110_reset_is_asserted), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(jh7110_clk_sys, jh7110_clk_sys_driver, jh7110_clk_sys_methods, + sizeof(struct jh7110_clkgen_softc)); +EARLY_DRIVER_MODULE(jh7110_clk_sys, simplebus, jh7110_clk_sys_driver, 0, 0, + BUS_PASS_BUS + BUS_PASS_ORDER_LATE); +MODULE_VERSION(jh7110_clk_sys, 1); diff --git a/sys/riscv/starfive/files.starfive b/sys/riscv/starfive/files.starfive index 556c4618ad18..d867dee1099b 100644 --- a/sys/riscv/starfive/files.starfive +++ b/sys/riscv/starfive/files.starfive @@ -1,3 +1,7 @@ +dev/clk/starfive/jh7110_clk.c standard +dev/clk/starfive/jh7110_clk_aon.c standard +dev/clk/starfive/jh7110_clk_pll.c standard +dev/clk/starfive/jh7110_clk_sys.c standard dev/mmc/host/dwmmc_starfive.c optional dwmmc_starfive fdt riscv/starfive/starfive_syscon.c standard