git: 20d6c796fae0 - stable/14 - arm64: zynqmp: Add clock driver

From: Emmanuel Vadot <manu_at_FreeBSD.org>
Date: Wed, 18 Oct 2023 14:31:37 UTC
The branch stable/14 has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=20d6c796fae0d3075485159514825a9090e50ce8

commit 20d6c796fae0d3075485159514825a9090e50ce8
Author:     Emmanuel Vadot <manu@FreeBSD.org>
AuthorDate: 2023-09-07 07:57:03 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2023-10-18 14:31:03 +0000

    arm64: zynqmp: Add clock driver
    
    Add clock and reset drivers for the ZynqMP SoC.
    The clocks are discovered by talking to the firmware as the topology isn't
    fixed on this SoC.
    
    Differential Revision:  https://reviews.freebsd.org/D41812
    Sponsored by:   Beckhoff Automation GmbH & Co. KG
    
    (cherry picked from commit 4e579ad047720775ab580b74192c7de8a3386fea)
---
 sys/conf/files.arm64                  |   7 +
 sys/dev/clk/xilinx/zynqmp_clk_div.c   | 140 +++++++++
 sys/dev/clk/xilinx/zynqmp_clk_div.h   |  38 +++
 sys/dev/clk/xilinx/zynqmp_clk_fixed.c | 101 ++++++
 sys/dev/clk/xilinx/zynqmp_clk_fixed.h |  33 ++
 sys/dev/clk/xilinx/zynqmp_clk_gate.c  | 102 ++++++
 sys/dev/clk/xilinx/zynqmp_clk_gate.h  |  33 ++
 sys/dev/clk/xilinx/zynqmp_clk_mux.c   |  89 ++++++
 sys/dev/clk/xilinx/zynqmp_clk_mux.h   |  33 ++
 sys/dev/clk/xilinx/zynqmp_clk_pll.c   | 132 ++++++++
 sys/dev/clk/xilinx/zynqmp_clk_pll.h   |  33 ++
 sys/dev/clk/xilinx/zynqmp_clock.c     | 562 ++++++++++++++++++++++++++++++++++
 sys/dev/clk/xilinx/zynqmp_reset.c     | 253 +++++++++++++++
 13 files changed, 1556 insertions(+)

diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 987a1ea6cd09..dc78840646bb 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -700,3 +700,10 @@ arm/xilinx/zy7_gpio.c				optional gpio soc_xilinx_zynq fdt
 dev/usb/controller/xlnx_dwc3.c			optional xhci soc_xilinx_zynq fdt
 dev/firmware/xilinx/zynqmp_firmware.c		optional fdt soc_xilinx_zynq
 dev/firmware/xilinx/zynqmp_firmware_if.m	optional fdt soc_xilinx_zynq
+dev/clk/xilinx/zynqmp_clock.c			optional fdt soc_xilinx_zynq
+dev/clk/xilinx/zynqmp_clk_div.c			optional fdt soc_xilinx_zynq
+dev/clk/xilinx/zynqmp_clk_fixed.c		optional fdt soc_xilinx_zynq
+dev/clk/xilinx/zynqmp_clk_gate.c		optional fdt soc_xilinx_zynq
+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
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_div.c b/sys/dev/clk/xilinx/zynqmp_clk_div.c
new file mode 100644
index 000000000000..cc6e4d73e92d
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_div.c
@@ -0,0 +1,140 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_div.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+#define DIV_ROUND_CLOSEST(n, d)	(((n) + (d) / 2) / (d))
+
+struct zynqmp_clk_div_softc {
+	device_t			firmware;
+	enum zynqmp_clk_div_type	type;
+	uint32_t			id;
+};
+
+static int
+zynqmp_clk_div_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+zynqmp_clk_div_recalc(struct clknode *clk, uint64_t *freq)
+{
+	struct zynqmp_clk_div_softc *sc;
+	uint32_t div;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+	rv = ZYNQMP_FIRMWARE_CLOCK_GETDIVIDER(sc->firmware, sc->id, &div);
+	if (rv != 0) {
+		printf("%s: Error while getting divider for %s\n",
+		    __func__,
+		    clknode_get_name(clk));
+		return (EINVAL);
+	}
+
+	if (sc->type == CLK_DIV_TYPE_DIV0)
+		div &= 0xFFFF;
+	else
+		div = div >> 16;
+	*freq = howmany((unsigned long long)*freq, div + 1);
+	return (0);
+}
+
+static int
+zynqmp_clk_div_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct zynqmp_clk_div_softc *sc;
+	uint32_t div;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+
+	div = DIV_ROUND_CLOSEST(fparent, *fout);
+	if (sc->type == CLK_DIV_TYPE_DIV0) {
+		div &= 0xFFFF;
+		div |= 0xFFFF << 16;
+	} else {
+		div <<= 16;
+		div |= 0xFFFF;
+	}
+
+	rv = ZYNQMP_FIRMWARE_CLOCK_SETDIVIDER(sc->firmware, sc->id, div);
+	if (rv != 0) {
+		printf("%s: Error while setting divider for %s\n",
+		    __func__,
+		    clknode_get_name(clk));
+		return (EINVAL);
+	}
+
+	return (rv);
+}
+
+static clknode_method_t zynqmp_clk_div_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		zynqmp_clk_div_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	zynqmp_clk_div_recalc),
+	CLKNODEMETHOD(clknode_set_freq,		zynqmp_clk_div_set_freq),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_div_clknode, zynqmp_clk_div_clknode_class,
+    zynqmp_clk_div_clknode_methods, sizeof(struct zynqmp_clk_div_softc), clknode_class);
+
+int
+zynqmp_clk_div_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef, enum zynqmp_clk_div_type type)
+{
+	struct clknode *clk;
+	struct zynqmp_clk_div_softc *sc;
+	uint32_t fw_clk_id;
+
+	fw_clk_id = clkdef->id - 1;
+	clkdef->id = 0;
+	clk = clknode_create(clkdom, &zynqmp_clk_div_clknode_class, clkdef);
+	if (clk == NULL)
+		return (1);
+	sc = clknode_get_softc(clk);
+	sc->id = fw_clk_id;
+	sc->firmware = fw;
+	sc->type = type;
+	clknode_register(clkdom, clk);
+	return (0);
+}
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_div.h b/sys/dev/clk/xilinx/zynqmp_clk_div.h
new file mode 100644
index 000000000000..f0dc07bf63e6
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_div.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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.
+ */
+
+#ifndef _ZYNQMP_CLK_DIV_H_
+#define	_ZYNQMP_CLK_DIV_H_
+
+enum zynqmp_clk_div_type {
+	CLK_DIV_TYPE_DIV0 = 0,
+	CLK_DIV_TYPE_DIV1
+};
+
+int zynqmp_clk_div_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef, enum zynqmp_clk_div_type type);
+
+#endif /* _ZYNQMP_CLK_DIV_H_ */
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_fixed.c b/sys/dev/clk/xilinx/zynqmp_clk_fixed.c
new file mode 100644
index 000000000000..94de0491acb6
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_fixed.c
@@ -0,0 +1,101 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_fixed.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+struct zynqmp_clk_fixed_softc {
+	device_t	firmware;
+	uint32_t	id;
+};
+
+static int
+zynqmp_clk_fixed_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+zynqmp_clk_fixed_recalc(struct clknode *clk, uint64_t *freq)
+{
+	struct zynqmp_clk_fixed_softc *sc;
+	uint32_t mult, div;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+	rv = ZYNQMP_FIRMWARE_CLOCK_GET_FIXEDFACTOR(sc->firmware, sc->id, &mult, &div);
+	if (rv != 0) {
+		printf("%s: Error while getting fixed factor for %s\n",
+		    __func__,
+		    clknode_get_name(clk));
+		return (EINVAL);
+	}
+
+	*freq = (*freq * mult) / div;
+	return (0);
+}
+
+static clknode_method_t zynqmp_clk_fixed_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		zynqmp_clk_fixed_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	zynqmp_clk_fixed_recalc),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_fixed_clknode, zynqmp_clk_fixed_clknode_class,
+    zynqmp_clk_fixed_clknode_methods, sizeof(struct zynqmp_clk_fixed_softc), clknode_class);
+
+int
+zynqmp_clk_fixed_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)
+{
+	struct clknode *clk;
+	struct zynqmp_clk_fixed_softc *sc;
+	uint32_t fw_clk_id;
+
+	fw_clk_id = clkdef->id - 1;
+	clkdef->id = 0;
+	clk = clknode_create(clkdom, &zynqmp_clk_fixed_clknode_class, clkdef);
+	if (clk == NULL)
+		return (1);
+	sc = clknode_get_softc(clk);
+	sc->id = fw_clk_id;
+	sc->firmware = fw;
+	clknode_register(clkdom, clk);
+	return (0);
+}
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_fixed.h b/sys/dev/clk/xilinx/zynqmp_clk_fixed.h
new file mode 100644
index 000000000000..c014ea7b5457
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_fixed.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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.
+ */
+
+#ifndef _ZYNQMP_CLK_FIXED_H_
+#define	_ZYNQMP_CLK_FIXED_H_
+
+int zynqmp_clk_fixed_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef);
+
+#endif /* _ZYNQMP_CLK_FIXED_H_ */
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_gate.c b/sys/dev/clk/xilinx/zynqmp_clk_gate.c
new file mode 100644
index 000000000000..180c7db38c09
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_gate.c
@@ -0,0 +1,102 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_gate.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+struct zynqmp_clk_gate_softc {
+	device_t	firmware;
+	uint32_t	id;
+};
+
+static int
+zynqmp_clk_gate_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+zynqmp_clk_set_gate(struct clknode *clk, bool enable)
+{
+	struct zynqmp_clk_gate_softc *sc;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+	if (enable)
+		rv = ZYNQMP_FIRMWARE_CLOCK_ENABLE(sc->firmware, sc->id);
+	else
+		rv = ZYNQMP_FIRMWARE_CLOCK_DISABLE(sc->firmware, sc->id);
+	if (rv != 0) {
+		printf("%s: Error %sbling %s\n",
+		    __func__,
+		    enable == true ? "ena" : "disa",
+		    clknode_get_name(clk));
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static clknode_method_t zynqmp_clk_gate_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,	zynqmp_clk_gate_init),
+	CLKNODEMETHOD(clknode_set_gate,	zynqmp_clk_set_gate),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_gate_clknode, zynqmp_clk_gate_clknode_class,
+    zynqmp_clk_gate_clknode_methods, sizeof(struct zynqmp_clk_gate_softc), clknode_class);
+
+int
+zynqmp_clk_gate_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)
+{
+	struct clknode *clk;
+	struct zynqmp_clk_gate_softc *sc;
+	uint32_t fw_clk_id;
+
+	fw_clk_id = clkdef->id - 1;
+	clkdef->id = 0;
+	clk = clknode_create(clkdom, &zynqmp_clk_gate_clknode_class, clkdef);
+	if (clk == NULL)
+		return (1);
+	sc = clknode_get_softc(clk);
+	sc->id = fw_clk_id;
+	sc->firmware = fw;
+	clknode_register(clkdom, clk);
+	return (0);
+}
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_gate.h b/sys/dev/clk/xilinx/zynqmp_clk_gate.h
new file mode 100644
index 000000000000..bc6e9f218d41
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_gate.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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.
+ */
+
+#ifndef _ZYNQMP_CLK_GATE_H_
+#define	_ZYNQMP_CLK_GATE_H_
+
+int zynqmp_clk_gate_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef);
+
+#endif /* _ZYNQMP_CLK_GATE_H_ */
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_mux.c b/sys/dev/clk/xilinx/zynqmp_clk_mux.c
new file mode 100644
index 000000000000..6826ee5123fe
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_mux.c
@@ -0,0 +1,89 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_mux.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+struct zynqmp_clk_mux_softc {
+	device_t	firmware;
+	uint32_t	id;
+};
+
+static int
+zynqmp_clk_mux_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+zynqmp_clk_mux_set_mux(struct clknode *clk, int idx)
+{
+
+	printf("%s: called for %s\n", __func__, clknode_get_name(clk));
+	return (0);
+}
+
+static clknode_method_t zynqmp_clk_mux_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		zynqmp_clk_mux_init),
+	CLKNODEMETHOD(clknode_set_mux,		zynqmp_clk_mux_set_mux),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_mux_clknode, zynqmp_clk_mux_clknode_class,
+    zynqmp_clk_mux_clknode_methods, sizeof(struct zynqmp_clk_mux_softc), clknode_class);
+
+int
+zynqmp_clk_mux_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)
+{
+	struct clknode *clk;
+	struct zynqmp_clk_mux_softc *sc;
+	uint32_t fw_clk_id;
+
+	fw_clk_id = clkdef->id - 1;
+	clkdef->id = 0;
+	clk = clknode_create(clkdom, &zynqmp_clk_mux_clknode_class, clkdef);
+	if (clk == NULL)
+		return (1);
+	sc = clknode_get_softc(clk);
+	sc->id = fw_clk_id;
+	sc->firmware = fw;
+	clknode_register(clkdom, clk);
+	return (0);
+}
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_mux.h b/sys/dev/clk/xilinx/zynqmp_clk_mux.h
new file mode 100644
index 000000000000..4768accd2c9e
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_mux.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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.
+ */
+
+#ifndef _ZYNQMP_CLK_MUX_H_
+#define	_ZYNQMP_CLK_MUX_H_
+
+int zynqmp_clk_mux_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef);
+
+#endif /* _ZYNQMP_CLK_MUX_H_ */
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_pll.c b/sys/dev/clk/xilinx/zynqmp_clk_pll.c
new file mode 100644
index 000000000000..6e5da9533859
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_pll.c
@@ -0,0 +1,132 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_pll.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+struct zynqmp_clk_pll_softc {
+	device_t	firmware;
+	uint32_t	id;
+};
+
+enum pll_mode {
+	PLL_MODE_INT = 0,
+	PLL_MODE_FRAC,
+	PLL_MODE_ERROR,
+};
+
+static int
+zynqmp_clk_pll_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static int
+zynqmp_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
+{
+	struct zynqmp_clk_pll_softc *sc;
+	uint64_t pll_freq, pll_frac;
+	uint32_t div, mode, frac;
+	int rv;
+
+	sc = clknode_get_softc(clk);
+	rv = ZYNQMP_FIRMWARE_CLOCK_GETDIVIDER(sc->firmware, sc->id, &div);
+	if (rv != 0) {
+		printf("%s: Error while getting divider for %s\n",
+		    __func__,
+		    clknode_get_name(clk));
+	}
+	rv = ZYNQMP_FIRMWARE_PLL_GET_MODE(sc->firmware, sc->id, &mode);
+	if (rv != 0) {
+		printf("%s: Error while getting mode for %s\n",
+		    __func__,
+		    clknode_get_name(clk));
+	}
+	if (mode == PLL_MODE_ERROR)
+		return (0);
+
+	pll_freq = *freq * div;
+	if (mode == PLL_MODE_FRAC) {
+		ZYNQMP_FIRMWARE_PLL_GET_FRAC_DATA(sc->firmware, sc->id, &frac);
+		pll_frac = (*freq * frac) / (1 << 16);
+		pll_freq += pll_frac;
+	}
+
+	*freq = pll_freq;
+	return (0);
+}
+
+static int
+zynqmp_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+    int flags, int *stop)
+{
+
+	/* TODO probably at one point */
+	return (ENOTSUP);
+}
+
+static clknode_method_t zynqmp_clk_pll_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		zynqmp_clk_pll_init),
+	CLKNODEMETHOD(clknode_recalc_freq,	zynqmp_clk_pll_recalc),
+	CLKNODEMETHOD(clknode_set_freq,		zynqmp_clk_pll_set_freq),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_pll_clknode, zynqmp_clk_pll_clknode_class,
+    zynqmp_clk_pll_clknode_methods, sizeof(struct zynqmp_clk_pll_softc), clknode_class);
+
+int
+zynqmp_clk_pll_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef)
+{
+	struct clknode *clk;
+	struct zynqmp_clk_pll_softc *sc;
+	uint32_t fw_clk_id;
+
+	fw_clk_id = clkdef->id - 1;
+	clkdef->id = 0;
+	clk = clknode_create(clkdom, &zynqmp_clk_pll_clknode_class, clkdef);
+	if (clk == NULL)
+		return (1);
+	sc = clknode_get_softc(clk);
+	sc->id = fw_clk_id;
+	sc->firmware = fw;
+	clknode_register(clkdom, clk);
+	return (0);
+}
diff --git a/sys/dev/clk/xilinx/zynqmp_clk_pll.h b/sys/dev/clk/xilinx/zynqmp_clk_pll.h
new file mode 100644
index 000000000000..c905efc1755f
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clk_pll.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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.
+ */
+
+#ifndef _ZYNQMP_CLK_PLL_H_
+#define	_ZYNQMP_CLK_PLL_H_
+
+int zynqmp_clk_pll_register(struct clkdom *clkdom, device_t fw, struct clknode_init_def *clkdef);
+
+#endif /* _ZYNQMP_CLK_PLL_H_ */
diff --git a/sys/dev/clk/xilinx/zynqmp_clock.c b/sys/dev/clk/xilinx/zynqmp_clock.c
new file mode 100644
index 000000000000..76f23cec38d0
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_clock.c
@@ -0,0 +1,562 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <machine/bus.h>
+#include <sys/queue.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_fixed.h>
+
+#include <dev/clk/xilinx/zynqmp_clk_mux.h>
+#include <dev/clk/xilinx/zynqmp_clk_pll.h>
+#include <dev/clk/xilinx/zynqmp_clk_fixed.h>
+#include <dev/clk/xilinx/zynqmp_clk_div.h>
+#include <dev/clk/xilinx/zynqmp_clk_gate.h>
+
+#include <dev/firmware/xilinx/pm_defs.h>
+
+#include "clkdev_if.h"
+#include "zynqmp_firmware_if.h"
+
+#define	ZYNQMP_MAX_NAME_LEN	16
+#define	ZYNQMP_MAX_NODES	6
+#define	ZYNQMP_MAX_PARENTS	100
+
+#define	ZYNQMP_CLK_IS_VALID	(1 << 0)
+#define	ZYNQMP_CLK_IS_EXT	(1 << 2)
+
+#define	ZYNQMP_GET_NODE_TYPE(x)		(x & 0x7)
+#define	ZYNQMP_GET_NODE_CLKFLAGS(x)	((x >> 8) & 0xFF)
+#define	ZYNQMP_GET_NODE_TYPEFLAGS(x)	((x >> 24) & 0xF)
+
+enum ZYNQMP_NODE_TYPE {
+	CLK_NODE_TYPE_NULL = 0,
+	CLK_NODE_TYPE_MUX,
+	CLK_NODE_TYPE_PLL,
+	CLK_NODE_TYPE_FIXED,
+	CLK_NODE_TYPE_DIV0,
+	CLK_NODE_TYPE_DIV1,
+	CLK_NODE_TYPE_GATE,
+};
+
+/*
+ * Clock IDs in the firmware starts at 0 but
+ * exported clocks (and so clock exposed by the clock framework)
+ * starts at 1
+ */
+#define	ZYNQMP_ID_TO_CLK(x)	((x) + 1)
+#define	CLK_ID_TO_ZYNQMP(x)	((x) - 1)
+
+struct zynqmp_clk {
+	TAILQ_ENTRY(zynqmp_clk)	next;
+	struct clknode_init_def	clkdef;
+	uint32_t		id;
+	uint32_t		parentids[ZYNQMP_MAX_PARENTS];
+	uint32_t		topology[ZYNQMP_MAX_NODES];
+	uint32_t		attributes;
+};
+
+struct zynqmp_clock_softc {
+	device_t			dev;
+	device_t			parent;
+	phandle_t			node;
+	clk_t				clk_pss_ref;
+	clk_t				clk_video;
+	clk_t				clk_pss_alt_ref;
+	clk_t				clk_aux_ref;
+	clk_t				clk_gt_crx_ref;
+	struct clkdom			*clkdom;
+};
+
+struct name_resp {
+	char name[16];
+};
+
+struct zynqmp_clk_softc {
+	struct zynqmp_clk	*clk;
+	device_t		firmware;
+	uint32_t		id;
+};
+
+static int
+zynqmp_clk_init(struct clknode *clk, device_t dev)
+{
+
+	clknode_init_parent_idx(clk, 0);
+	return (0);
+}
+
+static clknode_method_t zynqmp_clk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		zynqmp_clk_init),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(zynqmp_clk_clknode, zynqmp_clk_clknode_class,
+    zynqmp_clk_clknode_methods, sizeof(struct zynqmp_clk_softc), clknode_class);
+
+static int
*** 686 LINES SKIPPED ***