Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142359006
D43037.id137656.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
38 KB
Referenced Files
None
Subscribers
None
D43037.id137656.diff
View Options
diff --git a/sys/dev/clk/starfive/jh7110_clk.h b/sys/dev/clk/starfive/jh7110_clk.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/clk/starfive/jh7110_clk.h
@@ -0,0 +1,73 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ */
+
+#include <dev/clk/clk.h>
+
+#ifndef _CLK_JH7110_CLK_H_
+#define _CLK_JH7110_CLK_H_
+
+#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 JH7110_CLK_AON 0x10
+#define JH7110_CLK_ISP 0x20
+#define JH7110_CLK_STG 0x40
+#define JH7110_CLK_SYS 0x80
+#define JH7110_CLK_VOUT 0x100
+
+struct jh7110_clkgen_softc {
+ struct mtx mtx;
+ struct clkdom *clkdom;
+ struct resource *mem_res;
+ int dev_flag;
+};
+
+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 /* _CLK_JH7110_CLK_H_ */
diff --git a/sys/dev/clk/starfive/jh7110_clk.c b/sys/dev/clk/starfive/jh7110_clk.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/clk/starfive/jh7110_clk.c
@@ -0,0 +1,317 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org>
+ * Copyright (c) 2022 Mitchell Horne <mhorne@FreeBSD.org>
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/resource.h>
+
+#include <dev/clk/clk.h>
+#include <dev/hwreset/hwreset.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include <dev/clk/starfive/jh7110_clk.h>
+
+#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
+
+/* offsets for reset registers */
+#define AONCRG_RESET_SELECTOR 0x38
+#define STGCRG_RESET_SELECTOR 0x74
+#define AONCRG_RESET_STATUS 0x3c
+#define STGCRG_RESET_STATUS 0x78
+#define SYSCRG_RESET_SELECTOR_OFFSET 0x2f8
+#define SYSCRG_RESET_STATUS_OFFSET 0x308
+
+struct jh7110_clk_sc {
+ uint32_t offset;
+ uint32_t flags;
+ uint64_t d_max;
+ int id;
+};
+
+struct jh7110_rstdata {
+ uint32_t status_offset;
+ uint32_t selector_offset;
+};
+
+#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 */
+
+static void
+jh7110_reset_io_assign(device_t dev, intptr_t id, struct jh7110_rstdata *iodata)
+{
+ struct jh7110_clkgen_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->dev_flag == JH7110_CLK_AON) {
+ iodata->status_offset = AONCRG_RESET_STATUS;
+ iodata->selector_offset = AONCRG_RESET_SELECTOR;
+
+ return;
+ }
+
+ if (sc->dev_flag != JH7110_CLK_SYS)
+ panic("Reset fails, id %lu, dev_flag 0x%x\n", id, sc->dev_flag);
+
+ iodata->status_offset = SYSCRG_RESET_STATUS_OFFSET + id / 32 * 4;
+ iodata->selector_offset = SYSCRG_RESET_SELECTOR_OFFSET + id / 32 * 4;
+
+ return;
+}
+
+int
+jh7110_reset_assert(device_t dev, intptr_t id, bool assert)
+{
+ struct jh7110_clkgen_softc *sc;
+ struct jh7110_rstdata iodata;
+ uint32_t regvalue, bitmask = 1UL << id % 32;
+
+ sc = device_get_softc(dev);
+
+ jh7110_reset_io_assign(dev, id, &iodata);
+
+ mtx_lock(&sc->mtx);
+
+ regvalue = READ4(sc, iodata.selector_offset);
+
+ if (assert)
+ regvalue |= bitmask;
+ else
+ regvalue &= ~bitmask;
+ WRITE4(sc, iodata.selector_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;
+ struct jh7110_rstdata iodata;
+ uint32_t regvalue;
+ uint32_t bitmask;
+
+ sc = device_get_softc(dev);
+
+ jh7110_reset_io_assign(dev, id, &iodata);
+
+ mtx_lock(&sc->mtx);
+
+ regvalue = READ4(sc, iodata.status_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_aon.c b/sys/dev/clk/starfive/jh7110_clk_aon.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/clk/starfive/jh7110_clk_aon.c
@@ -0,0 +1,166 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ */
+
+/* Clocks for JH7110 AON group. PLL driver must be attached before this. */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/hwreset/hwreset.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/clk/clk.h>
+#include <dev/clk/starfive/jh7110_clk.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#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->dev_flag = JH7110_CLK_AON;
+
+ 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.h b/sys/dev/clk/starfive/jh7110_clk_pll.h
new file mode 100644
--- /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 <xingyu.wu@starfivetech.com>
+ */
+
+#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_pll.c b/sys/dev/clk/starfive/jh7110_clk_pll.c
new file mode 100644
--- /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 <jsihv@gmx.com>
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Mitchell Horne
+ * <mhorne@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include <dev/clk/starfive/jh7110_clk_pll.h>
+#include <dev/clk/starfive/jh7110_clk.h>
+#include <dev/clk/clk.h>
+
+#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_sys.c b/sys/dev/clk/starfive/jh7110_clk_sys.c
new file mode 100644
--- /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 <mmel@FreeBSD.org>
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ * Copyright (c) 2022 Mitchell Horne <mhorne@FreeBSD.org>
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ */
+
+/* Clocks for JH7110 SYS group. PLL driver must be attached before this. */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+#include <dev/hwreset/hwreset.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/clk/clk.h>
+#include <dev/clk/starfive/jh7110_clk.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#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->dev_flag = JH7110_CLK_SYS;
+
+ 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) {
+ 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);
+ }
+
+ /* Registering 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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jan 20, 1:08 AM (3 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27757253
Default Alt Text
D43037.id137656.diff (38 KB)
Attached To
Mode
D43037: jh7110_clkgen: Add StarFive JH7110 clock generator driver
Attached
Detach File
Event Timeline
Log In to Comment