Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152773360
D43037.id135253.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
46 KB
Referenced Files
None
Subscribers
None
D43037.id135253.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,94 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2023 Jari Sihvola <jsihv@gmx.com>
+ *
+ * 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 ``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 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 <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,371 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org>
+ * Copyright (c) 2022 Mitchell Horne <mhorne@FreeBSD.org>
+ * Copyright (c) 2023 Jari Sihvola <jsihv@gmx.com>
+ *
+ * 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 ``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 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/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_SELECTOR0 0x2f8
+#define SYSCRG_RESET_SELECTOR1 0x2fc
+#define SYSCRG_RESET_SELECTOR2 0x300
+#define SYSCRG_RESET_SELECTOR3 0x304
+#define SYSCRG_RESET_STATUS0 0x308
+#define SYSCRG_RESET_STATUS1 0x30c
+#define SYSCRG_RESET_STATUS2 0x310
+#define SYSCRG_RESET_STATUS3 0x314
+
+enum jh7110_reset_crg {
+ SYS0,
+ SYS1,
+ SYS2,
+ SYS3,
+ STG,
+ AON,
+};
+
+struct jh7110_clk_sc {
+ uint32_t offset;
+ uint32_t flags;
+ uint64_t d_max;
+ int id;
+};
+
+struct jh7110_rstdata {
+ int crg;
+ uint64_t status_offset;
+ uint64_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;
+ uint32_t crg;
+
+ sc = device_get_softc(dev);
+
+ if (sc->dev_flag == JH7110_CLK_AON) {
+ iodata->crg = AON;
+ iodata->status_offset = AONCRG_RESET_STATUS;
+ iodata->selector_offset = AONCRG_RESET_SELECTOR;
+
+ return;
+ }
+
+ crg = id / 32;
+
+ if (crg == SYS0) {
+ iodata->crg = SYS0;
+ iodata->status_offset = SYSCRG_RESET_STATUS0;
+ iodata->selector_offset = SYSCRG_RESET_SELECTOR0;
+ } else if (crg == SYS1) {
+ iodata->crg = SYS1;
+ iodata->status_offset = SYSCRG_RESET_STATUS1;
+ iodata->selector_offset = SYSCRG_RESET_SELECTOR1;
+ } else if (crg == SYS2) {
+ iodata->crg = SYS2;
+ iodata->status_offset = SYSCRG_RESET_STATUS2;
+ iodata->selector_offset = SYSCRG_RESET_SELECTOR2;
+ } else if (crg == SYS3) {
+ iodata->crg = SYS3;
+ iodata->status_offset = SYSCRG_RESET_STATUS3;
+ iodata->selector_offset = SYSCRG_RESET_SELECTOR3;
+ } else
+ panic("Reset with id %lu, crg %d has no group\n", id, crg);
+
+ 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,198 @@
+/*-
+ * 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>
+ *
+ * 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 ``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 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.
+ */
+
+/* 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/fbio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/clk/clk.h>
+#include <dev/clk/clk_div.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/clk/clk_link.h>
+#include <dev/clk/clk_mux.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 <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include <dev/clk/starfive/jh7110_clk.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 (EACCES);
+}
+
+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,208 @@
+/* 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 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,459 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
+ *
+ * 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 ``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 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/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.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/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.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"
+
+#define PLL_OFFSET_0_ 0x18
+#define PLL_OFFSET_1_ 0x1c
+#define PLL_OFFSET_2_ 0x20
+#define PLL_OFFSET_3_ 0x24
+#define PLL_OFFSET_4_ 0x28
+#define PLL_OFFSET_5_ 0x2c
+#define PLL_OFFSET_6_ 0x30
+#define PLL_OFFSET_7_ 0x34
+
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+#define SYSCON_READ_4(reg) \
+ bus_read_4(sc->syscon_mem_res, (reg))
+#define SYSCON_MODIFY_4(reg, cbits, sbits) \
+ jh7110_syscon_modify_4(sc->syscon_mem_res, (reg), (cbits), (sbits))
+
+#define PLL_MASK_FILL(id) do { \
+ sc->pll_data[id].dacpd_mask = PLL## id ##_DACPD_MASK; \
+ sc->pll_data[id].dsmpd_mask = PLL## id ##_DSMPD_MASK; \
+ sc->pll_data[id].fbdiv_mask = PLL## id ##_FBDIV_MASK; \
+ sc->pll_data[id].frac_mask = PLL## id ##_FRAC_MASK; \
+ sc->pll_data[id].prediv_mask = PLL## id ##_PREDIV_MASK; \
+ sc->pll_data[id].postdiv1_mask = PLL## id ##_POSTDIV1_MASK; \
+} while (0)
+
+#define PLL_SHIFT_FILL(id) do { \
+ sc->pll_data[id].dacpd_shift = PLL## id ##_DACPD_SHIFT; \
+ sc->pll_data[id].dsmpd_shift = PLL## id ##_DSMPD_SHIFT; \
+ sc->pll_data[id].fbdiv_shift = PLL## id ##_FBDIV_SHIFT; \
+ sc->pll_data[id].frac_shift = PLL## id ##_FRAC_SHIFT; \
+ sc->pll_data[id].prediv_shift = PLL## id ##_PREDIV_SHIFT; \
+ sc->pll_data[id].postdiv1_shift = PLL## id ##_POSTDIV1_SHIFT; \
+} while (0)
+
+#define PLL_OFFSET_FILL(id, val1, val2, val3, val4, val5, val6) do { \
+ sc->pll_data[id].dacpd_offset = PLL_OFFSET_## val1 ##_ ; \
+ sc->pll_data[id].dsmpd_offset = PLL_OFFSET_## val2 ##_ ; \
+ sc->pll_data[id].fbdiv_offset = PLL_OFFSET_## val3 ##_ ; \
+ sc->pll_data[id].frac_offset = PLL_OFFSET_## val4 ##_ ; \
+ sc->pll_data[id].prediv_offset = PLL_OFFSET_## val5 ##_ ; \
+ sc->pll_data[id].postdiv1_offset = PLL_OFFSET_## val6 ##_ ; \
+} while (0)
+
+static struct ofw_compat_data compat_data[] = {
+ { "starfive,jh7110-sys-syscon", 1 },
+ { NULL, 0 }
+};
+
+static struct resource_spec res_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE },
+ RESOURCE_SPEC_END
+};
+
+struct pll_clk_data {
+ 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;
+};
+
+struct jh7110_clk_pll_softc {
+ struct mtx mtx;
+ struct clkdom *clkdom;
+ struct resource *syscon_mem_res;
+};
+
+struct jh7110_clk_pll_sc {
+ int id;
+ struct pll_clk_data pll_data[JH7110_PLLCLK_END];
+};
+
+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_syscon_modify_4(struct resource *res, bus_size_t offset,
+ uint32_t clear_bits, uint32_t set_bits)
+{
+ uint32_t val;
+ uint32_t new_val;
+
+ val = bus_read_4(res, offset);
+
+ new_val = (val & ~clear_bits) | set_bits;
+
+ if (new_val != val)
+ bus_write_4(res, offset, new_val);
+
+ return (0);
+}
+
+static int
+jh7110_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq)
+{
+ struct jh7110_clk_pll_softc *sc;
+ struct jh7110_clk_pll_sc *clk_sc;
+ struct pll_clk_data *data;
+ 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);
+
+ if (clk_sc->id == JH7110_PLLCLK_PLL0_OUT)
+ data = &clk_sc->pll_data[0];
+ else if (clk_sc->id == JH7110_PLLCLK_PLL1_OUT)
+ data = &clk_sc->pll_data[1];
+ else
+ data = &clk_sc->pll_data[2];
+
+ DEVICE_LOCK(clk);
+
+ dacpd = (SYSCON_READ_4(data->dacpd_offset) & data->dacpd_mask) >>
+ data->dacpd_shift;
+ dsmpd = (SYSCON_READ_4(data->dsmpd_offset) & data->dsmpd_mask) >>
+ data->dsmpd_shift;
+ fbdiv = (SYSCON_READ_4(data->fbdiv_offset) & data->fbdiv_mask) >>
+ data->fbdiv_shift;
+ prediv = (SYSCON_READ_4(data->prediv_offset) & data->prediv_mask) >>
+ data->prediv_shift;
+ postdiv1 = (SYSCON_READ_4(data->postdiv1_offset) &
+ data->postdiv1_mask) >> data->postdiv1_shift;
+ frac = (SYSCON_READ_4(data->frac_offset) & data->frac_mask) >>
+ data->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_clk_pll_sc *clk_sc;
+ struct pll_clk_data *data;
+ const struct jh7110_pll_syscon_value *syscon_val = NULL;
+
+ sc = device_get_softc(clknode_get_device(clk));
+ clk_sc = clknode_get_softc(clk);
+
+ if (clk_sc->id == JH7110_PLLCLK_PLL0_OUT)
+ data = &clk_sc->pll_data[0];
+ else if (clk_sc->id == JH7110_PLLCLK_PLL1_OUT)
+ data = &clk_sc->pll_data[1];
+ else
+ data = &clk_sc->pll_data[2];
+
+ for (int i = 0; i != data->syscon_nitems; i++) {
+ if (*fout == data->syscon_arr[i].freq) {
+ syscon_val = &data->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) {
+ *done = 1;
+ return (0);
+ }
+
+ DEVICE_LOCK(clk);
+
+ SYSCON_MODIFY_4(data->dacpd_offset, data->dacpd_mask,
+ syscon_val->dacpd << data->dacpd_shift & data->dacpd_mask);
+ SYSCON_MODIFY_4(data->dsmpd_offset, data->dsmpd_mask,
+ syscon_val->dsmpd << data->dsmpd_shift & data->dsmpd_mask);
+ SYSCON_MODIFY_4(data->prediv_offset, data->prediv_mask,
+ syscon_val->prediv << data->prediv_shift & data->prediv_mask);
+ SYSCON_MODIFY_4(data->fbdiv_offset, data->fbdiv_mask,
+ syscon_val->fbdiv << data->fbdiv_shift & data->fbdiv_mask);
+ SYSCON_MODIFY_4(data->postdiv1_offset,
+ data->postdiv1_mask, (syscon_val->postdiv1 >> 1)
+ << data->postdiv1_shift & data->postdiv1_mask);
+
+ if (!syscon_val->dacpd && !syscon_val->dsmpd) {
+ SYSCON_MODIFY_4(data->frac_offset, data->frac_mask,
+ syscon_val->frac << data->frac_shift & data->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_search_compatible(dev, compat_data)->ocd_data == 0)
+ 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 i, error;
+
+ sc = device_get_softc(dev);
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ error = bus_alloc_resources(dev, res_spec, &sc->syscon_mem_res);
+ if (error) {
+ device_printf(dev, "Couldn't allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL) {
+ device_printf(dev, "Couldn't create clkdom\n");
+ return (ENXIO);
+ }
+
+ for (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) {
+ device_printf(dev, "Clkdom_finit() returns error %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_clk_pll_sc), 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_clk_pll_sc *sc;
+
+ clk = clknode_create(clkdom, &jh7110_pllnode_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->id = clkdef->clkdef.id;
+
+ switch (sc->id) {
+ case JH7110_PLLCLK_PLL0_OUT:
+ sc->pll_data[sc->id].syscon_arr =
+ jh7110_pll0_syscon_freq;
+ sc->pll_data[sc->id].syscon_nitems =
+ nitems(jh7110_pll0_syscon_freq);
+ PLL_MASK_FILL(0);
+ PLL_SHIFT_FILL(0);
+ PLL_OFFSET_FILL(sc->id, 0, 0, 1, 2, 3, 2);
+ break;
+ case JH7110_PLLCLK_PLL1_OUT:
+ sc->pll_data[sc->id].syscon_arr =
+ jh7110_pll1_syscon_freq;
+ sc->pll_data[sc->id].syscon_nitems =
+ nitems(jh7110_pll1_syscon_freq);
+ PLL_MASK_FILL(1);
+ PLL_SHIFT_FILL(1);
+ PLL_OFFSET_FILL(sc->id, 3, 3, 3, 4, 5, 4);
+ break;
+ case JH7110_PLLCLK_PLL2_OUT:
+ sc->pll_data[sc->id].syscon_arr =
+ jh7110_pll2_syscon_freq;
+ sc->pll_data[sc->id].syscon_nitems =
+ nitems(jh7110_pll2_syscon_freq);
+ PLL_MASK_FILL(2);
+ PLL_SHIFT_FILL(2);
+ PLL_OFFSET_FILL(sc->id, 5, 5, 5, 6, 7, 6);
+ 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,293 @@
+/*-
+ * 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>
+ *
+ * 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 ``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 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.
+ */
+
+/* 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/fbio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/clk/clk.h>
+#include <dev/clk/clk_div.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/clk/clk_link.h>
+#include <dev/clk/clk_mux.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 <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include <dev/clk/starfive/jh7110_clk.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 (EACCES);
+}
+
+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
Sat, Apr 18, 12:44 AM (17 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31688443
Default Alt Text
D43037.id135253.diff (46 KB)
Attached To
Mode
D43037: jh7110_clkgen: Add StarFive JH7110 clock generator driver
Attached
Detach File
Event Timeline
Log In to Comment