Page MenuHomeFreeBSD

D57732.diff
No OneTemporary

D57732.diff

diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC
--- a/sys/arm64/conf/GENERIC
+++ b/sys/arm64/conf/GENERIC
@@ -38,6 +38,7 @@
include "std.hisilicon"
include "std.imx"
include "std.marvell"
+include "std.mediatek"
include "std.nvidia"
include "std.nxp"
include "std.qcom"
diff --git a/sys/arm64/conf/MEDIATEK b/sys/arm64/conf/MEDIATEK
new file mode 100644
--- /dev/null
+++ b/sys/arm64/conf/MEDIATEK
@@ -0,0 +1,38 @@
+#
+# MEDIATEK -- Mediatek kernel configuration file for FreeBSD/arm64
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# https://docs.freebsd.org/en/books/handbook/kernelconfig/#kernelconfig-config
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+
+#NO_UNIVERSE
+
+cpu ARM64
+ident MEDIATEK
+
+makeoptions DEBUG=-g # Enable kernel debugging sybmbols
+makeoptions WITH_KERNEL_BIN=1
+
+options EARLY_PRINTF=ns8250
+options SOCDEV_PA=0x11002000
+options UART_NS8250_EARLY_REG_SHIFT=2
+options UART_NS8250_EARLY_REG_IO_WIDTH=2
+options BOOTVERBOSE
+
+# Include SoC specific configuration
+include "std.arm64"
+include "std.dev"
+include "std.mediatek"
+
diff --git a/sys/arm64/conf/std.mediatek b/sys/arm64/conf/std.mediatek
new file mode 100644
--- /dev/null
+++ b/sys/arm64/conf/std.mediatek
@@ -0,0 +1,10 @@
+options SOC_MEDIATEK
+
+device uart_ns8250
+
+# GPIO / PINCTRL
+device mt7622_pinctrl
+
+options FDT
+# DTBs
+makeoptions MODULES_EXTRA+="dtb/mediatek"
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mdtk_clk.h b/sys/arm64/mediatek/mdtk_clk.h
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mdtk_clk.h
@@ -0,0 +1,149 @@
+#ifndef __MDTK_CLK_H__
+#define __MDTK_CLK_H__
+
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/* Parent list */
+#define PLIST(_name) static const char *_name[]
+
+/* Standard gate. */
+#define GATE(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 1, \
+ .on_value = 1, \
+ .off_value = 0, \
+}
+
+/* Inverter gate. */
+#define I_GATE(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 1, \
+ .on_value = 0, \
+ .off_value = 1, \
+}
+
+/* Fixed rate clock. */
+#define FRATE(_id, _name, _freq) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_cnt = 0, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .freq = _freq, \
+}
+
+/* Link. */
+#define LINK(_idx, _clkname, _pname) \
+{ \
+ .clkdef.id = _idx, \
+ .clkdef.name = _clkname, \
+ .clkdef.parent_name = _pname, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS \
+}
+
+/* Fixed factor clock. */
+#define FFACT(_id, _name, _pname, _mult, _div) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .mult = _mult, \
+ .div = _div, \
+}
+
+/* Divided clock. */
+#define DIV(_id, _name, _pname, _reg, _shift, _width) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = _name, \
+ .clkdef.parent_names = (const char *[]){_pname}, \
+ .clkdef.parent_cnt = 1, \
+ .offset = _reg, \
+ .i_shift = _shift, \
+ .i_width = _width, \
+}
+
+/* Pure multiplexer. */
+#define MUX0(_id, cname, plists, _reg, _shift, _width) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = plists, \
+ .clkdef.parent_cnt = nitems(plists), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = _reg, \
+ .shift = _shift, \
+ .width = _width, \
+}
+
+/* Inverter gate. */
+#define I_GATE(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 1, \
+ .on_value = 0, \
+ .off_value = 1, \
+}
+
+struct mdtk_clk_def {
+ struct clk_link_def *linked_def;
+ struct clk_fixed_def *fixed_def;
+ struct clk_mux_def *muxes_def;
+ struct clk_gate_def *gates_def;
+ struct clk_div_def *dived_def;
+ int num_linked;
+ int num_fixed;
+ int num_muxes;
+ int num_gates;
+ int num_dived;
+};
+
+struct mdtk_clk_softc {
+ device_t dev;
+ struct resource *mem_res;
+ struct mtx mtx;
+ struct clkdom *clkdom;
+ struct syscon *syscon;
+};
+
+int mdtk_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val);
+
+int mdtk_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val);
+
+int mdtk_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
+ uint32_t set_mask);
+
+void mdtk_clkdev_device_lock(device_t dev);
+
+void mdtk_clkdev_device_unlock(device_t dev);
+
+void mdtk_register_clocks(device_t dev, struct mdtk_clk_def *cldef);
+int mdtk_hwreset_by_idx(struct mdtk_clk_softc *sc, intptr_t idx, bool reset);
+#endif
diff --git a/sys/arm64/mediatek/mdtk_clk.c b/sys/arm64/mediatek/mdtk_clk.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mdtk_clk.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.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/mt7622-clk.h>
+#include <dev/clk/clk_fixed.h>
+#include <dev/clk/clk_div.h>
+#include <dev/clk/clk_mux.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/clk/clk_link.h>
+
+#include <arm64/mediatek/mdtk_clk.h>
+
+static void
+init_fixeds(struct mdtk_clk_softc *sc, struct clk_fixed_def *clks,
+ int nclks) {
+ int i, rv;
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_fixed_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clknode_fixed_register failed");
+ }
+
+}
+
+static void
+init_linked(struct mdtk_clk_softc *sc, struct clk_link_def *clks,
+ int nclks) {
+ for (int i = 0; i < nclks; i++) {
+ int rv = clknode_link_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clknode_link_register failed");
+ }
+
+}
+
+static void
+init_muxes(struct mdtk_clk_softc *sc, struct clk_mux_def *clks, int nclks) {
+ int i, rv;
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_mux_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clknode_mux_register failed");
+ }
+}
+
+static void
+init_gates(struct mdtk_clk_softc *sc, struct clk_gate_def *clks, int nclks) {
+ int i, rv;
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_gate_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clknode_gate_register failed");
+ }
+}
+
+static void
+init_div(struct mdtk_clk_softc *sc, struct clk_div_def *clks, int nclks) {
+ int i, rv;
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_div_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clknode_div_register failed");
+ }
+}
+
+int
+mdtk_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *val = bus_read_4(sc->mem_res, addr);
+ return (0);
+}
+
+int
+mdtk_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_4(sc->mem_res, addr, val);
+ return (0);
+}
+
+int
+mdtk_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
+ uint32_t set_mask) {
+ struct mdtk_clk_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ reg = bus_read_4(sc->mem_res, addr);
+ reg &= ~clear_mask;
+ reg |= set_mask;
+ bus_write_4(sc->mem_res, addr, reg);
+ return (0);
+}
+
+void
+mdtk_clkdev_device_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+void
+mdtk_clkdev_device_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+void
+mdtk_register_clocks(device_t dev, struct mdtk_clk_def *cldef) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL)
+ panic("clkdom == NULL");
+
+ init_fixeds(sc, cldef->fixed_def, cldef->num_fixed);
+ init_linked(sc, cldef->linked_def, cldef->num_linked);
+ init_muxes(sc, cldef->muxes_def, cldef->num_muxes);
+ init_gates(sc, cldef->gates_def, cldef->num_gates);
+ init_div(sc, cldef->dived_def, cldef->num_dived);
+
+ clkdom_finit(sc->clkdom);
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+}
+
+int
+mdtk_hwreset_by_idx(struct mdtk_clk_softc *sc, intptr_t idx, bool reset) {
+ device_printf(sc->dev, "idx %ld, reset %d\n", idx, reset);
+ return (0);
+}
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mt7622_clk_audio.c b/sys/arm64/mediatek/mt7622_clk_audio.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_audio.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+#include <dt-bindings/clock/mt7622-clk.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/hwreset/hwreset.h>
+#include "syscon_if.h"
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-audsys", 1},
+ {NULL, 0},
+};
+
+static struct clk_gate_def gates_clk[] = {
+ /* AUDIO0 */
+ GATE(CLK_AUDIO_AFE, "audio_afe", "rtc", 0x0, 2),
+ GATE(CLK_AUDIO_HDMI, "audio_hdmi", "apll1_ck_sel", 0x0, 20),
+ GATE(CLK_AUDIO_SPDF, "audio_spdf", "apll1_ck_sel", 0x0, 21),
+ GATE(CLK_AUDIO_APLL, "audio_apll", "apll1_ck_sel", 0x0, 23),
+ /* AUDIO1 */
+ GATE(CLK_AUDIO_I2SIN1, "audio_i2sin1", "a1sys_hp_sel", 0x10, 0),
+ GATE(CLK_AUDIO_I2SIN2, "audio_i2sin2", "a1sys_hp_sel", 0x10, 1),
+ GATE(CLK_AUDIO_I2SIN3, "audio_i2sin3", "a1sys_hp_sel", 0x10, 2),
+ GATE(CLK_AUDIO_I2SIN4, "audio_i2sin4", "a1sys_hp_sel", 0x10, 3),
+ GATE(CLK_AUDIO_I2SO1, "audio_i2so1", "a1sys_hp_sel", 0x10, 6),
+ GATE(CLK_AUDIO_I2SO2, "audio_i2so2", "a1sys_hp_sel", 0x10, 7),
+ GATE(CLK_AUDIO_I2SO3, "audio_i2so3", "a1sys_hp_sel", 0x10, 8),
+ GATE(CLK_AUDIO_I2SO4, "audio_i2so4", "a1sys_hp_sel", 0x10, 9),
+ GATE(CLK_AUDIO_ASRCI1, "audio_asrci1", "asm_h_sel", 0x10, 12),
+ GATE(CLK_AUDIO_ASRCI2, "audio_asrci2", "asm_h_sel", 0x10, 13),
+ GATE(CLK_AUDIO_ASRCO1, "audio_asrco1", "asm_h_sel", 0x10, 14),
+ GATE(CLK_AUDIO_ASRCO2, "audio_asrco2", "asm_h_sel", 0x10, 15),
+ GATE(CLK_AUDIO_INTDIR, "audio_intdir", "intdir_sel", 0x10, 20),
+ GATE(CLK_AUDIO_A1SYS, "audio_a1sys", "a1sys_hp_sel", 0x10, 21),
+ GATE(CLK_AUDIO_A2SYS, "audio_a2sys", "a2sys_hp_sel", 0x10, 22),
+ GATE(CLK_AUDIO_AFE_CONN, "audio_afe_conn", "a1sys_hp_sel", 0x10, 23),
+ /* AUDIO2 */
+ GATE(CLK_AUDIO_UL1, "audio_ul1", "a1sys_hp_sel", 0x14, 0),
+ GATE(CLK_AUDIO_UL2, "audio_ul2", "a1sys_hp_sel", 0x14, 1),
+ GATE(CLK_AUDIO_UL3, "audio_ul3", "a1sys_hp_sel", 0x14, 2),
+ GATE(CLK_AUDIO_UL4, "audio_ul4", "a1sys_hp_sel", 0x14, 3),
+ GATE(CLK_AUDIO_UL5, "audio_ul5", "a1sys_hp_sel", 0x14, 4),
+ GATE(CLK_AUDIO_UL6, "audio_ul6", "a1sys_hp_sel", 0x14, 5),
+ GATE(CLK_AUDIO_DL1, "audio_dl1", "a1sys_hp_sel", 0x14, 6),
+ GATE(CLK_AUDIO_DL2, "audio_dl2", "a1sys_hp_sel", 0x14, 7),
+ GATE(CLK_AUDIO_DL3, "audio_dl3", "a1sys_hp_sel", 0x14, 8),
+ GATE(CLK_AUDIO_DL4, "audio_dl4", "a1sys_hp_sel", 0x14, 9),
+ GATE(CLK_AUDIO_DL5, "audio_dl5", "a1sys_hp_sel", 0x14, 10),
+ GATE(CLK_AUDIO_DL6, "audio_dl6", "a1sys_hp_sel", 0x14, 11),
+ GATE(CLK_AUDIO_DLMCH, "audio_dlmch", "a1sys_hp_sel", 0x14, 12),
+ GATE(CLK_AUDIO_ARB1, "audio_arb1", "a1sys_hp_sel", 0x14, 13),
+ GATE(CLK_AUDIO_AWB, "audio_awb", "a1sys_hp_sel", 0x14, 14),
+ GATE(CLK_AUDIO_AWB2, "audio_awb2", "a1sys_hp_sel", 0x14, 15),
+ GATE(CLK_AUDIO_DAI, "audio_dai", "a1sys_hp_sel", 0x14, 16),
+ GATE(CLK_AUDIO_MOD, "audio_mod", "a1sys_hp_sel", 0x14, 17),
+ /* AUDIO3 */
+ GATE(CLK_AUDIO_ASRCI3, "audio_asrci3", "asm_h_sel", 0x634, 2),
+ GATE(CLK_AUDIO_ASRCI4, "audio_asrci4", "asm_h_sel", 0x634, 3),
+ GATE(CLK_AUDIO_ASRCO3, "audio_asrco3", "asm_h_sel", 0x634, 6),
+ GATE(CLK_AUDIO_ASRCO4, "audio_asrco4", "asm_h_sel", 0x634, 7),
+ GATE(CLK_AUDIO_MEM_ASRC1, "audio_mem_asrc1", "asm_h_sel", 0x634, 10),
+ GATE(CLK_AUDIO_MEM_ASRC2, "audio_mem_asrc2", "asm_h_sel", 0x634, 11),
+ GATE(CLK_AUDIO_MEM_ASRC3, "audio_mem_asrc3", "asm_h_sel", 0x634, 12),
+ GATE(CLK_AUDIO_MEM_ASRC4, "audio_mem_asrc4", "asm_h_sel", 0x634, 13),
+ GATE(CLK_AUDIO_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 0x634, 14),
+};
+
+static struct mdtk_clk_def clk_def = {
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+};
+
+static int
+audio_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+audio_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek mt7622 audio clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+audio_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (ofw_bus_is_compatible(dev, "syscon")) {
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev,
+ "Cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ sc->syscon = syscon_create_ofw_node(dev,
+ &syscon_class, ofw_bus_get_node(dev));
+ if (sc->syscon == NULL) {
+ device_printf(dev,
+ "Failed to create/register syscon\n");
+ return (ENXIO);
+ }
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+}
+
+static int
+audio_clk_hwreset_assert(device_t dev, intptr_t idx, bool value) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ uint32_t mask, reset_reg;
+
+ CLKDEV_DEVICE_LOCK(sc->dev);
+ KASSERT((idx > 0 && idx < 32), ("%s: idx out of range", __func__));
+
+
+ mask = 1 << (idx % 32);
+ reset_reg = (idx / 32) * 4;
+
+ CLKDEV_MODIFY_4(sc->dev, reset_reg, mask, value ? mask : 0);
+ CLKDEV_DEVICE_UNLOCK(sc->dev);
+
+ return (0);
+}
+
+static int
+audio_clk_syscon_get_handle(device_t dev, struct syscon **syscon) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *syscon = sc->syscon;
+ if (*syscon == NULL) {
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+audio_clk_syscon_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+audio_clk_syscon_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t mt7622_audio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, audio_clk_probe),
+ DEVMETHOD(device_attach, audio_clk_attach),
+ DEVMETHOD(device_detach, audio_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD(hwreset_assert, audio_clk_hwreset_assert),
+
+ /* Syscon interface */
+ DEVMETHOD(syscon_get_handle, audio_clk_syscon_get_handle),
+ DEVMETHOD(syscon_device_lock, audio_clk_syscon_lock),
+ DEVMETHOD(syscon_device_unlock, audio_clk_syscon_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mt7622_audio, mt7622_audio_driver, mt7622_audio_methods,
+sizeof(struct mdtk_clk_softc), syscon_class);
+
+EARLY_DRIVER_MODULE(mt7622_audio, simplebus, mt7622_audio_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 4);
diff --git a/sys/arm64/mediatek/mt7622_clk_eth.c b/sys/arm64/mediatek/mt7622_clk_eth.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_eth.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+#include <dt-bindings/clock/mt7622-clk.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/hwreset/hwreset.h>
+#include "syscon_if.h"
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-ethsys", 1},
+ {NULL, 0},
+};
+
+static struct clk_gate_def gates_clk[] = {
+ /* eth */
+ GATE(CLK_ETH_HSDMA_EN, "eth_hsdma_en", "eth_sel", 0x30, 5),
+ GATE(CLK_ETH_ESW_EN, "eth_esw_en", "eth_500m", 0x30, 6),
+ GATE(CLK_ETH_GP2_EN, "eth_gp2_en", "txclk_src_pre", 0x30, 7),
+ GATE(CLK_ETH_GP1_EN, "eth_gp1_en", "txclk_src_pre", 0x30, 8),
+ GATE(CLK_ETH_GP0_EN, "eth_gp0_en", "txclk_src_pre", 0x30, 9),
+};
+
+static struct mdtk_clk_def clk_def = {
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+};
+
+static int
+eth_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+eth_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek mt7622 ethernet clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+eth_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (ofw_bus_is_compatible(dev, "syscon")) {
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev,
+ "Cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ sc->syscon = syscon_create_ofw_node(dev,
+ &syscon_class, ofw_bus_get_node(dev));
+ if (sc->syscon == NULL) {
+ device_printf(dev,
+ "Failed to create/register syscon\n");
+ return (ENXIO);
+ }
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+}
+
+static int
+eth_clk_syscon_get_handle(device_t dev, struct syscon **syscon) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *syscon = sc->syscon;
+ if (*syscon == NULL) {
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+eth_clk_syscon_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+eth_clk_syscon_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t mt7622_eth_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, eth_clk_probe),
+ DEVMETHOD(device_attach, eth_clk_attach),
+ DEVMETHOD(device_detach, eth_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ /* Syscon interface */
+ DEVMETHOD(syscon_get_handle, eth_clk_syscon_get_handle),
+ DEVMETHOD(syscon_device_lock, eth_clk_syscon_lock),
+ DEVMETHOD(syscon_device_unlock, eth_clk_syscon_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mt7622_eth, mt7622_eth_driver, mt7622_eth_methods,
+sizeof(struct mdtk_clk_softc), syscon_class);
+
+EARLY_DRIVER_MODULE(mt7622_eth, simplebus, mt7622_eth_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 5);
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mt7622_clk_infracfg.c b/sys/arm64/mediatek/mt7622_clk_infracfg.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_infracfg.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+#include <dt-bindings/clock/mt7622-clk.h>
+#include <dev/clk/clk_mux.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/hwreset/hwreset.h>
+#include "syscon_if.h"
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-infracfg", 1},
+ {NULL, 0},
+};
+
+PLIST(infra_mux1_parents) = {
+ "clkxtal",
+ "armpll",
+ //"main_core_en",
+ "armpll"
+};
+
+static struct clk_gate_def gates_clk[] = {
+ GATE(CLK_INFRA_DBGCLK_PD, "infra_dbgclk_pd", "axi_sel", 0x44, 0),
+ GATE(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 0x44, 2),
+ GATE(CLK_INFRA_AUDIO_PD, "infra_audio_pd", "aud_intbus_sel", 0x44, 5),
+ //GATE(CLK_INFRA_IRRX_PD, "infra_irrx_pd", "irrx_sel", 0x44, 16),
+ GATE(CLK_INFRA_APXGPT_PD, "infra_apxgpt_pd", "f10m_ref_sel", 0x44, 18),
+ GATE(CLK_INFRA_PMIC_PD, "infra_pmic_pd", "pmicspi_sel", 0x44, 22),
+};
+
+static struct clk_mux_def muxes_clk[] = {
+ MUX0(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents, 0x000, 2, 2),
+};
+
+static struct mdtk_clk_def clk_def = {
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+ .muxes_def = muxes_clk,
+ .num_muxes = nitems(muxes_clk),
+};
+
+static int
+infracfg_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+infracfg_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek infracfg clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+infracfg_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (ofw_bus_is_compatible(dev, "syscon")) {
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev,
+ "Cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ sc->syscon = syscon_create_ofw_node(dev,
+ &syscon_class, ofw_bus_get_node(dev));
+ if (sc->syscon == NULL) {
+ device_printf(dev,
+ "Failed to create/register syscon\n");
+ return (ENXIO);
+ }
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+}
+
+static int
+infracfg_clk_hwreset_assert(device_t dev, intptr_t idx, bool value) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ uint32_t mask, reset_reg;
+
+ CLKDEV_DEVICE_LOCK(sc->dev);
+ KASSERT((idx > 0 && idx < 32), ("%s: idx out of range", __func__));
+
+
+ mask = 1 << (idx % 32);
+ reset_reg = (idx / 32) * 4;
+
+ CLKDEV_MODIFY_4(sc->dev, reset_reg, mask, value ? mask : 0);
+ CLKDEV_DEVICE_UNLOCK(sc->dev);
+
+ return (0);
+}
+
+static int
+infracfg_clk_syscon_get_handle(device_t dev, struct syscon **syscon) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *syscon = sc->syscon;
+ if (*syscon == NULL) {
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+infracfg_clk_syscon_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+infracfg_clk_syscon_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t mt7622_infracfg_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, infracfg_clk_probe),
+ DEVMETHOD(device_attach, infracfg_clk_attach),
+ DEVMETHOD(device_detach, infracfg_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD(hwreset_assert, infracfg_clk_hwreset_assert),
+
+ /* Syscon interface */
+ DEVMETHOD(syscon_get_handle, infracfg_clk_syscon_get_handle),
+ DEVMETHOD(syscon_device_lock, infracfg_clk_syscon_lock),
+ DEVMETHOD(syscon_device_unlock, infracfg_clk_syscon_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mt7622_infracfg, mt7622_infracfg_driver, mt7622_infracfg_methods,
+sizeof(struct mdtk_clk_softc), syscon_class);
+
+EARLY_DRIVER_MODULE(mt7622_infracfg, simplebus, mt7622_infracfg_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 4);
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mt7622_clk_pciesys.c b/sys/arm64/mediatek/mt7622_clk_pciesys.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_pciesys.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.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/mt7622-clk.h>
+
+#include <dev/clk/clk_fixed.h>
+#include <dev/clk/clk_div.h>
+#include <dev/clk/clk_mux.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/clk/clk_link.h>
+#include <arm64/mediatek/mdtk_clk.h>
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-pciesys", 1},
+ {NULL, 0},
+};
+
+static struct clk_gate_def gates_pcie_clk[] = {
+ GATE(CLK_PCIE_P1_AUX_EN, "pcie_p1_aux_en", "p1_1mhz", 0x30, 12),
+ GATE(CLK_PCIE_P1_OBFF_EN, "pcie_p1_obff_en", "free_run_4mhz", 0x30, 13),
+ GATE(CLK_PCIE_P1_AHB_EN, "pcie_p1_ahb_en", "axi_sel", 0x30, 14),
+ GATE(CLK_PCIE_P1_AXI_EN, "pcie_p1_axi_en", "hif_sel", 0x30, 15),
+ GATE(CLK_PCIE_P1_MAC_EN, "pcie_p1_mac_en", "pcie1_mac_en", 0x30, 16),
+ GATE(CLK_PCIE_P1_PIPE_EN, "pcie_p1_pipe_en", "pcie1_pipe_en", 0x30, 17),
+ GATE(CLK_PCIE_P0_AUX_EN, "pcie_p0_aux_en", "p0_1mhz", 0x30, 18),
+ GATE(CLK_PCIE_P0_OBFF_EN, "pcie_p0_obff_en", "free_run_4mhz", 0x30, 19),
+ GATE(CLK_PCIE_P0_AHB_EN, "pcie_p0_ahb_en", "axi_sel", 0x30, 20),
+ GATE(CLK_PCIE_P0_AXI_EN, "pcie_p0_axi_en", "hif_sel", 0x30, 21),
+ GATE(CLK_PCIE_P0_MAC_EN, "pcie_p0_mac_en", "pcie0_mac_en", 0x30, 22),
+ GATE(CLK_PCIE_P0_PIPE_EN, "pcie_p0_pipe_en", "pcie0_pipe_en", 0x30, 23),
+ GATE(CLK_SATA_AHB_EN, "sata_ahb_en", "axi_sel", 0x30, 26),
+ GATE(CLK_SATA_AXI_EN, "sata_axi_en", "hif_sel", 0x30, 27),
+ GATE(CLK_SATA_ASIC_EN, "sata_asic_en", "sata_asic", 0x30, 28),
+ GATE(CLK_SATA_RBC_EN, "sata_rbc_en", "sata_rbc", 0x30, 29),
+ GATE(CLK_SATA_PM_EN, "sata_pm_en", "univpll2_d4", 0x30, 30),
+};
+
+static struct mdtk_clk_def clk_pcie_def = {
+ .linked_def = NULL,
+ .num_linked = 0,
+ .fixed_def = NULL,
+ .num_fixed = 0,
+ .gates_def = gates_pcie_clk,
+ .num_gates = nitems(gates_pcie_clk),
+ .muxes_def = NULL,
+ .num_muxes = 0,
+};
+
+static int
+mt7622_pciesys_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+mt7622_pciesys_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek mt7622 pciesys clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+mt7622_pciesys_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc;
+ sc = device_get_softc(dev);
+ int rid;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ mdtk_register_clocks(dev, &clk_pcie_def);
+
+ return (0);
+}
+
+static int
+mt7622_pciesys_clk_hwreset_assert(device_t dev, intptr_t idx, bool value) {
+ struct mdtk_clk_softc *sc;
+ sc = device_get_softc(dev);
+ uint32_t mask, reset_reg;
+
+ CLKDEV_DEVICE_LOCK(sc->dev);
+ KASSERT((idx > 0 && idx < 32), ("%s: idx out of range", __func__));
+
+
+ mask = 1 << (idx % 32);
+ reset_reg = (idx / 32) * 4;
+
+ CLKDEV_MODIFY_4(sc->dev, reset_reg, mask, value ? mask : 0);
+ CLKDEV_DEVICE_UNLOCK(sc->dev);
+
+ return (0);
+}
+
+static device_method_t mt7622_pciesys_clk_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mt7622_pciesys_clk_probe),
+ DEVMETHOD(device_attach, mt7622_pciesys_clk_attach),
+ DEVMETHOD(device_detach, mt7622_pciesys_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD(hwreset_assert, mt7622_pciesys_clk_hwreset_assert),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(mt7622_pciesys, mt7622_pciesys_driver, mt7622_pciesys_clk_methods,
+sizeof(struct mdtk_clk_softc));
+
+EARLY_DRIVER_MODULE(mt7622_pciesys, simplebus, mt7622_pciesys_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 5);
diff --git a/sys/arm64/mediatek/mt7622_clk_pericfg.c b/sys/arm64/mediatek/mt7622_clk_pericfg.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_pericfg.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+#include <dt-bindings/clock/mt7622-clk.h>
+#include <dev/clk/clk_mux.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/hwreset/hwreset.h>
+#include "syscon_if.h"
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+#define PERICFG_CG0 0x10
+#define PERICFG_CG1 0x14
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-pericfg", 1},
+ {NULL, 0},
+};
+
+PLIST(peribus_ck_parents) = {
+ "syspll1_d8",
+ "syspll1_d4"
+};
+
+static struct clk_gate_def gates_clk[] = {
+ GATE(CLK_PERI_THERM_PD, "peri_therm_pd", "axi_sel", PERICFG_CG0, 1),
+ GATE(CLK_PERI_PWM1_PD, "peri_pwm1_pd", "clkxtal", PERICFG_CG0, 2),
+ GATE(CLK_PERI_PWM2_PD, "peri_pwm2_pd", "clkxtal", PERICFG_CG0, 3),
+ GATE(CLK_PERI_PWM3_PD, "peri_pwm3_pd", "clkxtal", PERICFG_CG0, 4),
+ GATE(CLK_PERI_PWM4_PD, "peri_pwm4_pd", "clkxtal", PERICFG_CG0, 5),
+ GATE(CLK_PERI_PWM5_PD, "peri_pwm5_pd", "clkxtal", PERICFG_CG0, 6),
+ GATE(CLK_PERI_PWM6_PD, "peri_pwm6_pd", "clkxtal", PERICFG_CG0, 7),
+ GATE(CLK_PERI_PWM7_PD, "peri_pwm7_pd", "clkxtal", PERICFG_CG0, 8),
+ GATE(CLK_PERI_PWM_PD, "peri_pwm_pd", "clkxtal", PERICFG_CG0, 9),
+ GATE(CLK_PERI_AP_DMA_PD, "peri_ap_dma_pd", "axi_sel", PERICFG_CG0, 12),
+ GATE(CLK_PERI_MSDC30_0_PD, "peri_msdc30_0", "msdc30_0_sel", PERICFG_CG0, 13),
+ GATE(CLK_PERI_MSDC30_1_PD, "peri_msdc30_1", "msdc30_1_sel", PERICFG_CG0, 14),
+ GATE(CLK_PERI_UART0_PD, "peri_uart0_pd", "axi_sel", PERICFG_CG0, 17),
+ GATE(CLK_PERI_UART1_PD, "peri_uart1_pd", "axi_sel", PERICFG_CG0, 18),
+ GATE(CLK_PERI_UART2_PD, "peri_uart2_pd", "axi_sel", PERICFG_CG0, 19),
+ GATE(CLK_PERI_UART3_PD, "peri_uart3_pd", "axi_sel", PERICFG_CG0, 20),
+ GATE(CLK_PERI_UART4_PD, "peri_uart4_pd", "axi_sel", PERICFG_CG0, 21),
+ GATE(CLK_PERI_BTIF_PD, "peri_btif_pd", "axi_sel", PERICFG_CG0, 22),
+ GATE(CLK_PERI_I2C0_PD, "peri_i2c0_pd", "axi_sel", PERICFG_CG0, 23),
+ GATE(CLK_PERI_I2C1_PD, "peri_i2c1_pd", "axi_sel", PERICFG_CG0, 24),
+ GATE(CLK_PERI_I2C2_PD, "peri_i2c2_pd", "axi_sel", PERICFG_CG0, 25),
+ GATE(CLK_PERI_SPI1_PD, "peri_spi1_pd", "spi1_sel", PERICFG_CG0, 26),
+ GATE(CLK_PERI_AUXADC_PD, "peri_auxadc_pd", "clkxtal", PERICFG_CG0, 27),
+ GATE(CLK_PERI_SPI0_PD, "peri_spi0_pd", "spi0_sel", PERICFG_CG0, 28),
+ GATE(CLK_PERI_SNFI_PD, "peri_snfi_pd", "spinfi_infra_bclk_sel", PERICFG_CG0, 29),
+ GATE(CLK_PERI_NFI_PD, "peri_nfi_pd", "axi_sel", PERICFG_CG0, 30),
+ GATE(CLK_PERI_NFIECC_PD, "peri_nfiecc_pd", "axi_sel", PERICFG_CG0, 31),
+
+ GATE(CLK_PERI_FLASH_PD, "peri_flash_pd", "flash_sel", PERICFG_CG1, 1),
+ GATE(CLK_PERI_IRTX_PD, "peri_irtx_pd", "irtx_sel", PERICFG_CG1, 2),
+};
+
+static struct clk_mux_def muxes_clk[] = {
+ MUX0(0, "peribus_ck_sel_mux", peribus_ck_parents, 0x05C, 0, 1),
+};
+
+
+static struct mdtk_clk_def clk_def = {
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+ .muxes_def = muxes_clk,
+ .num_muxes = nitems(muxes_clk),
+};
+
+static int
+pericfg_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+pericfg_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek pericfg clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+pericfg_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ sc->dev = dev;
+
+ if (ofw_bus_is_compatible(dev, "syscon")) {
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev,
+ "Cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+ sc->syscon = syscon_create_ofw_node(dev,
+ &syscon_class, ofw_bus_get_node(dev));
+ if (sc->syscon == NULL) {
+ device_printf(dev,
+ "Failed to create/register syscon\n");
+ return (ENXIO);
+ }
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+}
+
+static int
+pericfg_clk_hwreset_assert(device_t dev, intptr_t idx, bool value) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ uint32_t mask, reset_reg;
+
+ CLKDEV_DEVICE_LOCK(sc->dev);
+ KASSERT((idx > 0 && idx < 32), ("%s: idx out of range", __func__));
+
+
+ mask = 1 << (idx % 32);
+ reset_reg = (idx / 32) * 4;
+
+ CLKDEV_MODIFY_4(sc->dev, reset_reg, mask, value ? mask : 0);
+ CLKDEV_DEVICE_UNLOCK(sc->dev);
+
+ return (0);
+}
+
+static int
+pericfg_clk_syscon_get_handle(device_t dev, struct syscon **syscon) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *syscon = sc->syscon;
+ if (*syscon == NULL) {
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+pericfg_clk_syscon_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+pericfg_clk_syscon_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t mdtk_mt7622_pericfg_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pericfg_clk_probe),
+ DEVMETHOD(device_attach, pericfg_clk_attach),
+ DEVMETHOD(device_detach, pericfg_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD(hwreset_assert, pericfg_clk_hwreset_assert),
+
+ /* Syscon interface */
+ DEVMETHOD(syscon_get_handle, pericfg_clk_syscon_get_handle),
+ DEVMETHOD(syscon_device_lock, pericfg_clk_syscon_lock),
+ DEVMETHOD(syscon_device_unlock, pericfg_clk_syscon_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mdtk_mt7622_pericfg, mdtk_mt7622_pericfg_driver, mdtk_mt7622_pericfg_methods,
+sizeof(struct mdtk_clk_softc), syscon_class);
+
+EARLY_DRIVER_MODULE(mdtk_mt7622_pericfg, simplebus, mdtk_mt7622_pericfg_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 3);
+
diff --git a/sys/arm64/mediatek/mt7622_clk_sgmii.c b/sys/arm64/mediatek/mt7622_clk_sgmii.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_sgmii.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/syscon/syscon.h>
+#include <dt-bindings/clock/mt7622-clk.h>
+#include <dev/clk/clk_gate.h>
+#include "syscon_if.h"
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-sgmiisys", 1},
+ {NULL, 0},
+};
+
+static struct clk_gate_def gates_clk[] = {
+ /* sgmii */
+ GATE(CLK_SGMII_TX250M_EN, "sgmii_tx250m_en", "ssusb_tx250m", 0xE4, 2),
+ GATE(CLK_SGMII_RX250M_EN, "sgmii_rx250m_en", "ssusb_eq_rx250m", 0xE4, 3),
+ GATE(CLK_SGMII_CDR_REF, "sgmii_cdr_ref", "ssusb_cdr_ref", 0xE4, 4),
+ GATE(CLK_SGMII_CDR_FB, "sgmii_cdr_fb", "ssusb_cdr_fb", 0xE4, 5),
+};
+
+static struct mdtk_clk_def clk_def = {
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+};
+
+static int
+sgmii_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+sgmii_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek mt7622 sgmii clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+sgmii_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (ofw_bus_is_compatible(dev, "syscon")) {
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev,
+ "Cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ sc->syscon = syscon_create_ofw_node(dev,
+ &syscon_class, ofw_bus_get_node(dev));
+ if (sc->syscon == NULL) {
+ device_printf(dev,
+ "Failed to create/register syscon\n");
+ return (ENXIO);
+ }
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+}
+
+static int
+sgmii_clk_syscon_get_handle(device_t dev, struct syscon **syscon) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ *syscon = sc->syscon;
+ if (*syscon == NULL) {
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+sgmii_clk_syscon_lock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+sgmii_clk_syscon_unlock(device_t dev) {
+ struct mdtk_clk_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static device_method_t mt7622_sgmii_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, sgmii_clk_probe),
+ DEVMETHOD(device_attach, sgmii_clk_attach),
+ DEVMETHOD(device_detach, sgmii_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ /* Syscon interface */
+ DEVMETHOD(syscon_get_handle, sgmii_clk_syscon_get_handle),
+ DEVMETHOD(syscon_device_lock, sgmii_clk_syscon_lock),
+ DEVMETHOD(syscon_device_unlock, sgmii_clk_syscon_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(mt7622_sgmii, mt7622_sgmii_driver, mt7622_sgmii_methods,
+sizeof(struct mdtk_clk_softc), syscon_class);
+
+EARLY_DRIVER_MODULE(mt7622_sgmii, simplebus, mt7622_sgmii_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 5);
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mt7622_clk_ssusbsys.c b/sys/arm64/mediatek/mt7622_clk_ssusbsys.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_ssusbsys.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.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/mt7622-clk.h>
+#include <dt-bindings/reset/mt7622-reset.h>
+#include <dev/clk/clk_gate.h>
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "mdtk_clk.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-ssusbsys", 2},
+ {NULL, 0},
+};
+
+static struct clk_gate_def gates_ssusb_clk[] = {
+ GATE(CLK_SSUSB_U2_PHY_1P_EN, "ssusb_u2_phy_1p", "to_u2_phy_1p", 0x30, 0),
+ GATE(CLK_SSUSB_U2_PHY_EN, "ssusb_u2_phy_en", "to_u2_phy", 0x30, 1),
+ GATE(CLK_SSUSB_REF_EN, "ssusb_ref_en", "to_usb3_ref", 0x30, 5),
+ GATE(CLK_SSUSB_SYS_EN, "ssusb_sys_en", "to_usb3_sys", 0x30, 6),
+ GATE(CLK_SSUSB_MCU_EN, "ssusb_mcu_en", "axi_sel", 0x30, 7),
+ GATE(CLK_SSUSB_DMA_EN, "ssusb_dma_en", "hif_sel", 0x30, 8),
+};
+
+static struct mdtk_clk_def clk_ssusb_def = {
+ .gates_def = gates_ssusb_clk,
+ .num_gates = nitems(gates_ssusb_clk),
+};
+
+static int
+mt7622_ssusbsys_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+mt7622_ssusbsys_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek mt7622 ssusbsys clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+mt7622_ssusbsys_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "cannot allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ mdtk_register_clocks(dev, &clk_ssusb_def);
+
+ return (0);
+}
+
+static int
+mt7622_ssusbsys_clk_hwreset_assert(device_t dev, intptr_t id, bool value) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+
+ return (mdtk_hwreset_by_idx(sc, id, value));
+}
+
+static device_method_t mt7622_ssusbsys_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mt7622_ssusbsys_clk_probe),
+ DEVMETHOD(device_attach, mt7622_ssusbsys_clk_attach),
+ DEVMETHOD(device_detach, mt7622_ssusbsys_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD(hwreset_assert, mt7622_ssusbsys_clk_hwreset_assert),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(mt7622_ssusbsys, mt7622_ssusbsys_driver, mt7622_ssusbsys_methods,
+sizeof(struct mdtk_clk_softc));
+
+EARLY_DRIVER_MODULE(mt7622_ssusbsys, simplebus, mt7622_ssusbsys_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 5);
diff --git a/sys/arm64/mediatek/mt7622_clk_topckgen.c b/sys/arm64/mediatek/mt7622_clk_topckgen.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt7622_clk_topckgen.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.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/mt7622-clk.h>
+#include <dev/clk/clk_fixed.h>
+#include <dev/clk/clk_div.h>
+#include <dev/clk/clk_mux.h>
+#include <dev/clk/clk_gate.h>
+#include <dev/clk/clk_link.h>
+#include <arm64/mediatek/mdtk_clk.h>
+#include <dev/hwreset/hwreset.h>
+#include "clkdev_if.h"
+
+#define CLK_CFG_0 0x040
+#define CLK_CFG_1 0x050
+#define CLK_CFG_2 0x060
+#define CLK_CFG_3 0x070
+#define CLK_CFG_4 0x080
+#define CLK_CFG_5 0x090
+#define CLK_CFG_6 0x0A0
+#define CLK_CFG_7 0x0B0
+#define CLK_AUDDIV_0 0x120
+
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt7622-topckgen", 1},
+ {NULL, 0},
+};
+
+/* Parent lists */
+PLIST(eth_ck_parents) = {
+ "clkxtal",
+ "syspll1_d2",
+ "univpll1_d2",
+ "syspll1_d4",
+ "univpll_d5",
+ "sgmiipll_d2",
+ "univpll_d7",
+ "dmpll_ck"};
+
+PLIST(ddrphycfg_ck_parents) = {
+ "clkxtal",
+ "syspll1_d8"
+};
+
+PLIST(mem_ck_parents) = {
+ "clkxtal",
+ "dmpll_ck"
+};
+
+PLIST(axi_ck_parents) = {
+ "clkxtal",
+ "syspll1_d2",
+ "syspll_d5",
+ "syspll1_d4",
+ "univpll_d5",
+ "univpll2_d2",
+ "univpll_d7",
+ "dmpll_ck"
+};
+
+PLIST(pwm_ck_parents) = {
+ "clkxtal",
+ "univpll2_d4",
+ "univpll3_d2",
+ "univpll1_d4"
+};
+
+PLIST(f10m_ref_ck_parents) = {
+ "clkxtal",
+ "syspll4_d16"
+};
+
+PLIST(nfi_infra_ck_parents) = {
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "clkxtal",
+ "univpll2_d8",
+ "syspll1_d8",
+ "univpll1_d8",
+ "syspll4_d2",
+ "univpll2_d4",
+ "univpll3_d2",
+ "syspll1_d4",
+ "syspll_d7"
+};
+
+PLIST(flash_ck_parents) = {
+ "clkxtal",
+ "univpll_div80_d4",
+ "syspll2_d8",
+ "syspll3_d4",
+ "univpll3_d4",
+ "univpll1_d8",
+ "syspll2_d4",
+ "univpll2_d4"
+};
+
+PLIST(uart_ck_parents) = {
+ "clkxtal",
+ "univpll2_d8"
+};
+
+PLIST(spi0_ck_parents) = {
+ "clkxtal",
+ "syspll3_d2",
+ "clkxtal",
+ "syspll2_d4",
+ "syspll4_d2",
+ "univpll2_d4",
+ "univpll1_d8",
+ "clkxtal"
+};
+
+PLIST(spi1_ck_parents) = {
+ "clkxtal",
+ "syspll3_d2",
+ "clkxtal",
+ "syspll2_d4",
+ "syspll4_d2",
+ "univpll2_d4",
+ "univpll1_d8",
+ "clkxtal"
+};
+
+PLIST(msdc50_0_ck_parents) = {
+ "clkxtal",
+ "univpll2_d8",
+ "univpll2_d4",
+ "syspll_d7",
+ "univpll2_d2",
+ "univpll_d5",
+ "univpll1_d2",
+ "univpll_d3"
+};
+
+PLIST(msdc30_0_ck_parents) = {
+ "clkxtal",
+ "univpll2_d16",
+ "univ48m_ck",
+ "syspll2_d4",
+ "univpll2_d4",
+ "syspll_d7",
+ "syspll2_d2",
+ "univpll2_d2"
+};
+
+PLIST(msdc30_1_ck_parents) = {
+ "clkxtal",
+ "univpll2_d16",
+ "univ48m_ck",
+ "syspll2_d4",
+ "univpll2_d4",
+ "syspll_d7",
+ "syspll2_d2",
+ "univpll2_d2"
+};
+
+PLIST(a1sys_hp_ck_parents) = {
+ "clkxtal",
+ "aud1pll_ck",
+ "aud2pll_ck",
+ "clkxtal"
+};
+
+PLIST(a2sys_hp_ck_parents) = {
+ "clkxtal",
+ "aud1pll_ck",
+ "aud2pll_ck",
+ "clkxtal"
+};
+
+PLIST(intdir_ck_parents) = {
+ "clkxtal",
+ "syspll_d2",
+ "univpll_d2",
+ "sgmiipll_ck"
+};
+
+PLIST(aud_intbus_ck_parents) = {
+ "clkxtal",
+ "syspll1_d4",
+ "syspll4_d2",
+ "syspll3_d2"
+};
+
+PLIST(pmicspi_ck_parents) = {
+ "clkxtal",
+ "syspll1_d8",
+ "syspll3_d4",
+ "syspll1_d16",
+ "univpll3_d4",
+ "univpll2_d16",
+ "dmpll_d8"
+};
+
+PLIST(scp_ck_parents) = {
+ "clkxtal",
+ "syspll1_d8",
+ "univpll2_d2",
+ "univpll2_d4"
+};
+
+PLIST(atb_ck_parents) = {
+ "clkxtal",
+ "syspll1_d2",
+ "syspll_d5",
+ "dmpll_ck"
+};
+
+PLIST(hif_ck_parents) = {
+ "clkxtal",
+ "syspll1_d2",
+ "univpll1_d2",
+ "syspll1_d4",
+ "univpll_d5",
+ "sgmiipll_d2",
+ "univpll_d7",
+ "dmpll_ck"
+};
+
+PLIST(audio_ck_parents) = {
+ "clkxtal",
+ "syspll3_d4",
+ "syspll4_d4",
+ "univpll1_d16"
+};
+
+PLIST(usb20_ck_parents) = {
+ "clkxtal",
+ "univpll3_d4",
+ "syspll1_d8",
+ "clkxtal"
+};
+
+PLIST(aud1_ck_parents) = {
+ "clkxtal",
+ "aud1pll_ck"
+};
+
+PLIST(aud2_ck_parents) = {
+ "clkxtal",
+ "aud2pll_ck"
+};
+
+PLIST(irrx_ck_parents) = {
+ "clkxtal",
+ "syspll4_d16"
+};
+
+PLIST(irtx_ck_parents) = {
+ "clkxtal",
+ "syspll4_d16"
+};
+
+PLIST(asm_l_ck_parents) = {
+ "clkxtal",
+ "syspll_d5",
+ "univpll2_d2",
+ "univpll2_d4"
+};
+
+PLIST(asm_m_ck_parents) = {
+ "clkxtal",
+ "syspll_d5",
+ "univpll2_d2",
+ "univpll2_d4"
+};
+
+PLIST(asm_h_ck_parents) = {
+ "clkxtal",
+ "syspll_d5",
+ "univpll2_d2",
+ "univpll2_d4"
+};
+
+PLIST(apll_ck_parents) = {
+ "aud1_sel",
+ "aud2_sel"
+};
+
+PLIST(apll2_ck_parents) = {
+ "aud2_sel",
+ "aud1_sel"
+};
+
+static struct clk_fixed_def fixed_clk[] = {
+ FRATE(CLK_TOP_TO_U2_PHY, "to_u2_phy", 31250000),
+ FRATE(CLK_TOP_TO_U2_PHY_1P, "to_u2_phy_1p", 31250000),
+ FRATE(CLK_TOP_PCIE0_PIPE_EN, "pcie0_pipe_en", 125000000),
+ FRATE(CLK_TOP_PCIE1_PIPE_EN, "pcie1_pipe_en", 125000000),
+ FRATE(CLK_TOP_SSUSB_TX250M, "ssusb_tx250m", 250000000),
+ FRATE(CLK_TOP_SSUSB_EQ_RX250M, "ssusb_eq_rx250m", 250000000),
+ FRATE(CLK_TOP_SSUSB_CDR_REF, "ssusb_cdr_ref", 33333333),
+ FRATE(CLK_TOP_SSUSB_CDR_FB, "ssusb_cdr_fb", 50000000),
+ FRATE(CLK_TOP_SATA_ASIC, "sata_asic", 50000000),
+ FRATE(CLK_TOP_SATA_RBC, "sata_rbc", 50000000),
+ FRATE(CLK_APMIXED_ARMPLL, "armpll", 120000000ULL),
+ FRATE(CLK_APMIXED_MAINPLL, "mainpll", 1120000000ULL),
+ FRATE(CLK_APMIXED_UNIV2PLL, "univ2pll", 2400000000ULL),
+ FRATE(CLK_APMIXED_ETH1PLL, "eth1pll", 500000000ULL),
+ FRATE(CLK_APMIXED_ETH2PLL, "eth2pll", 650000000ULL),
+ FRATE(CLK_APMIXED_AUD1PLL, "aud1pll", 147456000ULL),
+ FRATE(CLK_APMIXED_AUD2PLL, "aud2pll", 135475000ULL),
+ FRATE(CLK_APMIXED_TRGPLL, "trgpll", 725000000ULL),
+ FRATE(CLK_APMIXED_SGMIPLL, "sgmipll", 650000000ULL),
+
+ FFACT(CLK_TOP_TO_USB3_SYS, "to_usb3_sys", "eth1pll", 1, 4),
+ FFACT(CLK_TOP_P1_1MHZ, "p1_1mhz", "eth1pll", 1, 500),
+ FFACT(CLK_TOP_4MHZ, "free_run_4mhz", "eth1pll", 1, 125),
+ FFACT(CLK_TOP_P0_1MHZ, "p0_1mhz", "eth1pll", 1, 500),
+ FFACT(CLK_TOP_TXCLK_SRC_PRE, "txclk_src_pre", "sgmiipll_d2", 1, 1),
+ FFACT(CLK_TOP_RTC, "rtc", "clkxtal", 1, 1024),
+ FFACT(CLK_TOP_MEMPLL, "mempll", "clkxtal", 32, 1),
+ FFACT(CLK_TOP_DMPLL, "dmpll_ck", "mempll", 1, 1),
+ FFACT(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
+ FFACT(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 4),
+ FFACT(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 8),
+ FFACT(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 16),
+ FFACT(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 12),
+ FFACT(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "mainpll", 1, 24),
+ FFACT(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
+ FFACT(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 10),
+ FFACT(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 20),
+ FFACT(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 14),
+ FFACT(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 28),
+ FFACT(CLK_TOP_SYSPLL4_D16, "syspll4_d16", "mainpll", 1, 112),
+ FFACT(CLK_TOP_UNIVPLL, "univpll", "univ2pll", 1, 2),
+ FFACT(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
+ FFACT(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 4),
+ FFACT(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 8),
+ FFACT(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 16),
+ FFACT(CLK_TOP_UNIVPLL1_D16, "univpll1_d16", "univpll", 1, 32),
+ FFACT(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 6),
+ FFACT(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 12),
+ FFACT(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 24),
+ FFACT(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll", 1, 48),
+ FFACT(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
+ FFACT(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 10),
+ FFACT(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 20),
+ FFACT(CLK_TOP_UNIVPLL3_D16, "univpll3_d16", "univpll", 1, 80),
+ FFACT(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
+ FFACT(CLK_TOP_UNIVPLL_D80_D4, "univpll_div80_d4", "univpll", 1, 320),
+ FFACT(CLK_TOP_SGMIIPLL, "sgmiipll_ck", "sgmipll", 1, 1),
+ FFACT(CLK_TOP_SGMIIPLL_D2, "sgmiipll_d2", "sgmipll", 1, 2),
+
+ FFACT(/*CLK_TOP_SYSPLL_D7*/ 0, "syspll_d7", "mainpll", 1, 8),
+ FFACT(/*CLK_TOP_SYSPLL2_D2 */0, "syspll2_d2", "mainpll", 1, 6),
+ FFACT(/*CLK_TOP_UNIVPLL_D3*/ 0, "univpll_d3", "univpll", 1, 3),
+ FFACT(/*CLK_TOP_SYSPLL1_D16*/ 0, "syspll1_d16", "syspll_d2", 1, 16),
+ FFACT(/*CLK_TOP_DMPLL_D8*/ 0, "dmpll_d8", "dmpll_ck", 1, 8),
+ FFACT(CLK_TOP_AUD1PLL, "aud1pll_ck", "aud1pll", 1, 1),
+ FFACT(CLK_TOP_AUD2PLL, "aud2pll_ck", "aud2pll", 1, 1),
+ FFACT(CLK_TOP_UNIV48M, "univ48m_ck", "univpll", 1, 25),
+ FFACT(CLK_TOP_TO_USB3_REF, "to_usb3_ref", "univpll2_d4", 1, 4),
+ FFACT(CLK_TOP_PCIE1_MAC_EN, "pcie1_mac_en", "univpll1_d4", 1, 1),
+ FFACT(CLK_TOP_PCIE0_MAC_EN, "pcie0_mac_en", "univpll1_d4", 1, 1),
+ FFACT(CLK_TOP_ETH_500M, "eth_500m", "eth1pll", 1, 1),
+ FFACT(CLK_TOP_AUD_I2S2_MCK, "aud_i2s2_mck", "i2s2_mck_sel", 1, 2),
+};
+
+static struct clk_gate_def gates_clk[] = {
+ I_GATE(CLK_TOP_ETH_SEL, "eth_sel", "eth_sel_mux", CLK_CFG_0, 31),
+ I_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", "ddrphycfg_sel_mux", CLK_CFG_0, 23),
+ I_GATE(CLK_TOP_MEM_SEL, "mem_sel", "mem_sel_mux", CLK_CFG_0, 15),
+ I_GATE(CLK_TOP_AXI_SEL, "axi_sel", "axi_sel_mux", CLK_CFG_0, 7),
+
+ I_GATE(CLK_TOP_PWM_SEL, "pwm_sel", "pwm_sel_mux", CLK_CFG_1, 7),
+ I_GATE(CLK_TOP_F10M_REF_SEL, "f10m_ref_sel", "f10m_ref_sel_mux", CLK_CFG_1, 15),
+ I_GATE(CLK_TOP_NFI_INFRA_SEL, "spinfi_infra_bclk_sel", "spinfi_infra_bclk_sel_mux", CLK_CFG_1, 23),
+ I_GATE(CLK_TOP_FLASH_SEL, "flash_sel", "flash_sel_mux", CLK_CFG_1, 31),
+
+ I_GATE(CLK_TOP_UART_SEL, "uart_sel", "uart_sel_mux", CLK_CFG_2, 7),
+ I_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", "spi0_sel_mux", CLK_CFG_2, 15),
+ I_GATE(CLK_TOP_SPI1_SEL, "spi1_sel", "spi1_sel_mux", CLK_CFG_2, 23),
+ I_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", "msdc50_0_sel_mux", CLK_CFG_2, 31),
+
+ I_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", "msdc30_0_sel_mux", CLK_CFG_3, 7),
+ I_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", "msdc30_1_sel_mux", CLK_CFG_3, 15),
+ I_GATE(CLK_TOP_A1SYS_HP_SEL, "a1sys_hp_sel", "a1sys_hp_sel_mux", CLK_CFG_3, 23),
+ I_GATE(CLK_TOP_A2SYS_HP_SEL, "a2sys_hp_sel", "a2sys_hp_sel_mux", CLK_CFG_3, 31),
+
+ I_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", "intdir_sel_mux", CLK_CFG_4, 7),
+ I_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", "aud_intbus_sel_mux", CLK_CFG_4, 15),
+ I_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", "pmicspi_sel_mux", CLK_CFG_4, 23),
+ I_GATE(CLK_TOP_SCP_SEL, "scp_sel", "scp_sel_mux", CLK_CFG_4, 31),
+
+ I_GATE(CLK_TOP_ATB_SEL, "atb_sel", "atb_sel_mux", CLK_CFG_5, 7),
+ I_GATE(CLK_TOP_HIF_SEL, "hif_sel", "hif_sel_mux", CLK_CFG_5, 15),
+ I_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", "audio_sel_mux", CLK_CFG_5, 23),
+ I_GATE(CLK_TOP_AUDIO_SEL, "usb20_sel", "usb20_sel_mux", CLK_CFG_5, 31),
+
+ I_GATE(CLK_TOP_AUD1_SEL, "aud1_sel", "aud1_sel_mux", CLK_CFG_6, 7),
+ I_GATE(CLK_TOP_AUD2_SEL, "aud2_sel", "aud2_sel_mux", CLK_CFG_6, 15),
+ I_GATE(CLK_TOP_IRRX_SEL, "irrx_sel_sel", "irrx_sel_mux", CLK_CFG_6, 23),
+ I_GATE(CLK_TOP_IRTX_SEL, "irtx_sel", "irtx_sel_mux", CLK_CFG_6, 31),
+
+ I_GATE(CLK_TOP_ASM_L_SEL, "asm_l_sel", "asm_l_sel_mux", CLK_CFG_6, 7),
+ I_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", "asm_m_sel_mux", CLK_CFG_6, 15),
+ I_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", "asm_h_sel_mux", CLK_CFG_6, 23),
+
+ I_GATE(CLK_TOP_APLL1_SEL, "apll1_ck_sel", "apll1_ck_div", CLK_AUDDIV_0, 0),
+ I_GATE(CLK_TOP_APLL2_SEL, "apll2_ck_sel", "apll2_ck_div", CLK_AUDDIV_0, 0),
+ I_GATE(CLK_TOP_I2S0_MCK_SEL, "i2s0_mck_sel", "i2s0_mck_div", CLK_AUDDIV_0, 0),
+ I_GATE(CLK_TOP_I2S1_MCK_SEL, "i2s1_mck_sel", "i2s1_mck_div", CLK_AUDDIV_0, 0),
+ I_GATE(CLK_TOP_I2S2_MCK_SEL, "i2s2_mck_sel", "i2s2_mck_div", CLK_AUDDIV_0, 0),
+ I_GATE(CLK_TOP_I2S3_MCK_SEL, "i2s3_mck_sel", "i2s3_mck_div", CLK_AUDDIV_0, 0),
+};
+
+static struct clk_mux_def muxes_clk[] = {
+ MUX0(0, "eth_sel_mux", eth_ck_parents, CLK_CFG_0, 24, 3),
+ MUX0(0, "ddrphycfg_sel_mux", ddrphycfg_ck_parents, CLK_CFG_0, 16, 1),
+ MUX0(0, "mem_sel_mux", mem_ck_parents, CLK_CFG_0, 8, 1),
+ MUX0(0, "axi_sel_mux", axi_ck_parents, CLK_CFG_0, 0, 3),
+
+ MUX0(0, "pwm_sel_mux", pwm_ck_parents, CLK_CFG_1, 0, 2),
+ MUX0(0, "f10m_ref_sel_mux", f10m_ref_ck_parents, CLK_CFG_1, 8, 1),
+ MUX0(0, "spinfi_infra_bclk_sel_mux", nfi_infra_ck_parents, CLK_CFG_1, 16, 4),
+ MUX0(0, "flash_sel_mux", flash_ck_parents, CLK_CFG_1, 24, 3),
+
+ MUX0(0, "uart_sel_mux", uart_ck_parents, CLK_CFG_2, 0, 1),
+ MUX0(0, "spi0_sel_mux", spi0_ck_parents, CLK_CFG_2, 8, 3),
+ MUX0(0, "spi1_sel_mux", spi1_ck_parents, CLK_CFG_2, 16, 3),
+ MUX0(0, "msdc50_0_sel_mux", msdc50_0_ck_parents, CLK_CFG_2, 24, 3),
+
+ MUX0(0, "msdc30_0_sel_mux", msdc30_0_ck_parents, CLK_CFG_3, 0, 3),
+ MUX0(0, "msdc30_1_sel_mux", msdc30_1_ck_parents, CLK_CFG_3, 8, 3),
+ MUX0(0, "a1sys_hp_sel_mux", a1sys_hp_ck_parents, CLK_CFG_3, 16, 2),
+ MUX0(0, "a2sys_hp_sel_mux", a2sys_hp_ck_parents, CLK_CFG_3, 24, 2),
+
+ MUX0(0, "intdir_sel_mux", intdir_ck_parents, CLK_CFG_4, 0, 2),
+ MUX0(0, "aud_intbus_sel_mux", aud_intbus_ck_parents, CLK_CFG_4, 8, 2),
+ MUX0(0, "pmicspi_sel_mux", pmicspi_ck_parents, CLK_CFG_4, 16, 3),
+ MUX0(0, "scp_sel_mux", scp_ck_parents, CLK_CFG_4, 24, 2),
+
+ MUX0(0, "atb_sel_mux", atb_ck_parents, CLK_CFG_5, 0, 2),
+ MUX0(0, "hif_sel_mux", hif_ck_parents, CLK_CFG_5, 8, 3),
+ MUX0(0, "audio_sel_mux", audio_ck_parents, CLK_CFG_5, 8, 3),
+ MUX0(0, "usb20_sel_mux", usb20_ck_parents, CLK_CFG_5, 24, 2),
+
+ MUX0(0, "aud1_sel_mux", aud1_ck_parents, CLK_CFG_6, 0, 1),
+ MUX0(0, "aud2_sel_mux", aud2_ck_parents, CLK_CFG_6, 8, 1),
+ MUX0(0, "irrx_sel_mux", irrx_ck_parents, CLK_CFG_6, 16, 1),
+ MUX0(0, "irtx_sel_mux", irtx_ck_parents, CLK_CFG_6, 24, 1),
+
+ MUX0(0, "asm_l_sel_mux", asm_l_ck_parents, CLK_CFG_7, 0, 2),
+ MUX0(0, "asm_m_sel_mux", asm_m_ck_parents, CLK_CFG_7, 8, 2),
+ MUX0(0, "asm_h_sel_mux", asm_h_ck_parents, CLK_CFG_7, 16, 2),
+
+ MUX0(0, "apll1_ck_mux", apll_ck_parents, CLK_AUDDIV_0, 6, 1),
+ MUX0(0, "apll2_ck_mux", apll2_ck_parents, CLK_AUDDIV_0, 7, 1),
+ MUX0(0, "i2s0_mck_mux", apll_ck_parents, CLK_AUDDIV_0, 8, 1),
+ MUX0(0, "i2s1_mck_mux", apll_ck_parents, CLK_AUDDIV_0, 9, 1),
+ MUX0(0, "i2s2_mck_mux", apll_ck_parents, CLK_AUDDIV_0, 10, 1),
+ MUX0(0, "i2s3_mck_mux", apll_ck_parents, CLK_AUDDIV_0, 11, 1),
+};
+
+static struct clk_div_def dived_clk[] = {
+ DIV(CLK_TOP_APLL1_DIV, "apll1_ck_div", "apll1_ck_mux",
+ 0x120, 24, 3),
+ DIV(CLK_TOP_APLL2_DIV, "apll2_ck_div", "apll2_ck_mux",
+ 0x120, 28, 3),
+ DIV(CLK_TOP_I2S0_MCK_DIV, "i2s0_mck_div", "i2s0_mck_mux",
+ 0x124, 0, 7),
+ DIV(CLK_TOP_I2S1_MCK_DIV, "i2s1_mck_div", "i2s1_mck_mux",
+ 0x124, 8, 7),
+ DIV(CLK_TOP_I2S2_MCK_DIV, "i2s2_mck_div", "i2s2_mck_mux",
+ 0x124, 16, 7),
+ DIV(CLK_TOP_I2S3_MCK_DIV, "i2s3_mck_div", "i2s3_mck_mux",
+ 0x124, 24, 7),
+ DIV(CLK_TOP_A1SYS_HP_DIV, "a1sys_div", "a1sys_hp_sel",
+ 0x128, 8, 7),
+ DIV(CLK_TOP_A2SYS_HP_DIV, "a2sys_div", "a2sys_hp_sel",
+ 0x128, 24, 7),
+};
+
+static struct mdtk_clk_def clk_def = {
+ .linked_def = NULL,
+ .num_linked = 0,
+ .fixed_def = fixed_clk,
+ .num_fixed = nitems(fixed_clk),
+ .gates_def = gates_clk,
+ .num_gates = nitems(gates_clk),
+ .dived_def = dived_clk,
+ .num_dived = nitems(dived_clk),
+ .muxes_def = muxes_clk,
+ .num_muxes = nitems(muxes_clk),
+};
+
+static int
+topckgen_clk_detach(device_t dev) {
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+topckgen_clk_probe(device_t dev) {
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Mediatek Topckgen clocks");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+topckgen_clk_attach(device_t dev) {
+ struct mdtk_clk_softc *sc = device_get_softc(dev);
+ int rid, rv;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ /* Resource setup. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "cannot allocate memory resource\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ mdtk_register_clocks(dev, &clk_def);
+ return (0);
+
+ fail:
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (rv);
+}
+
+static device_method_t mdtk_mt7622_topckgen_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, topckgen_clk_probe),
+ DEVMETHOD(device_attach, topckgen_clk_attach),
+ DEVMETHOD(device_detach, topckgen_clk_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, mdtk_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, mdtk_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, mdtk_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, mdtk_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, mdtk_clkdev_device_unlock),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(mdtk_mt7622_topckgen, mdtk_mt7622_topckgen_driver, mdtk_mt7622_topckgen_methods,
+sizeof(struct mdtk_clk_softc));
+
+EARLY_DRIVER_MODULE(mdtk_mt7622_topckgen, simplebus, mdtk_mt7622_topckgen_driver, NULL, NULL,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 2);
\ No newline at end of file
diff --git a/sys/arm64/mediatek/mt_uart.c b/sys/arm64/mediatek/mt_uart.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/mediatek/mt_uart.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2025 Martin Filla
+ * Copyright (c) 2025 Michal Meloun <mmel@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/cdefs.h>
+/*
+ * UART driver for mediatek SoCs.
+ */
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <dev/clk/clk.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_cpu_fdt.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_ns8250.h>
+#include <dev/ic/ns16550.h>
+
+#include "uart_if.h"
+
+/*
+ * High-level UART interface.
+ */
+struct mt_softc {
+ struct ns8250_softc ns8250_base;
+ clk_t baud_clk;
+ clk_t bus_clk;
+};
+
+/*
+ * UART class interface.
+ */
+static int
+mt_uart_attach(struct uart_softc *sc)
+{
+ int rv;
+ struct ns8250_softc *ns8250 = (struct ns8250_softc *)sc;
+ struct uart_bas *bas = &sc->sc_bas;
+
+ rv = ns8250_bus_attach(sc);
+ if (rv != 0)
+ return (rv);
+
+ ns8250->ier_mask = 0xc0;
+ ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask;
+ ns8250->ier |= ns8250->ier_rxbits;
+ uart_setreg(bas, REG_IER, ns8250->ier);
+ uart_barrier(bas);
+ return (0);
+}
+
+static kobj_method_t mt_methods[] = {
+ KOBJMETHOD(uart_probe, ns8250_bus_probe),
+ KOBJMETHOD(uart_attach, mt_uart_attach),
+ KOBJMETHOD(uart_detach, ns8250_bus_detach),
+ KOBJMETHOD(uart_flush, ns8250_bus_flush),
+ KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
+ KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl),
+ KOBJMETHOD(uart_ipend, ns8250_bus_ipend),
+ KOBJMETHOD(uart_param, ns8250_bus_param),
+ KOBJMETHOD(uart_receive, ns8250_bus_receive),
+ KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
+ KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_txbusy, ns8250_bus_txbusy),
+ KOBJMETHOD(uart_grab, ns8250_bus_grab),
+ KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
+ KOBJMETHOD_END
+};
+
+static struct uart_class mt_uart_class = {
+ "mediatek class",
+ mt_methods,
+ sizeof(struct mt_softc),
+ .uc_ops = &uart_ns8250_ops,
+ .uc_range = 8,
+ .uc_rclk = 0,
+ .uc_rshift = 2,
+ .uc_riowidth = 4,
+};
+
+/* Compatible devices. */
+static struct ofw_compat_data compat_data[] = {
+ {"mediatek,mt6577-uart", (uintptr_t)&mt_uart_class},
+ {NULL, (uintptr_t)NULL},
+};
+
+UART_FDT_CLASS(compat_data);
+
+/*
+ * UART Driver interface.
+ */
+static int
+uart_fdt_get_shift1(phandle_t node)
+{
+ pcell_t shift;
+
+ if ((OF_getencprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
+ shift = 2;
+ return ((int)shift);
+}
+
+static int
+mt_uart_probe(device_t dev)
+{
+ struct mt_softc *sc;
+ phandle_t node;
+ uint64_t freq;
+ int shift;
+ int rv;
+ const struct ofw_compat_data *cd;
+
+ sc = device_get_softc(dev);
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ cd = ofw_bus_search_compatible(dev, compat_data);
+ if (cd->ocd_data == 0)
+ return (ENXIO);
+ sc->ns8250_base.base.sc_class = (struct uart_class *)cd->ocd_data;
+
+ node = ofw_bus_get_node(dev);
+ shift = uart_fdt_get_shift1(node);
+ rv = clk_get_by_ofw_name(dev, 0, "baud", &sc->baud_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get UART baud clock: %d\n", rv);
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->baud_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable UART baud clock: %d\n", rv);
+ return (ENXIO);
+ }
+
+ rv = clk_get_by_ofw_name(dev, 0, "bus", &sc->bus_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get UART bus clock: %d\n", rv);
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->bus_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable UART bus clock: %d\n", rv);
+ return (ENXIO);
+ }
+
+ rv = clk_get_freq(sc->baud_clk, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get freq UART clock: %d\n", rv);
+ return (ENXIO);
+ }
+
+ return (uart_bus_probe(dev, shift, 0, (int)freq, 0, 0, 0));
+}
+
+static int
+mt_uart_detach(device_t dev)
+{
+ struct mt_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->baud_clk != NULL) {
+ clk_release(sc->baud_clk);
+ }
+
+ if (sc->bus_clk != NULL) {
+ clk_release(sc->bus_clk);
+ }
+
+
+ return (uart_bus_detach(dev));
+}
+
+static device_method_t mt_uart_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mt_uart_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, mt_uart_detach),
+ DEVMETHOD_END
+};
+
+static driver_t mt_uart_driver = {
+ uart_driver_name,
+ mt_uart_bus_methods,
+ sizeof(struct mt_softc),
+};
+
+DRIVER_MODULE(mdtk_uart, simplebus, mt_uart_driver, 0, 0);
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -853,3 +853,15 @@
dev/clk/xilinx/zynqmp_clk_mux.c optional fdt soc_xilinx_zynq
dev/clk/xilinx/zynqmp_clk_pll.c optional fdt soc_xilinx_zynq
dev/clk/xilinx/zynqmp_reset.c optional fdt soc_xilinx_zynq
+
+# Mediatek
+arm64/mediatek/mt_uart.c optional fdt soc_mediatek
+arm64/mediatek/mt7622_clk_topckgen.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_pericfg.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_infracfg.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_audio.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_eth.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_sgmii.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_ssusbsys.c optional clk fdt soc_mediatek
+arm64/mediatek/mt7622_clk_pciesys.c optional clk fdt soc_mediatek
+arm64/mediatek/mdtk_clk.c optional clk fdt soc_mediatek
diff --git a/sys/conf/options.arm64 b/sys/conf/options.arm64
--- a/sys/conf/options.arm64
+++ b/sys/conf/options.arm64
@@ -39,6 +39,7 @@
SOC_HISI_HI6220 opt_soc.h
SOC_INTEL_STRATIX10 opt_soc.h
SOC_MARVELL_8K opt_soc.h
+SOC_MEDIATEK opt_soc.h
SOC_NVIDIA_TEGRA210 opt_soc.h
SOC_NXP_LS opt_soc.h
SOC_ROCKCHIP opt_soc.h
diff --git a/sys/modules/dtb/mediatek/Makefile b/sys/modules/dtb/mediatek/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/dtb/mediatek/Makefile
@@ -0,0 +1,7 @@
+.if ${MACHINE_ARCH} == "aarch64"
+DTS= mediatek/mt7622-bananapi-bpi-r64.dts \
+ mediatek/mt7986a-bananapi-bpi-r3-mini.dts \
+ mediatek/mt7986a-bananapi-bpi-r3.dts
+.endif
+
+.include <bsd.dtb.mk>
\ No newline at end of file

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 24, 8:51 AM (15 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35439579
Default Alt Text
D57732.diff (76 KB)

Event Timeline