aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2023-09-07 07:57:03 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2023-09-18 13:23:26 +0000
commit4e579ad047720775ab580b74192c7de8a3386fea (patch)
tree74c3e89834a45d06f676ec3ff6e128ef57e987ac
parent9e88711f28dc9afa7d68ae8dd027d2399a2a290b (diff)
downloadsrc-4e579ad047720775ab580b74192c7de8a3386fea.tar.gz
src-4e579ad047720775ab580b74192c7de8a3386fea.zip
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
-rw-r--r--sys/conf/files.arm647
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_div.c140
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_div.h38
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_fixed.c101
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_fixed.h33
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_gate.c102
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_gate.h33
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_mux.c89
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_mux.h33
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_pll.c132
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clk_pll.h33
-rw-r--r--sys/dev/clk/xilinx/zynqmp_clock.c562
-rw-r--r--sys/dev/clk/xilinx/zynqmp_reset.c253
13 files changed, 1556 insertions, 0 deletions
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
+zynqmp_clk_register(struct clkdom *clkdom, device_t fw, struct zynqmp_clk *clkdef)
+{
+ struct clknode *clknode;
+ struct zynqmp_clk_softc *sc;
+ char *prev_clock_name = NULL;
+ char *clkname, *parent_name;
+ struct clknode_init_def *zynqclk;
+ int i;
+
+ for (i = 0; i < ZYNQMP_MAX_NODES; i++) {
+ /* Bail early if we have no node */
+ if (ZYNQMP_GET_NODE_TYPE(clkdef->topology[i]) == CLK_NODE_TYPE_NULL)
+ break;
+ zynqclk = malloc(sizeof(*zynqclk), M_DEVBUF, M_WAITOK | M_ZERO);
+ zynqclk->id = clkdef->clkdef.id;
+ /* For the first node in the topology we use the main clock parents */
+ if (i == 0) {
+ zynqclk->parent_cnt = clkdef->clkdef.parent_cnt;
+ zynqclk->parent_names = clkdef->clkdef.parent_names;
+ } else {
+ zynqclk->parent_cnt = 1;
+ zynqclk->parent_names = malloc(sizeof(char *) * zynqclk->parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
+ parent_name = strdup(prev_clock_name, M_DEVBUF);
+ zynqclk->parent_names[0] = (const char *)parent_name;
+ }
+ /* Register the clock node based on the topology type */
+ switch (ZYNQMP_GET_NODE_TYPE(clkdef->topology[i])) {
+ case CLK_NODE_TYPE_MUX:
+ asprintf(&clkname, M_DEVBUF, "%s_mux", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_mux_register(clkdom, fw, zynqclk);
+ break;
+ case CLK_NODE_TYPE_PLL:
+ asprintf(&clkname, M_DEVBUF, "%s_pll", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_pll_register(clkdom, fw, zynqclk);
+ break;
+ case CLK_NODE_TYPE_FIXED:
+ asprintf(&clkname, M_DEVBUF, "%s_fixed", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_fixed_register(clkdom, fw, zynqclk);
+ break;
+ case CLK_NODE_TYPE_DIV0:
+ asprintf(&clkname, M_DEVBUF, "%s_div0", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_div_register(clkdom, fw, zynqclk, CLK_DIV_TYPE_DIV0);
+ break;
+ case CLK_NODE_TYPE_DIV1:
+ asprintf(&clkname, M_DEVBUF, "%s_div1", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_div_register(clkdom, fw, zynqclk, CLK_DIV_TYPE_DIV1);
+ break;
+ case CLK_NODE_TYPE_GATE:
+ asprintf(&clkname, M_DEVBUF, "%s_gate", clkdef->clkdef.name);
+ zynqclk->name = (const char *)clkname;
+ zynqmp_clk_gate_register(clkdom, fw, zynqclk);
+ break;
+ case CLK_NODE_TYPE_NULL:
+ default:
+ clkname = NULL;
+ break;
+ }
+ if (i != 0) {
+ free(parent_name, M_DEVBUF);
+ free(zynqclk->parent_names, M_DEVBUF);
+ }
+ if (clkname != NULL)
+ prev_clock_name = strdup(clkname, M_DEVBUF);
+ free(clkname, M_DEVBUF);
+ free(zynqclk, M_DEVBUF);
+ }
+
+ /* Register main clock */
+ clkdef->clkdef.name = clkdef->clkdef.name;
+ clkdef->clkdef.parent_cnt = 1;
+ clkdef->clkdef.parent_names = malloc(sizeof(char *) * clkdef->clkdef.parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
+ clkdef->clkdef.parent_names[0] = strdup(prev_clock_name, M_DEVBUF);
+ clknode = clknode_create(clkdom, &zynqmp_clk_clknode_class, &clkdef->clkdef);
+ if (clknode == NULL)
+ return (1);
+ sc = clknode_get_softc(clknode);
+ sc->id = clkdef->clkdef.id - 1;
+ sc->firmware = fw;
+ sc->clk = clkdef;
+ clknode_register(clkdom, clknode);
+ return (0);
+}
+
+static int
+zynqmp_fw_clk_get_name(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
+{
+ char *clkname;
+ uint32_t query_data[4];
+ int rv;
+
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_NAME, id, 0, 0, query_data);
+ if (rv != 0)
+ return (rv);
+ if (query_data[0] == '\0')
+ return (EINVAL);
+ clkname = malloc(ZYNQMP_MAX_NAME_LEN, M_DEVBUF, M_ZERO | M_WAITOK);
+ memcpy(clkname, query_data, ZYNQMP_MAX_NAME_LEN);
+ clk->clkdef.name = clkname;
+ return (0);
+}
+
+static int
+zynqmp_fw_clk_get_attributes(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
+{
+ uint32_t query_data[4];
+ int rv;
+
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_ATTRIBUTES, id, 0, 0, query_data);
+ if (rv != 0)
+ return (rv);
+ clk->attributes = query_data[1];
+ return (0);
+}
+
+static int
+zynqmp_fw_clk_get_parents(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
+{
+ int rv, i;
+ uint32_t query_data[4];
+
+ for (i = 0; i < ZYNQMP_MAX_PARENTS; i += 3) {
+ clk->parentids[i] = -1;
+ clk->parentids[i + 1] = -1;
+ clk->parentids[i + 2] = -1;
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_PARENTS, id, i, 0, query_data);
+ clk->parentids[i] = query_data[1] & 0xFFFF;
+ clk->parentids[i + 1] = query_data[2] & 0xFFFF;
+ clk->parentids[i + 2] = query_data[3] & 0xFFFF;
+ if ((int32_t)query_data[1] == -1) {
+ clk->parentids[i] = -1;
+ break;
+ }
+ clk->parentids[i] += 1;
+ clk->clkdef.parent_cnt++;
+ if ((int32_t)query_data[2] == -1) {
+ clk->parentids[i + 1] = -1;
+ break;
+ }
+ clk->parentids[i + 1] += 1;
+ clk->clkdef.parent_cnt++;
+ if ((int32_t)query_data[3] == -1) {
+ clk->parentids[i + 2] = -1;
+ break;
+ }
+ clk->parentids[i + 2] += 1;
+ clk->clkdef.parent_cnt++;
+ if ((int32_t)query_data[1] == -2)
+ clk->parentids[i] = -2;
+ if ((int32_t)query_data[2] == -2)
+ clk->parentids[i + 1] = -2;
+ if ((int32_t)query_data[3] == -2)
+ clk->parentids[i + 2] = -2;
+ if (rv != 0)
+ break;
+ }
+ return (0);
+}
+
+static int
+zynqmp_fw_clk_get_topology(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
+{
+ uint32_t query_data[4];
+ int rv;
+
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_TOPOLOGY, id, 0, 0, query_data);
+ if (rv != 0)
+ return (rv);
+ clk->topology[0] = query_data[1];
+ clk->topology[1] = query_data[2];
+ clk->topology[2] = query_data[3];
+ if (query_data[3] == '\0')
+ goto out;
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_TOPOLOGY, id, 3, 0, query_data);
+ if (rv != 0)
+ return (rv);
+ clk->topology[3] = query_data[1];
+ clk->topology[4] = query_data[2];
+ clk->topology[5] = query_data[3];
+
+out:
+ return (0);
+}
+
+static int
+zynqmp_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells,
+ phandle_t *cells, struct clknode **clk)
+{
+
+ if (ncells != 1)
+ return (ERANGE);
+ *clk = clknode_find_by_id(clkdom, ZYNQMP_ID_TO_CLK(cells[0]));
+ if (*clk == NULL)
+ return (ENXIO);
+ return (0);
+}
+
+static int
+zynqmp_fw_clk_get_all(struct zynqmp_clock_softc *sc)
+{
+ TAILQ_HEAD(tailhead, zynqmp_clk) clk_list;
+ struct zynqmp_clk *clk, *tmp, *tmp2;
+ char *clkname;
+ int rv, i;
+ uint32_t query_data[4], num_clock;
+
+ TAILQ_INIT(&clk_list);
+ rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent,
+ PM_QID_CLOCK_GET_NUM_CLOCKS,
+ 0,
+ 0,
+ 0,
+ query_data);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get clock details from the firmware\n");
+ return (ENXIO);
+ }
+
+ num_clock = query_data[1];
+ for (i = 0; i < num_clock; i++) {
+ clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK | M_ZERO);
+ clk->clkdef.id = ZYNQMP_ID_TO_CLK(i);
+ zynqmp_fw_clk_get_name(sc, clk, i);
+ zynqmp_fw_clk_get_attributes(sc, clk, i);
+ if ((clk->attributes & ZYNQMP_CLK_IS_VALID) == 0) {
+ free(clk, M_DEVBUF);
+ continue;
+ }
+ if (clk->attributes & ZYNQMP_CLK_IS_EXT)
+ goto skip_ext;
+ /* Get parents id */
+ rv = zynqmp_fw_clk_get_parents(sc, clk, i);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get parent for %s\n", clk->clkdef.name);
+ free(clk, M_DEVBUF);
+ continue;
+ }
+ /* Get topology */
+ rv = zynqmp_fw_clk_get_topology(sc, clk, i);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get topology for %s\n", clk->clkdef.name);
+ free(clk, M_DEVBUF);
+ continue;
+ }
+ skip_ext:
+ TAILQ_INSERT_TAIL(&clk_list, clk, next);
+ }
+
+ /* Add a dummy clock */
+ clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK | M_ZERO);
+ clkname = strdup("dummy", M_DEVBUF);
+ clk->clkdef.name = (const char *)clkname;
+ clk->clkdef.id = i;
+ clk->attributes = ZYNQMP_CLK_IS_EXT;
+ TAILQ_INSERT_TAIL(&clk_list, clk, next);
+
+ /* Map parents id to name */
+ TAILQ_FOREACH_SAFE(clk, &clk_list, next, tmp) {
+ if (clk->attributes & ZYNQMP_CLK_IS_EXT)
+ continue;
+ clk->clkdef.parent_names = malloc(sizeof(char *) * clk->clkdef.parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
+ for (i = 0; i < ZYNQMP_MAX_PARENTS; i++) {
+ if (clk->parentids[i] == -1)
+ break;
+ if (clk->parentids[i] == -2) {
+ clk->clkdef.parent_names[i] = strdup("dummy", M_DEVBUF);
+ continue;
+ }
+ TAILQ_FOREACH(tmp2, &clk_list, next) {
+ if (tmp2->clkdef.id == clk->parentids[i]) {
+ if (tmp2->attributes & ZYNQMP_CLK_IS_EXT) {
+ int idx;
+
+ if (ofw_bus_find_string_index( sc->node,
+ "clock-names", tmp2->clkdef.name, &idx) == ENOENT)
+ clk->clkdef.parent_names[i] = strdup("dummy", M_DEVBUF);
+ else
+ clk->clkdef.parent_names[i] = strdup(tmp2->clkdef.name, M_DEVBUF);
+ }
+ else
+ clk->clkdef.parent_names[i] = strdup(tmp2->clkdef.name, M_DEVBUF);
+ break;
+ }
+ }
+ }
+ }
+
+ sc->clkdom = clkdom_create(sc->dev);
+ if (sc->clkdom == NULL)
+ panic("Cannot create clkdom\n");
+ clkdom_set_ofw_mapper(sc->clkdom, zynqmp_clock_ofw_map);
+
+ /* Register the clocks */
+ TAILQ_FOREACH_SAFE(clk, &clk_list, next, tmp) {
+ if (clk->attributes & ZYNQMP_CLK_IS_EXT) {
+ if (strcmp(clk->clkdef.name, "dummy") == 0) {
+ struct clk_fixed_def dummy;
+
+ bzero(&dummy, sizeof(dummy));
+ dummy.clkdef.id = clk->clkdef.id;
+ dummy.clkdef.name = strdup("dummy", M_DEVBUF);
+ clknode_fixed_register(sc->clkdom, &dummy);
+ free(__DECONST(char *, dummy.clkdef.name), M_DEVBUF);
+ }
+ } else
+ zynqmp_clk_register(sc->clkdom, sc->parent, clk);
+
+ TAILQ_REMOVE(&clk_list, clk, next);
+ for (i = 0; i < clk->clkdef.parent_cnt; i++)
+ free(__DECONST(char *, clk->clkdef.parent_names[i]), M_DEVBUF);
+ free(clk->clkdef.parent_names, M_DEVBUF);
+ free(__DECONST(char *, clk->clkdef.name), M_DEVBUF);
+ free(clk, M_DEVBUF);
+ }
+
+ if (clkdom_finit(sc->clkdom) != 0)
+ panic("cannot finalize clkdom initialization\n");
+
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+
+ return (0);
+}
+
+static int
+zynqmp_clock_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-clk"))
+ return (ENXIO);
+ device_set_desc(dev, "ZynqMP Clock Controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+zynqmp_clock_attach(device_t dev)
+{
+ struct zynqmp_clock_softc *sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->parent = device_get_parent(dev);
+ sc->node = ofw_bus_get_node(dev);
+
+ /* Enable all clocks */
+ if (clk_get_by_ofw_name(dev, 0, "pss_ref_clk", &sc->clk_pss_ref) != 0) {
+ device_printf(dev, "Cannot get pss_ref_clk clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_pss_ref);
+ if (rv != 0) {
+ device_printf(dev, "Could not enable clock pss_ref_clk\n");
+ return (ENXIO);
+ }
+ if (clk_get_by_ofw_name(dev, 0, "video_clk", &sc->clk_video) != 0) {
+ device_printf(dev, "Cannot get video_clk clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_video);
+ if (rv != 0) {
+ device_printf(dev, "Could not enable clock video_clk\n");
+ return (ENXIO);
+ }
+ if (clk_get_by_ofw_name(dev, 0, "pss_alt_ref_clk", &sc->clk_pss_alt_ref) != 0) {
+ device_printf(dev, "Cannot get pss_alt_ref_clk clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_pss_alt_ref);
+ if (rv != 0) {
+ device_printf(dev, "Could not enable clock pss_alt_ref_clk\n");
+ return (ENXIO);
+ }
+ if (clk_get_by_ofw_name(dev, 0, "aux_ref_clk", &sc->clk_aux_ref) != 0) {
+ device_printf(dev, "Cannot get pss_aux_clk clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_aux_ref);
+ if (rv != 0) {
+ device_printf(dev, "Could not enable clock pss_aux_clk\n");
+ return (ENXIO);
+ }
+ if (clk_get_by_ofw_name(dev, 0, "gt_crx_ref_clk", &sc->clk_gt_crx_ref) != 0) {
+ device_printf(dev, "Cannot get gt_crx_ref_clk clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_gt_crx_ref);
+ if (rv != 0) {
+ device_printf(dev, "Could not enable clock gt_crx_ref_clk\n");
+ return (ENXIO);
+ }
+
+ rv = zynqmp_fw_clk_get_all(sc);
+ if (rv != 0) {
+ clk_disable(sc->clk_gt_crx_ref);
+ clk_disable(sc->clk_aux_ref);
+ clk_disable(sc->clk_pss_alt_ref);
+ clk_disable(sc->clk_video);
+ clk_disable(sc->clk_pss_ref);
+ return (rv);
+ }
+ return (0);
+}
+
+static device_method_t zynqmp_clock_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, zynqmp_clock_probe),
+ DEVMETHOD(device_attach, zynqmp_clock_attach),
+
+ DEVMETHOD_END
+};
+
+static driver_t zynqmp_clock_driver = {
+ "zynqmp_clock",
+ zynqmp_clock_methods,
+ sizeof(struct zynqmp_clock_softc),
+};
+
+EARLY_DRIVER_MODULE(zynqmp_clock, simplebus, zynqmp_clock_driver, 0, 0,
+ BUS_PASS_BUS + BUS_PASS_ORDER_LAST);
diff --git a/sys/dev/clk/xilinx/zynqmp_reset.c b/sys/dev/clk/xilinx/zynqmp_reset.c
new file mode 100644
index 000000000000..484f19c229c5
--- /dev/null
+++ b/sys/dev/clk/xilinx/zynqmp_reset.c
@@ -0,0 +1,253 @@
+/*-
+ * 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 <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/hwreset/hwreset.h>
+
+#include <dev/firmware/xilinx/pm_defs.h>
+
+#include "hwreset_if.h"
+#include "zynqmp_firmware_if.h"
+
+#define ZYNQMP_RESET_PCIE_CFG 0
+#define ZYNQMP_RESET_PCIE_BRIDGE 1
+#define ZYNQMP_RESET_PCIE_CTRL 2
+#define ZYNQMP_RESET_DP 3
+#define ZYNQMP_RESET_SWDT_CRF 4
+#define ZYNQMP_RESET_AFI_FM5 5
+#define ZYNQMP_RESET_AFI_FM4 6
+#define ZYNQMP_RESET_AFI_FM3 7
+#define ZYNQMP_RESET_AFI_FM2 8
+#define ZYNQMP_RESET_AFI_FM1 9
+#define ZYNQMP_RESET_AFI_FM0 10
+#define ZYNQMP_RESET_GDMA 11
+#define ZYNQMP_RESET_GPU_PP1 12
+#define ZYNQMP_RESET_GPU_PP0 13
+#define ZYNQMP_RESET_GPU 14
+#define ZYNQMP_RESET_GT 15
+#define ZYNQMP_RESET_SATA 16
+#define ZYNQMP_RESET_ACPU3_PWRON 17
+#define ZYNQMP_RESET_ACPU2_PWRON 18
+#define ZYNQMP_RESET_ACPU1_PWRON 19
+#define ZYNQMP_RESET_ACPU0_PWRON 20
+#define ZYNQMP_RESET_APU_L2 21
+#define ZYNQMP_RESET_ACPU3 22
+#define ZYNQMP_RESET_ACPU2 23
+#define ZYNQMP_RESET_ACPU1 24
+#define ZYNQMP_RESET_ACPU0 25
+#define ZYNQMP_RESET_DDR 26
+#define ZYNQMP_RESET_APM_FPD 27
+#define ZYNQMP_RESET_SOFT 28
+#define ZYNQMP_RESET_GEM0 29
+#define ZYNQMP_RESET_GEM1 30
+#define ZYNQMP_RESET_GEM2 31
+#define ZYNQMP_RESET_GEM3 32
+#define ZYNQMP_RESET_QSPI 33
+#define ZYNQMP_RESET_UART0 34
+#define ZYNQMP_RESET_UART1 35
+#define ZYNQMP_RESET_SPI0 36
+#define ZYNQMP_RESET_SPI1 37
+#define ZYNQMP_RESET_SDIO0 38
+#define ZYNQMP_RESET_SDIO1 39
+#define ZYNQMP_RESET_CAN0 40
+#define ZYNQMP_RESET_CAN1 41
+#define ZYNQMP_RESET_I2C0 42
+#define ZYNQMP_RESET_I2C1 43
+#define ZYNQMP_RESET_TTC0 44
+#define ZYNQMP_RESET_TTC1 45
+#define ZYNQMP_RESET_TTC2 46
+#define ZYNQMP_RESET_TTC3 47
+#define ZYNQMP_RESET_SWDT_CRL 48
+#define ZYNQMP_RESET_NAND 49
+#define ZYNQMP_RESET_ADMA 50
+#define ZYNQMP_RESET_GPIO 51
+#define ZYNQMP_RESET_IOU_CC 52
+#define ZYNQMP_RESET_TIMESTAMP 53
+#define ZYNQMP_RESET_RPU_R50 54
+#define ZYNQMP_RESET_RPU_R51 55
+#define ZYNQMP_RESET_RPU_AMBA 56
+#define ZYNQMP_RESET_OCM 57
+#define ZYNQMP_RESET_RPU_PGE 58
+#define ZYNQMP_RESET_USB0_CORERESET 59
+#define ZYNQMP_RESET_USB1_CORERESET 60
+#define ZYNQMP_RESET_USB0_HIBERRESET 61
+#define ZYNQMP_RESET_USB1_HIBERRESET 62
+#define ZYNQMP_RESET_USB0_APB 63
+#define ZYNQMP_RESET_USB1_APB 64
+#define ZYNQMP_RESET_IPI 65
+#define ZYNQMP_RESET_APM_LPD 66
+#define ZYNQMP_RESET_RTC 67
+#define ZYNQMP_RESET_SYSMON 68
+#define ZYNQMP_RESET_AFI_FM6 69
+#define ZYNQMP_RESET_LPD_SWDT 70
+#define ZYNQMP_RESET_FPD 71
+#define ZYNQMP_RESET_RPU_DBG1 72
+#define ZYNQMP_RESET_RPU_DBG0 73
+#define ZYNQMP_RESET_DBG_LPD 74
+#define ZYNQMP_RESET_DBG_FPD 75
+#define ZYNQMP_RESET_APLL 76
+#define ZYNQMP_RESET_DPLL 77
+#define ZYNQMP_RESET_VPLL 78
+#define ZYNQMP_RESET_IOPLL 79
+#define ZYNQMP_RESET_RPLL 80
+#define ZYNQMP_RESET_GPO3_PL_0 81
+#define ZYNQMP_RESET_GPO3_PL_1 82
+#define ZYNQMP_RESET_GPO3_PL_2 83
+#define ZYNQMP_RESET_GPO3_PL_3 84
+#define ZYNQMP_RESET_GPO3_PL_4 85
+#define ZYNQMP_RESET_GPO3_PL_5 86
+#define ZYNQMP_RESET_GPO3_PL_6 87
+#define ZYNQMP_RESET_GPO3_PL_7 88
+#define ZYNQMP_RESET_GPO3_PL_8 89
+#define ZYNQMP_RESET_GPO3_PL_9 90
+#define ZYNQMP_RESET_GPO3_PL_10 91
+#define ZYNQMP_RESET_GPO3_PL_11 92
+#define ZYNQMP_RESET_GPO3_PL_12 93
+#define ZYNQMP_RESET_GPO3_PL_13 94
+#define ZYNQMP_RESET_GPO3_PL_14 95
+#define ZYNQMP_RESET_GPO3_PL_15 96
+#define ZYNQMP_RESET_GPO3_PL_16 97
+#define ZYNQMP_RESET_GPO3_PL_17 98
+#define ZYNQMP_RESET_GPO3_PL_18 99
+#define ZYNQMP_RESET_GPO3_PL_19 100
+#define ZYNQMP_RESET_GPO3_PL_20 101
+#define ZYNQMP_RESET_GPO3_PL_21 102
+#define ZYNQMP_RESET_GPO3_PL_22 103
+#define ZYNQMP_RESET_GPO3_PL_23 104
+#define ZYNQMP_RESET_GPO3_PL_24 105
+#define ZYNQMP_RESET_GPO3_PL_25 106
+#define ZYNQMP_RESET_GPO3_PL_26 107
+#define ZYNQMP_RESET_GPO3_PL_27 108
+#define ZYNQMP_RESET_GPO3_PL_28 109
+#define ZYNQMP_RESET_GPO3_PL_29 110
+#define ZYNQMP_RESET_GPO3_PL_30 111
+#define ZYNQMP_RESET_GPO3_PL_31 112
+#define ZYNQMP_RESET_RPU_LS 113
+#define ZYNQMP_RESET_PS_ONLY 114
+#define ZYNQMP_RESET_PL 115
+#define ZYNQMP_RESET_PS_PL0 116
+#define ZYNQMP_RESET_PS_PL1 117
+#define ZYNQMP_RESET_PS_PL2 118
+#define ZYNQMP_RESET_PS_PL3 119
+#define ZYNQMP_RESET_MAX ZYNQMP_RESET_PS_PL3
+
+struct zynqmp_reset_softc {
+ device_t dev;
+ device_t parent;
+};
+
+static int
+zynqmp_reset_assert(device_t dev, intptr_t id, bool reset)
+{
+ struct zynqmp_reset_softc *sc;
+ int rv;
+
+ if (id > ZYNQMP_RESET_MAX)
+ return (EINVAL);
+ sc = device_get_softc(dev);
+ device_printf(dev, "%s called for id = %ld, reset =%d\n", __func__, id, reset);
+ rv = ZYNQMP_FIRMWARE_RESET_ASSERT(sc->parent, id, reset);
+ return (rv);
+}
+
+static int
+zynqmp_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
+{
+ struct zynqmp_reset_softc *sc;
+ int rv;
+
+ if (id > ZYNQMP_RESET_MAX)
+ return (EINVAL);
+ sc = device_get_softc(dev);
+ device_printf(dev, "%s called for id = %ld\n", __func__, id);
+ rv = ZYNQMP_FIRMWARE_RESET_GET_STATUS(sc->parent, id, reset);
+
+ return (rv);
+}
+
+static int
+zynqmp_reset_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-reset"))
+ return (ENXIO);
+ device_set_desc(dev, "ZynqMP Reset Controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+zynqmp_reset_attach(device_t dev)
+{
+ struct zynqmp_reset_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->parent = device_get_parent(dev);
+
+ /* register our self as a reset provider */
+ hwreset_register_ofw_provider(dev);
+
+ return (0);
+}
+
+static device_method_t zynqmp_reset_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, zynqmp_reset_probe),
+ DEVMETHOD(device_attach, zynqmp_reset_attach),
+
+ /* Reset interface */
+ DEVMETHOD(hwreset_assert, zynqmp_reset_assert),
+ DEVMETHOD(hwreset_is_asserted, zynqmp_reset_is_asserted),
+
+ DEVMETHOD_END
+};
+
+static driver_t zynqmp_reset_driver = {
+ "zynqmp_reset",
+ zynqmp_reset_methods,
+ sizeof(struct zynqmp_reset_softc),
+};
+
+EARLY_DRIVER_MODULE(zynqmp_reset, simplebus, zynqmp_reset_driver, 0, 0,
+ BUS_PASS_BUS + BUS_PASS_ORDER_LAST);