Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153997085
D32294.id100910.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
56 KB
Referenced Files
None
Subscribers
None
D32294.id100910.diff
View Options
diff --git a/sys/arm/mv/clk/a37x0_nb_periph_clk_driver.c b/sys/arm/mv/clk/a37x0_nb_periph_clk_driver.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/a37x0_nb_periph_clk_driver.c
@@ -0,0 +1,166 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_fixed.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define NB_DEV_COUNT 17
+
+static struct clk_div_table a37x0_periph_clk_table_6 [] = {
+ { .value = 1, .divider = 1 },
+ { .value = 2, .divider = 2 },
+ { .value = 3, .divider = 3 },
+ { .value = 4, .divider = 4 },
+ { .value = 5, .divider = 5 },
+ { .value = 6, .divider = 6 },
+ { .value = 0, .divider = 0 }
+};
+
+static struct clk_div_table a37x0_periph_clk_table_2 [] = {
+ { .value = 0, .divider = 1 },
+ { .value = 1, .divider = 2 },
+ { .value = 2, .divider = 4 },
+ { .value = 3, .divider = 1 }
+};
+
+static struct a37x0_periph_clknode_def a37x0_nb_devices [] = {
+ CLK_FULL_DD("mmc", 0, 2, 0, 0, DIV_SEL2, DIV_SEL2, 16, 13,
+ "tbg_mux_mmc_50", "div1_mmc_51", "div2_mmc_52", "clk_mux_mmc_53"),
+ CLK_FULL_DD("sata_host", 1, 3, 2, 1, DIV_SEL2, DIV_SEL2, 10, 7,
+ "tbg_sata_host_mmc_55", "div1_sata_host_56", "div2_sata_host_57",
+ "clk_sata_host_mmc_58"),
+ CLK_FULL_DD("sec_at", 2, 6, 4, 2, DIV_SEL1, DIV_SEL1, 3, 0,
+ "tbg_mux_sec_at_60", "div1_sec_at_61", "div2_sec_at_62",
+ "clk_mux_sec_at_63"),
+ CLK_FULL_DD("sec_dap", 3, 7, 6, 3, DIV_SEL1, DIV_SEL1, 9, 6,
+ "tbg_mux_sec_dap_65", "div1_sec_dap_67", "div2_sec_dap_68",
+ "clk_mux_sec_dap_69"),
+ CLK_FULL_DD("tsecm", 4, 8, 8, 4, DIV_SEL1, DIV_SEL1, 15, 12,
+ "tbg_mux_tsecm_71", "div1_tsecm_72", "div2_tsecm_73",
+ "clk_mux_tsecm_74"),
+ CLK_FULL("setm_tmx", 5, 10, 10, 5, DIV_SEL1, 18,
+ a37x0_periph_clk_table_6, "tbg_mux_setm_tmx_76",
+ "div1_setm_tmx_77", "clk_mux_setm_tmx_78"),
+ CLK_FIXED("avs", 6, 11, 6, "mux_avs_80", "fixed1_avs_82"),
+ CLK_FULL_DD("pwm", 7, 13, 14, 8, DIV_SEL0, DIV_SEL0, 3, 0,
+ "tbg_mux_pwm_83", "div1_pwm_84", "div2_pwm_85", "clk_mux_pwm_86"),
+ CLK_FULL_DD("sqf", 8, 12, 12, 7, DIV_SEL1, DIV_SEL1, 27, 14,
+ "tbg_mux_sqf_88", "div1_sqf_89", "div2_sqf_90", "clk_mux_sqf_91"),
+ CLK_GATE("i2c_2", 9, 16, NULL),
+ CLK_GATE("i2c_1", 10, 17, NULL),
+ CLK_MUX_GATE_FIXED("ddr_phy", 11, 19, 10, "mux_ddr_phy_95",
+ "gate_ddr_phy_96", "fixed1_ddr_phy_97"),
+ CLK_FULL_DD("ddr_fclk", 12, 21, 16, 11, DIV_SEL0, DIV_SEL0, 15, 12,
+ "tbg_mux_ddr_fclk_99", "div1_ddr_fclk_100", "div2_ddr_fclk_101",
+ "clk_mux_ddr_fclk_102"),
+ CLK_FULL("trace", 13, 22, 18, 12, DIV_SEL0, 20,
+ a37x0_periph_clk_table_6, "tbg_mux_trace_104", "div1_trace_105",
+ "clk_mux_trace_106"),
+ CLK_FULL("counter", 14, 23, 20, 13, DIV_SEL0, 23,
+ a37x0_periph_clk_table_6, "tbg_mux_counter_108",
+ "div1_counter_109", "clk_mux_counter_110"),
+ CLK_FULL_DD("eip97", 15, 26, 24, 9, DIV_SEL2, DIV_SEL2, 22, 19,
+ "tbg_mux_eip97_112", "div1_eip97_113", "div2_eip97_114",
+ "clk_mux_eip97_115"),
+ CLK_CPU("cpu", 16, 22, 15, DIV_SEL0, 28, a37x0_periph_clk_table_2,
+ "tbg_mux_cpu_117", "div1_cpu_118"),
+};
+
+static struct ofw_compat_data a37x0_periph_compat_data [] = {
+ { "marvell,armada-3700-periph-clock-nb", 1 },
+ { NULL, 0 }
+};
+
+static int a37x0_nb_periph_clk_attach(device_t);
+static int a37x0_nb_periph_clk_probe(device_t);
+
+static device_method_t a37x0_nb_periph_clk_methods[] = {
+ DEVMETHOD(clkdev_device_unlock, a37x0_periph_clk_device_unlock),
+ DEVMETHOD(clkdev_device_lock, a37x0_periph_clk_device_lock),
+ DEVMETHOD(clkdev_read_4, a37x0_periph_clk_read_4),
+
+ DEVMETHOD(device_attach, a37x0_nb_periph_clk_attach),
+ DEVMETHOD(device_detach, a37x0_periph_clk_detach),
+ DEVMETHOD(device_probe, a37x0_nb_periph_clk_probe),
+
+ DEVMETHOD_END
+};
+
+static driver_t a37x0_nb_periph_driver = {
+ "a37x0_nb_periph_driver",
+ a37x0_nb_periph_clk_methods,
+ sizeof(struct a37x0_periph_clk_softc)
+};
+
+devclass_t a37x0_nb_periph_devclass;
+
+EARLY_DRIVER_MODULE(a37x0_nb_periph, simplebus, a37x0_nb_periph_driver,
+ a37x0_nb_periph_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_LATE);
+
+static int
+a37x0_nb_periph_clk_attach(device_t dev)
+{
+ struct a37x0_periph_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->devices = a37x0_nb_devices;
+ sc->device_count = NB_DEV_COUNT;
+
+ return (a37x0_periph_clk_attach(dev));
+}
+
+static int
+a37x0_nb_periph_clk_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev,
+ a37x0_periph_compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "marvell,armada-3700-nb-periph-clock");
+
+ return (BUS_PROBE_DEFAULT);
+}
diff --git a/sys/arm/mv/clk/a37x0_periph_clk_driver.c b/sys/arm/mv/clk/a37x0_periph_clk_driver.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/a37x0_periph_clk_driver.c
@@ -0,0 +1,216 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_fixed.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define TBG_COUNT 4
+#define XTAL_OFW_INDEX 4
+
+static struct resource_spec a37x0_periph_clk_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+int
+a37x0_periph_clk_attach(device_t dev)
+{
+ struct a37x0_periph_clknode_def *dev_defs;
+ struct a37x0_periph_clk_softc *sc;
+ const char *tbg_clocks[5];
+ const char *xtal_clock;
+ phandle_t node;
+ int error, i;
+ clk_t clock;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (bus_alloc_resources(dev, a37x0_periph_clk_spec, &sc->res) != 0) {
+ device_printf(dev, "Cannot allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL) {
+ device_printf(dev, "Cannot create clock domain\n");
+ return (ENXIO);
+ }
+
+ for (i = 0; i < TBG_COUNT; i++){
+ error = clk_get_by_ofw_index(dev, node, i, &clock);
+ if (error)
+ goto fail;
+ tbg_clocks[i] = clk_get_name(clock);
+ }
+
+ error = clk_get_by_ofw_index(dev, node, XTAL_OFW_INDEX, &clock);
+ if (error)
+ goto fail;
+ xtal_clock = clk_get_name(clock);
+
+ dev_defs = sc->devices;
+
+ for (i = 0; i< sc->device_count; i++) {
+ dev_defs[i].common_def.tbgs = tbg_clocks;
+ dev_defs[i].common_def.xtal = xtal_clock;
+ dev_defs[i].common_def.tbg_cnt = TBG_COUNT;
+ switch (dev_defs[i].type) {
+ case CLK_FULL_DD:
+ error = a37x0_periph_d_register_full_clk_dd(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_FULL:
+ error = a37x0_periph_d_register_full_clk(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_GATE:
+ error = a37x0_periph_gate_register_gate(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_MUX_GATE:
+ error = a37x0_periph_register_mux_gate(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_FIXED:
+ error = a37x0_periph_fixed_register_fixed(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_CPU:
+ error = a37x0_periph_d_register_periph_cpu(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_MDD:
+ error = a37x0_periph_d_register_mdd(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ case CLK_MUX_GATE_FIXED:
+ error = a37x0_periph_register_mux_gate_fixed(
+ sc->clkdom, &dev_defs[i]);
+ if (error)
+ goto fail;
+ break;
+
+ default:
+ return (ENXIO);
+ }
+ }
+
+ error = clkdom_finit(sc->clkdom);
+ if (error)
+ goto fail;
+
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+
+ return (0);
+
+fail:
+ bus_release_resources(dev, a37x0_periph_clk_spec, &sc->res);
+
+ return (error);
+
+}
+
+int
+a37x0_periph_clk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+{
+ struct a37x0_periph_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *val = bus_read_4(sc->res, addr);
+
+ return (0);
+}
+
+void
+a37x0_periph_clk_device_lock(device_t dev)
+{
+ struct a37x0_periph_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+void
+a37x0_periph_clk_device_unlock(device_t dev)
+{
+ struct a37x0_periph_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+int
+a37x0_periph_clk_detach(device_t dev)
+{
+
+ return (EBUSY);
+}
diff --git a/sys/arm/mv/clk/a37x0_sb_periph_clk_driver.c b/sys/arm/mv/clk/a37x0_sb_periph_clk_driver.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/a37x0_sb_periph_clk_driver.c
@@ -0,0 +1,135 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_fixed.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define SB_DEV_COUNT 14
+
+static struct a37x0_periph_clknode_def a37x0_sb_devices [] = {
+ CLK_MDD("gbe_50", 0, 6, 1, DIV_SEL2, DIV_SEL2, 6, 9,
+ "tbg_mux_gbe_50_120", "div1_gbe_50_121", "div2_gbe_50_122"),
+ CLK_MDD("gbe_core", 1, 8, 5, DIV_SEL1, DIV_SEL1, 18, 21,
+ "tbg_mux_gbe_core_124", "div1_gbe_core_125", "div2_gbe_core_126"),
+ CLK_MDD("gbe_125", 2, 10, 3, DIV_SEL1, DIV_SEL1, 6, 9,
+ "tbg_mux_gbe_125_128", "div1_gbe_50_129", "div2_gbe_50_130"),
+ CLK_GATE("gbe1_50", 3, 0, "gbe_50"),
+ CLK_GATE("gbe0_50", 4, 1, "gbe_50"),
+ CLK_GATE("gbe1_125", 5, 2, "gbe_125"),
+ CLK_GATE("gbe0_125", 6, 3, "gbe_125"),
+ CLK_MUX_GATE("gbe1_core", 7, 4, 13, "gbe_core",
+ "mux_gbe1_core_136", "fixed_gbe1_core_138"),
+ CLK_MUX_GATE("gbe0_core", 8, 5, 14, "gbe_core",
+ "mux_gbe0_core_139", "fixed_gbe0_core_141"),
+ CLK_MUX_GATE("gbe_bm", 9, 12, 12, "gbe_core",
+ "mux_gbe_bm_136", "fixed_gbe_bm_138"),
+ CLK_FULL_DD("sdio", 10, 11, 14, 7, DIV_SEL0, DIV_SEL0, 3, 6,
+ "tbg_mux_sdio_139", "div1_sdio_140", "div2_sdio_141",
+ "clk_mux_sdio_142"),
+ CLK_FULL_DD("usb32_usb2_sys", 11, 16, 16, 8, DIV_SEL0, DIV_SEL0, 9, 12,
+ "tbg_mux_usb32_usb2_sys_144", "div1_usb32_usb2_sys_145",
+ "div2_usb32_usb2_sys_146", "clk_mux_usb32_usb2_sys_147"),
+ CLK_FULL_DD("usb32_ss_sys", 12, 17, 18, 9, DIV_SEL0, DIV_SEL0, 15, 18,
+ "tbg_mux_usb32_ss_sys_149", "div1_usb32_ss_sys_150",
+ "div2_usb32_ss_sys_151", "clk_mux_usb32_ss_sys_152"),
+ CLK_GATE("pcie", 13, 14, "gbe_core")
+};
+
+static struct ofw_compat_data a37x0_sb_periph_compat_data[] = {
+ { "marvell,armada-3700-periph-clock-sb", 1 },
+ { NULL, 0 }
+};
+
+static int a37x0_sb_periph_clk_attach(device_t);
+static int a37x0_sb_periph_clk_probe(device_t);
+
+static device_method_t a37x0_sb_periph_clk_methods[] = {
+ DEVMETHOD(clkdev_device_unlock, a37x0_periph_clk_device_unlock),
+ DEVMETHOD(clkdev_device_lock, a37x0_periph_clk_device_lock),
+ DEVMETHOD(clkdev_read_4, a37x0_periph_clk_read_4),
+
+ DEVMETHOD(device_attach, a37x0_sb_periph_clk_attach),
+ DEVMETHOD(device_detach, a37x0_periph_clk_detach),
+ DEVMETHOD(device_probe, a37x0_sb_periph_clk_probe),
+
+ DEVMETHOD_END
+};
+
+static driver_t a37x0_sb_periph_driver = {
+ "a37x0_sb_periph_driver",
+ a37x0_sb_periph_clk_methods,
+ sizeof(struct a37x0_periph_clk_softc)
+};
+
+devclass_t a37x0_sb_periph_devclass;
+
+EARLY_DRIVER_MODULE(a37x0_sb_periph, simplebus, a37x0_sb_periph_driver,
+ a37x0_sb_periph_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_LATE);
+
+static int
+a37x0_sb_periph_clk_attach(device_t dev)
+{
+ struct a37x0_periph_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->devices = a37x0_sb_devices;
+ sc->device_count = SB_DEV_COUNT;
+
+ return (a37x0_periph_clk_attach(dev));
+}
+
+static int
+a37x0_sb_periph_clk_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev,
+ a37x0_sb_periph_compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "marvell,armada-3700-sb-periph-clock");
+
+ return (BUS_PROBE_DEFAULT);
+}
diff --git a/sys/arm/mv/clk/periph.h b/sys/arm/mv/clk/periph.h
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph.h
@@ -0,0 +1,422 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _PERIPH_H_
+#define _PERIPH_H_
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_mux.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_gate.h>
+
+#define TBG_SEL 0x0
+#define DIV_SEL0 0x4
+#define DIV_SEL1 0x8
+#define DIV_SEL2 0xC
+#define CLK_SEL 0x10
+#define CLK_DIS 0x14
+#define DIV_MASK 0x7
+
+#define MUX_POS 1
+#define DIV1_POS 2
+#define DIV2_POS 3
+#define GATE_POS 4
+#define FIXED1_POS 5
+#define FIXED2_POS 6
+#define CLK_MUX_POS 7
+
+#define RD4(_clk, offset, val) \
+ CLKDEV_READ_4(clknode_get_device(_clk), offset, val)
+
+#define A37x0_INTERNAL_CLK_ID(_base, _pos) \
+ ((_base * 10) + (_pos))
+
+#define CLK_FULL_DD(_name, _id, _gate_shift, _tbg_mux_shift, \
+ _clk_mux_shift, _div1_reg, _div2_reg, _div1_shift, _div2_shift, \
+ _tbg_mux_name, _div1_name, _div2_name, _clk_mux_name) \
+{ \
+ .type = CLK_FULL_DD, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.full_dd.tbg_mux.clkdef.name = _tbg_mux_name, \
+ .clk_def.full_dd.tbg_mux.offset = TBG_SEL, \
+ .clk_def.full_dd.tbg_mux.shift = _tbg_mux_shift, \
+ .clk_def.full_dd.tbg_mux.width = 0x2, \
+ .clk_def.full_dd.tbg_mux.mux_flags = 0x0, \
+ .clk_def.full_dd.div1.clkdef.name = _div1_name, \
+ .clk_def.full_dd.div1.offset = _div1_reg, \
+ .clk_def.full_dd.div1.i_shift = _div1_shift, \
+ .clk_def.full_dd.div1.i_width = 0x3, \
+ .clk_def.full_dd.div1.f_shift = 0x0, \
+ .clk_def.full_dd.div1.f_width = 0x0, \
+ .clk_def.full_dd.div1.div_flags = 0x0, \
+ .clk_def.full_dd.div1.div_table = NULL, \
+ .clk_def.full_dd.div2.clkdef.name = _div2_name, \
+ .clk_def.full_dd.div2.offset = _div2_reg, \
+ .clk_def.full_dd.div2.i_shift = _div2_shift, \
+ .clk_def.full_dd.div2.i_width = 0x3, \
+ .clk_def.full_dd.div2.f_shift = 0x0, \
+ .clk_def.full_dd.div2.f_width = 0x0, \
+ .clk_def.full_dd.div2.div_flags = 0x0, \
+ .clk_def.full_dd.div2.div_table = NULL, \
+ .clk_def.full_dd.clk_mux.clkdef.name = _clk_mux_name, \
+ .clk_def.full_dd.clk_mux.offset = CLK_SEL, \
+ .clk_def.full_dd.clk_mux.shift = _clk_mux_shift, \
+ .clk_def.full_dd.clk_mux.width = 0x1, \
+ .clk_def.full_dd.clk_mux.mux_flags = 0x0, \
+ .clk_def.full_dd.gate.clkdef.name = _name, \
+ .clk_def.full_dd.gate.offset = CLK_DIS, \
+ .clk_def.full_dd.gate.shift = _gate_shift, \
+ .clk_def.full_dd.gate.on_value = 0, \
+ .clk_def.full_dd.gate.off_value = 1, \
+ .clk_def.full_dd.gate.mask = 0x1, \
+ .clk_def.full_dd.gate.gate_flags = 0x0 \
+}
+
+#define CLK_FULL(_name, _id, _gate_shift, _tbg_mux_shift, \
+ _clk_mux_shift, _div1_reg, _div1_shift, _div_table, _tbg_mux_name, \
+ _div1_name, _clk_mux_name) \
+{ \
+ .type = CLK_FULL, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.full_d.tbg_mux.clkdef.name = _tbg_mux_name, \
+ .clk_def.full_d.tbg_mux.offset = TBG_SEL, \
+ .clk_def.full_d.tbg_mux.shift = _tbg_mux_shift, \
+ .clk_def.full_d.tbg_mux.width = 0x2, \
+ .clk_def.full_d.tbg_mux.mux_flags = 0x0, \
+ .clk_def.full_d.div.clkdef.name = _div1_name, \
+ .clk_def.full_d.div.offset = _div1_reg, \
+ .clk_def.full_d.div.i_shift = _div1_shift, \
+ .clk_def.full_d.div.i_width = 0x3, \
+ .clk_def.full_d.div.f_shift = 0x0, \
+ .clk_def.full_d.div.f_width = 0x0, \
+ .clk_def.full_d.div.div_flags = 0x0, \
+ .clk_def.full_d.div.div_table = _div_table, \
+ .clk_def.full_d.clk_mux.clkdef.name = _clk_mux_name, \
+ .clk_def.full_d.clk_mux.offset = CLK_SEL, \
+ .clk_def.full_d.clk_mux.shift = _clk_mux_shift, \
+ .clk_def.full_d.clk_mux.width = 0x1, \
+ .clk_def.full_d.clk_mux.mux_flags = 0x0, \
+ .clk_def.full_d.gate.clkdef.name = _name, \
+ .clk_def.full_d.gate.offset = CLK_DIS, \
+ .clk_def.full_d.gate.shift = _gate_shift, \
+ .clk_def.full_d.gate.on_value = 0, \
+ .clk_def.full_d.gate.off_value = 1, \
+ .clk_def.full_d.gate.mask = 0x1, \
+ .clk_def.full_d.gate.gate_flags = 0x0 \
+}
+
+#define CLK_CPU(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg, \
+ _div1_shift, _div_table, _tbg_mux_name, _div1_name) \
+{ \
+ .type = CLK_CPU, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.cpu.tbg_mux.clkdef.name = _tbg_mux_name, \
+ .clk_def.cpu.tbg_mux.offset = TBG_SEL, \
+ .clk_def.cpu.tbg_mux.shift = _tbg_mux_shift, \
+ .clk_def.cpu.tbg_mux.width = 0x2, \
+ .clk_def.cpu.tbg_mux.mux_flags = 0x0, \
+ .clk_def.cpu.div.clkdef.name = _div1_name, \
+ .clk_def.cpu.div.offset = _div1_reg, \
+ .clk_def.cpu.div.i_shift = _div1_shift, \
+ .clk_def.cpu.div.i_width = 0x3, \
+ .clk_def.cpu.div.f_shift = 0x0, \
+ .clk_def.cpu.div.f_width = 0x0, \
+ .clk_def.cpu.div.div_flags = 0x0, \
+ .clk_def.cpu.div.div_table = _div_table, \
+ .clk_def.cpu.clk_mux.clkdef.name = _name, \
+ .clk_def.cpu.clk_mux.offset = CLK_SEL, \
+ .clk_def.cpu.clk_mux.shift = _clk_mux_shift, \
+ .clk_def.cpu.clk_mux.width = 0x1, \
+ .clk_def.cpu.clk_mux.mux_flags = 0x0, \
+}
+
+#define CLK_GATE(_name, _id, _gate_shift, _pname) \
+{ \
+ .type = CLK_GATE, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .common_def.pname = _pname, \
+ .clk_def.gate.gate.clkdef.name = _name, \
+ .clk_def.gate.gate.clkdef.parent_cnt = 1, \
+ .clk_def.gate.gate.offset = CLK_DIS, \
+ .clk_def.gate.gate.shift = _gate_shift, \
+ .clk_def.gate.gate.on_value = 0, \
+ .clk_def.gate.gate.off_value = 1, \
+ .clk_def.gate.gate.mask = 0x1, \
+ .clk_def.gate.gate.gate_flags = 0x0 \
+}
+
+#define CLK_MDD(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg, \
+ _div2_reg, _div1_shift, _div2_shift, _tbg_mux_name, _div1_name, \
+ _div2_name) \
+{ \
+ .type = CLK_MDD, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.mdd.tbg_mux.clkdef.name = _tbg_mux_name, \
+ .clk_def.mdd.tbg_mux.offset = TBG_SEL, \
+ .clk_def.mdd.tbg_mux.shift = _tbg_mux_shift, \
+ .clk_def.mdd.tbg_mux.width = 0x2, \
+ .clk_def.mdd.tbg_mux.mux_flags = 0x0, \
+ .clk_def.mdd.div1.clkdef.name = _div1_name, \
+ .clk_def.mdd.div1.offset = _div1_reg, \
+ .clk_def.mdd.div1.i_shift = _div1_shift, \
+ .clk_def.mdd.div1.i_width = 0x3, \
+ .clk_def.mdd.div1.f_shift = 0x0, \
+ .clk_def.mdd.div1.f_width = 0x0, \
+ .clk_def.mdd.div1.div_flags = 0x0, \
+ .clk_def.mdd.div1.div_table = NULL, \
+ .clk_def.mdd.div2.clkdef.name = _div2_name, \
+ .clk_def.mdd.div2.offset = _div2_reg, \
+ .clk_def.mdd.div2.i_shift = _div2_shift, \
+ .clk_def.mdd.div2.i_width = 0x3, \
+ .clk_def.mdd.div2.f_shift = 0x0, \
+ .clk_def.mdd.div2.f_width = 0x0, \
+ .clk_def.mdd.div2.div_flags = 0x0, \
+ .clk_def.mdd.div2.div_table = NULL, \
+ .clk_def.mdd.clk_mux.clkdef.name = _name, \
+ .clk_def.mdd.clk_mux.offset = CLK_SEL, \
+ .clk_def.mdd.clk_mux.shift = _clk_mux_shift, \
+ .clk_def.mdd.clk_mux.width = 0x1, \
+ .clk_def.mdd.clk_mux.mux_flags = 0x0 \
+}
+
+#define CLK_MUX_GATE(_name, _id, _gate_shift, _mux_shift, _pname, \
+ _mux_name, _fixed_name) \
+{ \
+ .type = CLK_MUX_GATE, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .common_def.pname = _pname, \
+ .clk_def.mux_gate.mux.clkdef.name = _mux_name, \
+ .clk_def.mux_gate.mux.offset = TBG_SEL, \
+ .clk_def.mux_gate.mux.shift = _mux_shift, \
+ .clk_def.mux_gate.mux.width = 0x1, \
+ .clk_def.mux_gate.mux.mux_flags = 0x0, \
+ .clk_def.mux_gate.gate.clkdef.name = _name, \
+ .clk_def.mux_gate.gate.offset = CLK_DIS, \
+ .clk_def.mux_gate.gate.shift = _gate_shift, \
+ .clk_def.mux_gate.gate.on_value = 0, \
+ .clk_def.mux_gate.gate.off_value = 1, \
+ .clk_def.mux_gate.gate.mask = 0x1, \
+ .clk_def.mux_gate.gate.gate_flags = 0x0, \
+ .clk_def.mux_gate.fixed.clkdef.name = _fixed_name \
+}
+
+#define CLK_MUX_GATE_FIXED(_name, _id, _gate_shift, _mux_shift, \
+ _mux_name, _gate_name, _fixed1_name) \
+{ \
+ .type = CLK_MUX_GATE_FIXED, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.mux_gate_fixed.mux.clkdef.name = _mux_name, \
+ .clk_def.mux_gate_fixed.mux.offset = TBG_SEL, \
+ .clk_def.mux_gate_fixed.mux.shift = _mux_shift, \
+ .clk_def.mux_gate_fixed.mux.width = 0x1, \
+ .clk_def.mux_gate_fixed.mux.mux_flags = 0x0, \
+ .clk_def.mux_gate_fixed.gate.clkdef.name = _gate_name, \
+ .clk_def.mux_gate_fixed.gate.offset = CLK_DIS, \
+ .clk_def.mux_gate_fixed.gate.shift = _gate_shift, \
+ .clk_def.mux_gate_fixed.gate.on_value = 0, \
+ .clk_def.mux_gate_fixed.gate.off_value = 1, \
+ .clk_def.mux_gate_fixed.gate.mask = 0x1, \
+ .clk_def.mux_gate_fixed.gate.gate_flags = 0x0, \
+ .clk_def.mux_gate_fixed.fixed1.clkdef.name = _fixed1_name, \
+ .clk_def.mux_gate_fixed.fixed2.clkdef.name = _name \
+}
+
+#define CLK_FIXED(_name, _id, _gate_shift, _mux_shift, _mux_name, \
+ _fixed_name) \
+{ \
+ .type = CLK_FIXED, \
+ .common_def.device_name = _name, \
+ .common_def.device_id = _id, \
+ .clk_def.fixed.mux.clkdef.name = _mux_name, \
+ .clk_def.fixed.mux.offset = TBG_SEL, \
+ .clk_def.fixed.mux.shift = _mux_shift, \
+ .clk_def.fixed.mux.width = 0x1, \
+ .clk_def.fixed.mux.mux_flags = 0x0, \
+ .clk_def.fixed.gate.clkdef.name = _name, \
+ .clk_def.fixed.gate.offset = CLK_DIS, \
+ .clk_def.fixed.gate.shift = _gate_shift, \
+ .clk_def.fixed.gate.on_value = 0, \
+ .clk_def.fixed.gate.off_value = 1, \
+ .clk_def.fixed.gate.mask = 0x1, \
+ .clk_def.fixed.gate.gate_flags = 0x0, \
+ .clk_def.fixed.fixed.clkdef.name = _fixed_name \
+}
+
+struct a37x0_periph_clk_softc {
+ device_t dev;
+ struct resource *res;
+ struct clkdom *clkdom;
+ struct mtx mtx;
+ struct a37x0_periph_clknode_def *devices;
+ int device_count;
+};
+
+struct a37x0_periph_clk_dd_def {
+ struct clk_mux_def tbg_mux;
+ struct clk_div_def div1;
+ struct clk_div_def div2;
+ struct clk_mux_def clk_mux;
+ struct clk_gate_def gate;
+};
+
+struct a37x0_periph_clk_cpu_def {
+ struct clk_mux_def tbg_mux;
+ struct clk_div_def div;
+ struct clk_mux_def clk_mux;
+};
+
+struct a37x0_periph_clk_d_def {
+ struct clk_mux_def tbg_mux;
+ struct clk_div_def div;
+ struct clk_mux_def clk_mux;
+ struct clk_gate_def gate;
+};
+
+struct a37x0_periph_clk_fixed_def {
+ struct clk_mux_def mux;
+ struct clk_fixed_def fixed;
+ struct clk_gate_def gate;
+};
+
+struct a37x0_periph_clk_gate_def {
+ struct clk_gate_def gate;
+};
+
+struct a37x0_periph_clk_mux_dd_def {
+ struct clk_mux_def tbg_mux;
+ struct clk_div_def div1;
+ struct clk_div_def div2;
+ struct clk_mux_def clk_mux;
+};
+
+struct a37x0_periph_clk_mux_div_def {
+ struct clk_mux_def mux;
+ struct clk_div_def div;
+};
+
+struct a37x0_periph_clk_mux_gate_def {
+ struct clk_mux_def mux;
+ struct clk_fixed_def fixed;
+ struct clk_gate_def gate;
+};
+
+struct a37x0_periph_clk_mux_gate_fixed_def {
+ struct clk_fixed_def fixed1;
+ struct clk_mux_def mux;
+ struct clk_gate_def gate;
+ struct clk_fixed_def fixed2;
+};
+
+enum a37x0_periph_clk_type {
+ /* Double divider clock */
+ CLK_FULL_DD,
+ /* Single divider clock */
+ CLK_FULL,
+ /* Gate clock */
+ CLK_GATE,
+ /* Mux, gate clock */
+ CLK_MUX_GATE,
+ /* CPU clock */
+ CLK_CPU,
+ /* Clock with fixed frequency divider */
+ CLK_FIXED,
+ /* Clock with double divider, without gate */
+ CLK_MDD,
+ /* Clock with two fixed frequency dividers */
+ CLK_MUX_GATE_FIXED
+};
+
+struct a37x0_periph_common_defs {
+ char *device_name;
+ int device_id;
+ int tbg_cnt;
+ const char *pname;
+ const char **tbgs;
+ const char *xtal;
+};
+
+union a37x0_periph_clocks_defs {
+ struct a37x0_periph_clk_dd_def full_dd;
+ struct a37x0_periph_clk_d_def full_d;
+ struct a37x0_periph_clk_gate_def gate;
+ struct a37x0_periph_clk_mux_gate_def mux_gate;
+ struct a37x0_periph_clk_cpu_def cpu;
+ struct a37x0_periph_clk_fixed_def fixed;
+ struct a37x0_periph_clk_mux_dd_def mdd;
+ struct a37x0_periph_clk_mux_gate_fixed_def mux_gate_fixed;
+};
+
+struct a37x0_periph_clknode_def {
+ enum a37x0_periph_clk_type type;
+ struct a37x0_periph_common_defs common_def;
+ union a37x0_periph_clocks_defs clk_def;
+};
+
+int a37x0_periph_create_mux(struct clkdom *,
+ struct clk_mux_def *, int);
+int a37x0_periph_create_div(struct clkdom *,
+ struct clk_div_def *, int);
+int a37x0_periph_create_gate(struct clkdom *,
+ struct clk_gate_def *, int);
+void a37x0_periph_set_props(struct clknode_init_def *, const char **,
+ unsigned int);
+int a37x0_periph_d_register_full_clk_dd(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_d_register_full_clk(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_d_register_periph_cpu(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_fixed_register_fixed(struct clkdom*,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_gate_register_gate(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_d_register_mdd(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_d_register_mux_div_clk(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_register_mux_gate(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+int a37x0_periph_register_mux_gate_fixed(struct clkdom *,
+ struct a37x0_periph_clknode_def *);
+
+int a37x0_periph_clk_read_4(device_t, bus_addr_t, uint32_t *);
+void a37x0_periph_clk_device_unlock(device_t);
+void a37x0_periph_clk_device_lock(device_t);
+int a37x0_periph_clk_attach(device_t);
+int a37x0_periph_clk_detach(device_t);
+
+#endif
diff --git a/sys/arm/mv/clk/periph.c b/sys/arm/mv/clk/periph.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph.c
@@ -0,0 +1,112 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+int
+a37x0_periph_create_mux(struct clkdom *clkdom,
+ struct clk_mux_def *mux, int id)
+{
+ int error;
+
+ mux->clkdef.id = id;
+
+ error = clknode_mux_register(clkdom, mux);
+ if (error != 0) {
+ printf("Failed to create %s: %d\n", mux->clkdef.name, error);
+ return (error);
+ }
+
+ return (0);
+}
+
+int
+a37x0_periph_create_div(struct clkdom *clkdom,
+ struct clk_div_def *div, int id)
+{
+ int error;
+
+ div->clkdef.id = id;
+
+ error = clknode_div_register(clkdom, div);
+ if (error != 0) {
+ printf("Failed to register %s: %d\n", div->clkdef.name, error);
+ return (error);
+ }
+
+ return (0);
+}
+
+int
+a37x0_periph_create_gate(struct clkdom *clkdom,
+ struct clk_gate_def *gate, int id)
+{
+ int error;
+
+ gate->clkdef.id = id;
+
+ error = clknode_gate_register(clkdom, gate);
+ if (error != 0) {
+ printf("Failed to create %s:%d\n", gate->clkdef.name, error);
+ return (error);
+ }
+
+ return (0);
+}
+
+void
+a37x0_periph_set_props(struct clknode_init_def *clkdef,
+ const char **parent_names, unsigned int parent_cnt)
+{
+
+ clkdef->parent_names = parent_names;
+ clkdef->parent_cnt = parent_cnt;
+}
+
diff --git a/sys/arm/mv/clk/periph_clk_d.c b/sys/arm/mv/clk/periph_clk_d.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph_clk_d.c
@@ -0,0 +1,282 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define PARENT_CNT 2
+
+/*
+ * Register chain: mux (select proper TBG) -> div1 (first frequency divider) ->
+ * div2 (second frequency divider) -> mux (select divided freq.
+ * or xtal output) -> gate (enable or disable clock), which is also final node
+ */
+
+int
+a37x0_periph_d_register_full_clk_dd(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_mux_def *clk_mux;
+ struct clk_mux_def *tbg_mux;
+ struct clk_gate_def *gate;
+ struct clk_div_def *div1;
+ struct clk_div_def *div2;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_id = device_def->common_def.device_id;
+ dev_name = device_def->common_def.device_name;
+ tbg_mux = &device_def->clk_def.full_dd.tbg_mux;
+ div1 = &device_def->clk_def.full_dd.div1;
+ div2 = &device_def->clk_def.full_dd.div2;
+ gate = &device_def->clk_def.full_dd.gate;
+ clk_mux = &device_def->clk_def.full_dd.clk_mux;
+
+ a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
+ device_def->common_def.tbg_cnt);
+
+ error = a37x0_periph_create_mux(clkdom,
+ tbg_mux, A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div1->clkdef, &tbg_mux->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div1,
+ A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div2->clkdef, &div1->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div2,
+ A37x0_INTERNAL_CLK_ID(dev_id, DIV2_POS));
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.xtal;
+ parent_names[1] = div2->clkdef.name;
+
+ a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, clk_mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, CLK_MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&gate->clkdef, &clk_mux->clkdef.name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ dev_id);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
+
+/*
+ * Register chain: mux (select proper TBG) -> div1 (first frequency divider) ->
+ * mux (select divided freq. or xtal output) -> gate (enable or disable clock),
+ * which is also final node
+ */
+
+int
+a37x0_periph_d_register_full_clk(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_mux_def *tbg_mux;
+ struct clk_mux_def *clk_mux;
+ struct clk_gate_def *gate;
+ struct clk_div_def *div;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_id = device_def->common_def.device_id;
+ dev_name = device_def->common_def.device_name;
+ tbg_mux = &device_def->clk_def.full_d.tbg_mux;
+ div = &device_def->clk_def.full_d.div;
+ gate = &device_def->clk_def.full_d.gate;
+ clk_mux = &device_def->clk_def.full_d. clk_mux;
+
+ a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
+ device_def->common_def.tbg_cnt);
+ error = a37x0_periph_create_mux(clkdom, tbg_mux,
+ A37x0_INTERNAL_CLK_ID(device_def->common_def.device_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div->clkdef, &tbg_mux->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div,
+ A37x0_INTERNAL_CLK_ID(device_def->common_def.device_id, DIV1_POS));
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.xtal;
+ parent_names[1] = div->clkdef.name;
+
+ a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, clk_mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, CLK_MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&gate->clkdef, &clk_mux->clkdef.name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ dev_id);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
+
+/*
+ * Register CPU clock. It consists of mux (select proper TBG) -> div (frequency
+ * divider) -> mux (choose divided or xtal output).
+ */
+
+int
+a37x0_periph_d_register_periph_cpu(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_mux_def *clk_mux;
+ struct clk_mux_def *tbg_mux;
+ struct clk_div_def *div;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_name = device_def->common_def.device_name;
+ dev_id = device_def->common_def.device_id;
+ tbg_mux = &device_def->clk_def.cpu.tbg_mux;
+ div = &device_def->clk_def.cpu.div;
+ clk_mux = &device_def->clk_def.cpu.clk_mux;
+
+ a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
+ device_def->common_def.tbg_cnt);
+ error = a37x0_periph_create_mux(clkdom, tbg_mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div->clkdef, &tbg_mux->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div,
+ A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.xtal;
+ parent_names[1] = div->clkdef.name;
+
+ a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, clk_mux,
+ dev_id);
+
+fail:
+
+ return (error);
+}
+
+/*
+ * Register chain: mux (choose proper TBG) -> div1 (first frequency divider) ->
+ * div2 (second frequency divider) -> mux (choose divided or xtal output).
+ */
+int
+a37x0_periph_d_register_mdd(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_mux_def *tbg_mux;
+ struct clk_mux_def *clk_mux;
+ struct clk_div_def *div1;
+ struct clk_div_def *div2;
+ const char * dev_name;
+ int error, dev_id;
+
+ dev_name = device_def->common_def.device_name;
+ dev_id = device_def->common_def.device_id;
+ tbg_mux = &device_def->clk_def.mdd.tbg_mux;
+ div1 = &device_def->clk_def.mdd.div1;
+ div2 = &device_def->clk_def.mdd.div2;
+ clk_mux = &device_def->clk_def.mdd.clk_mux;
+
+ a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
+ device_def->common_def.tbg_cnt);
+ error = a37x0_periph_create_mux(clkdom, tbg_mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div1->clkdef, &tbg_mux->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div1,
+ A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&div2->clkdef, &div1->clkdef.name, 1);
+ error = a37x0_periph_create_div(clkdom, div2,
+ A37x0_INTERNAL_CLK_ID(dev_id, DIV2_POS));
+
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.xtal;
+ parent_names[1] = div2->clkdef.name;
+
+ a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, clk_mux,
+ dev_id);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
diff --git a/sys/arm/mv/clk/periph_clk_fixed.c b/sys/arm/mv/clk/periph_clk_fixed.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph_clk_fixed.c
@@ -0,0 +1,107 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define PARENT_CNT 2
+
+/*
+ * Register clock with fixed frequency divider clock. Chain consists of:
+ * fixed clock (output from xtal/2) -> mux (choose fixed or xtal frequency)
+ */
+
+int
+a37x0_periph_fixed_register_fixed(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_fixed_def fixed_def;
+ struct clk_gate_def *gate;
+ struct clk_mux_def *mux;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_name = device_def->common_def.device_name;
+ dev_id = device_def->common_def.device_id;
+ mux = &device_def->clk_def.fixed.mux;
+ gate = &device_def->clk_def.fixed.gate;
+ fixed_def = device_def->clk_def.fixed.fixed;
+
+ fixed_def.clkdef.parent_names = &device_def->common_def.xtal;
+ fixed_def.clkdef.parent_cnt = 1;
+ fixed_def.clkdef.id = A37x0_INTERNAL_CLK_ID(dev_id, FIXED1_POS);
+ fixed_def.clkdef.flags = 0;
+ fixed_def.mult = 1;
+ fixed_def.div = 2;
+ fixed_def.freq = 0;
+
+ parent_names[0] = device_def->common_def.xtal;
+ parent_names[1] = fixed_def.clkdef.name;
+
+ error = clknode_fixed_register(clkdom, &fixed_def);
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&mux->clkdef, parent_names ,PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&gate->clkdef, &mux->clkdef.name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ dev_id);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
diff --git a/sys/arm/mv/clk/periph_clk_gate.c b/sys/arm/mv/clk/periph_clk_gate.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph_clk_gate.c
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+/*
+ * Regsiter gate clock (disable or enable clock).
+ */
+
+int
+a37x0_periph_gate_register_gate(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ struct clk_gate_def *gate;
+ const char *parent_name;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_id = device_def->common_def.device_id;
+ dev_name = device_def->common_def.device_name;
+
+ gate = &device_def->clk_def.gate.gate;
+
+ if (device_def->common_def.pname == NULL)
+ parent_name = device_def->common_def.xtal;
+ else
+ parent_name = device_def->common_def.pname;
+
+ a37x0_periph_set_props(&gate->clkdef, &parent_name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ dev_id);
+ if (error) goto fail;
+
+ fail:
+ return (error);
+
+ return (0);
+}
diff --git a/sys/arm/mv/clk/periph_clk_mux_gate.c b/sys/arm/mv/clk/periph_clk_mux_gate.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/mv/clk/periph_clk_mux_gate.c
@@ -0,0 +1,170 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+#include "periph.h"
+
+#define PARENT_CNT 2
+#define TBG_A_S_OFW_INDEX 0
+
+/*
+ * Register chain: fixed (freq/2) -> mux (choose fixed or parent frequency) ->
+ * gate (enable or disable clock).
+ */
+
+int
+a37x0_periph_register_mux_gate(struct clkdom *clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ const char *parent_names[PARENT_CNT];
+ struct clk_fixed_def fixed;
+ struct clk_gate_def *gate;
+ struct clk_mux_def *mux;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_name = device_def->common_def.device_name;
+ dev_id = device_def->common_def.device_id;
+ mux = &device_def->clk_def.mux_gate.mux;
+ gate = &device_def->clk_def.mux_gate.gate;
+ fixed = device_def->clk_def.fixed.fixed;
+
+ fixed.clkdef.id = A37x0_INTERNAL_CLK_ID(dev_id, FIXED1_POS);
+ fixed.clkdef.parent_names = &device_def->common_def.pname;
+ fixed.clkdef.parent_cnt = 1;
+ fixed.clkdef.flags = 0x0;
+ fixed.mult = 1;
+ fixed.div = 2;
+ fixed.freq = 0;
+
+ error = clknode_fixed_register(clkdom, &fixed);
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.pname;
+ parent_names[1] = fixed.clkdef.name;
+
+ a37x0_periph_set_props(&mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&gate->clkdef, &mux->clkdef.name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ dev_id);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
+
+/*
+ * Register chain: fixed1 (freq/2) -> mux (fixed1 or TBG-A-S frequency) ->
+ * gate -> fixed2 (freq/2).
+ */
+
+int
+a37x0_periph_register_mux_gate_fixed(struct clkdom * clkdom,
+ struct a37x0_periph_clknode_def *device_def)
+{
+ struct clk_fixed_def *fixed1, *fixed2;
+ const char *parent_names[PARENT_CNT];
+ struct clk_gate_def *gate;
+ struct clk_mux_def *mux;
+ const char *dev_name;
+ int error, dev_id;
+
+ dev_name = device_def->common_def.device_name;
+ dev_id = device_def->common_def.device_id;
+ mux = &device_def->clk_def.mux_gate_fixed.mux;
+ gate = &device_def->clk_def.mux_gate_fixed.gate;
+ fixed1 = &device_def->clk_def.mux_gate_fixed.fixed1;
+ fixed2 = &device_def->clk_def.mux_gate_fixed.fixed2;
+
+ fixed1->clkdef.parent_names = &device_def->common_def.pname;
+ fixed1->clkdef.id = A37x0_INTERNAL_CLK_ID(dev_id, FIXED1_POS);
+ fixed1->clkdef.flags = 0x0;
+ fixed1->mult = 1;
+ fixed1->div = 2;
+ fixed1->freq = 0;
+
+ error = clknode_fixed_register(clkdom, fixed1);
+ if (error)
+ goto fail;
+
+ parent_names[0] = device_def->common_def.tbgs[TBG_A_S_OFW_INDEX];
+ parent_names[1] = fixed1->clkdef.name;
+
+ a37x0_periph_set_props(&mux->clkdef, parent_names, PARENT_CNT);
+ error = a37x0_periph_create_mux(clkdom, mux,
+ A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
+ if (error)
+ goto fail;
+
+ a37x0_periph_set_props(&gate->clkdef, &mux->clkdef.name, 1);
+ error = a37x0_periph_create_gate(clkdom, gate,
+ A37x0_INTERNAL_CLK_ID(dev_id, GATE_POS));
+ if (error)
+ goto fail;
+
+ fixed2->clkdef.parent_names = &gate->clkdef.name;
+ fixed2->clkdef.parent_cnt = 1;
+ fixed2->clkdef.id = dev_id;
+
+ error = clknode_fixed_register(clkdom, fixed2);
+ if (error)
+ goto fail;
+
+fail:
+
+ return (error);
+}
diff --git a/sys/arm64/conf/std.marvell b/sys/arm64/conf/std.marvell
--- a/sys/arm64/conf/std.marvell
+++ b/sys/arm64/conf/std.marvell
@@ -56,6 +56,8 @@
# Clocks
device a37x0_xtal # Marvell xtal-clock
device a37x0_tbg # Marvell tbg-clock
+device a37x0_nb_periph # Marvell north-bridge peripheral clock
+device a37x0_sb_periph # Maravell south-bridge peripheral clock
# DTBs
makeoptions MODULES_EXTRA+="dtb/mv"
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -470,6 +470,14 @@
arm/mv/mv_cp110_icu_bus.c optional mv_cp110_icu fdt
arm/mv/mv_thermal.c optional SOC_MARVELL_8K mv_thermal fdt
arm/mv/clk/a37x0_tbg_pll.c optional a37x0_tbg clk fdt syscon
+arm/mv/clk/a37x0_periph_clk_driver.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
+arm/mv/clk/a37x0_nb_periph_clk_driver.c optional a37x0_nb_periph clk fdt syscon
+arm/mv/clk/a37x0_sb_periph_clk_driver.c optional a37x0_sb_periph clk fdt syscon
+arm/mv/clk/periph.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
+arm/mv/clk/periph_clk_d.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
+arm/mv/clk/periph_clk_fixed.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
+arm/mv/clk/periph_clk_gate.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
+arm/mv/clk/periph_clk_mux_gate.c optional a37x0_nb_periph a37x0_sb_periph clk fdt syscon
# NVidia
arm/nvidia/tegra_abpmisc.c optional fdt soc_nvidia_tegra210
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 26, 8:24 AM (20 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32175754
Default Alt Text
D32294.id100910.diff (56 KB)
Attached To
Mode
D32294: Add driver for marvell, a37x0 peripheral clocks
Attached
Detach File
Event Timeline
Log In to Comment