On Mon, Apr 26, 2021 at 05:25:18PM +0200, Mark Kettenis wrote:
> > Date: Mon, 26 Apr 2021 14:19:38 +0000
> > From: Visa Hankala <[email protected]>
> >
> > The following diff adds a preliminary driver for the system-level
> > control registers of Xilinx Zynq-7000. It enables system reset. It also
> > adds clock bits for use with the SDIO and Gigabit Ethernet controllers.
> >
> > On some arm64 and armv7 platforms, there are separate drivers for clocks
> > and resets. However, on Zynq-7000 it looks more natural to use a single
> > driver. Below is an outline of the relevant part of the device tree:
> >
> > slcr: slcr@f8000000 {
> > #address-cells = <1>;
> > #size-cells = <1>;
> > compatible = "xlnx,zynq-slcr", "syscon",
> > "simple-mfd";
> > reg = <0xF8000000 0x1000>;
> > ranges;
> > clkc: clkc@100 {
> > #clock-cells = <1>;
> > compatible = "xlnx,ps7-clkc";
> > fclk-enable = <0>;
> > clock-output-names = "armpll", "ddrpll",
> > ...;
> > reg = <0x100 0x100>;
> > };
> >
> >
> > rstc: rstc@200 {
> > compatible = "xlnx,zynq-reset";
> > reg = <0x200 0x48>;
> > #reset-cells = <1>;
> > syscon = <&slcr>;
> > };
> >
> > pinctrl0: pinctrl@700 {
> > compatible = "xlnx,pinctrl-zynq";
> > reg = <0x700 0x200>;
> > syscon = <&slcr>;
> > };
> > };
> >
> > OK?
>
> Hmm, I'm not sure. Your driver doesn't provide pinctrl support. I'm
> not sure how much code you'd need for that, but if it is a significant
> amount of code, having separate clock and pinctrl drivers would make
> sense.
I see, adding pinctrl logic would be easier if clocks and resets were
handled in separate drivers. I have now reorganized the code to reflect
this.
Both the clock and reset drivers access the control registers by using
common routines. I have put them in the reset driver file. However,
if this looks too ugly, I can add them in a separate .c file.
The use of the mutex might be overzealous. The main point is to prevent
accidental interleaving when lifting the write protection for register
update.
OK?
Index: share/man/man4/man4.armv7/Makefile
===================================================================
RCS file: src/share/man/man4/man4.armv7/Makefile,v
retrieving revision 1.28
diff -u -p -r1.28 Makefile
--- share/man/man4/man4.armv7/Makefile 10 Apr 2020 22:26:46 -0000 1.28
+++ share/man/man4/man4.armv7/Makefile 27 Apr 2021 12:42:20 -0000
@@ -6,7 +6,7 @@ MAN= agtimer.4 amdisplay.4 ampintc.4 amp
omap.4 omclock.4 omcm.4 omdog.4 omgpio.4 ommmc.4 omrng.4 omsysc.4 \
omwugen.4 prcm.4 \
sxie.4 sxiintc.4 \
- sxitimer.4 sxits.4 sysreg.4
+ sxitimer.4 sxits.4 sysreg.4 zqclock.4 zqreset.4
MANSUBDIR=armv7
Index: share/man/man4/man4.armv7/zqclock.4
===================================================================
RCS file: share/man/man4/man4.armv7/zqclock.4
diff -N share/man/man4/man4.armv7/zqclock.4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ share/man/man4/man4.armv7/zqclock.4 27 Apr 2021 12:42:20 -0000
@@ -0,0 +1,37 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2021 Visa Hankala
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt ZQCLOCK 4
+.Os
+.Sh NAME
+.Nm zqclock
+.Nd Xilinx Zynq-7000 clock controller
+.Sh SYNOPSIS
+.Cd "zqclock* at fdt?"
+.Sh DESCRIPTION
+The
+.Nm
+driver controls the clock signals for the integrated components
+of Zynq-7000 SoCs.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr zqreset 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 7.0 .
Index: share/man/man4/man4.armv7/zqreset.4
===================================================================
RCS file: share/man/man4/man4.armv7/zqreset.4
diff -N share/man/man4/man4.armv7/zqreset.4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ share/man/man4/man4.armv7/zqreset.4 27 Apr 2021 12:42:20 -0000
@@ -0,0 +1,37 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2021 Visa Hankala
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt ZQRESET 4
+.Os
+.Sh NAME
+.Nm zqreset
+.Nd Xilinx Zynq-7000 reset controller
+.Sh SYNOPSIS
+.Cd "zqreset* at fdt?"
+.Sh DESCRIPTION
+The
+.Nm
+driver controls the reset signals for the integrated components
+of Zynq-7000 SoCs.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr zqclock 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 7.0 .
Index: sys/arch/armv7/conf/GENERIC
===================================================================
RCS file: src/sys/arch/armv7/conf/GENERIC,v
retrieving revision 1.135
diff -u -p -r1.135 GENERIC
--- sys/arch/armv7/conf/GENERIC 24 Apr 2021 07:49:11 -0000 1.135
+++ sys/arch/armv7/conf/GENERIC 27 Apr 2021 12:42:21 -0000
@@ -213,6 +213,8 @@ dwdog* at fdt?
# Xilinx Zynq-7000
cduart* at fdt?
+zqclock* at fdt?
+zqreset* at fdt?
# I2C devices
abcrtc* at iic? # Abracon x80x RTC
Index: sys/arch/armv7/conf/RAMDISK
===================================================================
RCS file: src/sys/arch/armv7/conf/RAMDISK,v
retrieving revision 1.121
diff -u -p -r1.121 RAMDISK
--- sys/arch/armv7/conf/RAMDISK 24 Apr 2021 07:49:11 -0000 1.121
+++ sys/arch/armv7/conf/RAMDISK 27 Apr 2021 12:42:21 -0000
@@ -198,6 +198,8 @@ dwdog* at fdt?
# Xilinx Zynq-7000
cduart* at fdt?
+zqclock* at fdt?
+zqreset* at fdt?
axppmic* at iic? # axp209 pmic
crosec* at iic?
Index: sys/arch/armv7/conf/files.armv7
===================================================================
RCS file: src/sys/arch/armv7/conf/files.armv7,v
retrieving revision 1.37
diff -u -p -r1.37 files.armv7
--- sys/arch/armv7/conf/files.armv7 5 Jun 2018 20:41:19 -0000 1.37
+++ sys/arch/armv7/conf/files.armv7 27 Apr 2021 12:42:21 -0000
@@ -75,3 +75,4 @@ include "arch/armv7/exynos/files.exynos"
include "arch/armv7/vexpress/files.vexpress"
include "arch/armv7/broadcom/files.broadcom"
include "arch/armv7/marvell/files.marvell"
+include "arch/armv7/xilinx/files.xilinx"
Index: sys/arch/armv7/xilinx/files.xilinx
===================================================================
RCS file: sys/arch/armv7/xilinx/files.xilinx
diff -N sys/arch/armv7/xilinx/files.xilinx
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/armv7/xilinx/files.xilinx 27 Apr 2021 12:42:21 -0000
@@ -0,0 +1,9 @@
+# $OpenBSD$
+
+device zqclock
+attach zqclock at fdt
+file arch/armv7/xilinx/zqclock.c zqclock
+
+device zqreset
+attach zqreset at fdt
+file arch/armv7/xilinx/zqreset.c zqreset
Index: sys/arch/armv7/xilinx/slcreg.h
===================================================================
RCS file: sys/arch/armv7/xilinx/slcreg.h
diff -N sys/arch/armv7/xilinx/slcreg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/armv7/xilinx/slcreg.h 27 Apr 2021 12:42:21 -0000
@@ -0,0 +1,49 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2021 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define SLCR_LOCK 0x0004
+#define SLCR_LOCK_KEY 0x767b
+#define SLCR_UNLOCK 0x0008
+#define SLCR_UNLOCK_KEY 0xdf0d
+#define SLCR_ARM_PLL_CTRL 0x0100
+#define SLCR_DDR_PLL_CTRL 0x0104
+#define SLCR_IO_PLL_CTRL 0x0108
+#define SLCR_PLL_CTRL_FDIV_MASK 0x7f
+#define SLCR_PLL_CTRL_FDIV_SHIFT 12
+#define SLCR_GEM0_CLK_CTRL 0x0140
+#define SLCR_GEM1_CLK_CTRL 0x0144
+#define SLCR_SDIO_CLK_CTRL 0x0150
+#define SLCR_UART_CLK_CTRL 0x0154
+#define SLCR_CLK_CTRL_DIVISOR1(x) (((x) >> 20) & 0x3f)
+#define SLCR_CLK_CTRL_DIVISOR1_SHIFT 20
+#define SLCR_CLK_CTRL_DIVISOR(x) (((x) >> 8) & 0x3f)
+#define SLCR_CLK_CTRL_DIVISOR_SHIFT 8
+#define SLCR_CLK_CTRL_SRCSEL_MASK (0x7 << 4)
+#define SLCR_CLK_CTRL_SRCSEL_DDR (0x3 << 4)
+#define SLCR_CLK_CTRL_SRCSEL_ARM (0x2 << 4)
+#define SLCR_CLK_CTRL_SRCSEL_IO (0x1 << 4)
+#define SLCR_CLK_CTRL_CLKACT(i) (0x1 << (i))
+#define SLCR_PSS_RST_CTRL 0x0200
+#define SLCR_PSS_RST_CTRL_SOFT_RST (1 << 0)
+
+#define SLCR_DIV_MASK 0x3f
+
+extern struct mutex zynq_slcr_lock;
+
+uint32_t zynq_slcr_read(struct regmap *, uint32_t);
+void zynq_slcr_write(struct regmap *, uint32_t, uint32_t);
Index: sys/arch/armv7/xilinx/zqclock.c
===================================================================
RCS file: sys/arch/armv7/xilinx/zqclock.c
diff -N sys/arch/armv7/xilinx/zqclock.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/armv7/xilinx/zqclock.c 27 Apr 2021 12:42:21 -0000
@@ -0,0 +1,316 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2021 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Driver for Xilinx Zynq-7000 clock controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_clock.h>
+#include <dev/ofw/ofw_misc.h>
+
+#include <armv7/xilinx/slcreg.h>
+
+#define CLK_ARM_PLL 0
+#define CLK_DDR_PLL 1
+#define CLK_IO_PLL 2
+#define CLK_CPU_6OR4X 3
+#define CLK_CPU_3OR2X 4
+#define CLK_CPU_2X 5
+#define CLK_CPU_1X 6
+#define CLK_DDR_2X 7
+#define CLK_DDR_3X 8
+#define CLK_DCI 9
+#define CLK_LQSPI 10
+#define CLK_SMC 11
+#define CLK_PCAP 12
+#define CLK_GEM0 13
+#define CLK_GEM1 14
+#define CLK_FCLK0 15
+#define CLK_FCLK1 16
+#define CLK_FCLK2 17
+#define CLK_FCLK3 18
+#define CLK_CAN0 19
+#define CLK_CAN1 20
+#define CLK_SDIO0 21
+#define CLK_SDIO1 22
+#define CLK_UART0 23
+#define CLK_UART1 24
+#define CLK_SPI0 25
+#define CLK_SPI1 26
+#define CLK_DMA 27
+
+struct zqclock_softc {
+ struct device sc_dev;
+ struct regmap *sc_rm;
+
+ struct clock_device sc_cd;
+ uint32_t sc_psclk_freq; /* in Hz */
+};
+
+int zqclock_match(struct device *, void *, void *);
+void zqclock_attach(struct device *, struct device *, void *);
+
+void zqclock_enable(void *, uint32_t *, int);
+uint32_t zqclock_get_frequency(void *, uint32_t *);
+int zqclock_set_frequency(void *, uint32_t *, uint32_t);
+
+const struct cfattach zqclock_ca = {
+ sizeof(struct zqclock_softc), zqclock_match, zqclock_attach
+};
+
+struct cfdriver zqclock_cd = {
+ NULL, "zqclock", DV_DULL
+};
+
+struct zqclock_clock {
+ uint16_t clk_ctl_reg;
+ uint8_t clk_has_div1;
+ uint8_t clk_index;
+};
+
+const struct zqclock_clock zqclock_clocks[] = {
+ [CLK_GEM0] = { SLCR_GEM0_CLK_CTRL, 1, 0 },
+ [CLK_GEM1] = { SLCR_GEM1_CLK_CTRL, 1, 0 },
+ [CLK_SDIO0] = { SLCR_SDIO_CLK_CTRL, 0, 0 },
+ [CLK_SDIO1] = { SLCR_SDIO_CLK_CTRL, 0, 1 },
+ [CLK_UART0] = { SLCR_UART_CLK_CTRL, 0, 0 },
+ [CLK_UART1] = { SLCR_UART_CLK_CTRL, 0, 1 },
+};
+
+int
+zqclock_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "xlnx,ps7-clkc");
+}
+
+void
+zqclock_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ struct zqclock_softc *sc = (struct zqclock_softc *)self;
+
+ sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
+ if (sc->sc_rm == NULL) {
+ printf(": can't get regmap\n");
+ return;
+ }
+
+ sc->sc_psclk_freq = OF_getpropint(faa->fa_node, "ps-clk-frequency",
+ 33333333);
+
+ printf(": %u MHz PS clock\n", (sc->sc_psclk_freq + 500000) / 1000000);
+
+ sc->sc_cd.cd_node = faa->fa_node;
+ sc->sc_cd.cd_cookie = sc;
+ sc->sc_cd.cd_enable = zqclock_enable;
+ sc->sc_cd.cd_get_frequency = zqclock_get_frequency;
+ sc->sc_cd.cd_set_frequency = zqclock_set_frequency;
+ clock_register(&sc->sc_cd);
+}
+
+const struct zqclock_clock *
+zqclock_get_clock(uint32_t idx)
+{
+ const struct zqclock_clock *clock;
+
+ if (idx >= nitems(zqclock_clocks))
+ return NULL;
+
+ clock = &zqclock_clocks[idx];
+ if (clock->clk_ctl_reg == 0)
+ return NULL;
+
+ return clock;
+}
+
+uint32_t
+zqclock_get_pll_frequency(struct zqclock_softc *sc, uint32_t clk_ctrl)
+{
+ uint32_t reg, val;
+
+ switch (clk_ctrl & SLCR_CLK_CTRL_SRCSEL_MASK) {
+ case SLCR_CLK_CTRL_SRCSEL_ARM:
+ reg = SLCR_ARM_PLL_CTRL;
+ break;
+ case SLCR_CLK_CTRL_SRCSEL_DDR:
+ reg = SLCR_DDR_PLL_CTRL;
+ break;
+ default:
+ reg = SLCR_IO_PLL_CTRL;
+ break;
+ }
+
+ val = zynq_slcr_read(sc->sc_rm, reg);
+ return sc->sc_psclk_freq * ((val >> SLCR_PLL_CTRL_FDIV_SHIFT) &
+ SLCR_PLL_CTRL_FDIV_MASK);
+}
+
+uint32_t
+zqclock_get_frequency(void *cookie, uint32_t *cells)
+{
+ const struct zqclock_clock *clock;
+ struct zqclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+ uint32_t ctl, div, freq;
+
+ clock = zqclock_get_clock(idx);
+ if (clock == NULL)
+ return 0;
+
+ mtx_enter(&zynq_slcr_lock);
+
+ ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
+
+ div = SLCR_CLK_CTRL_DIVISOR(ctl);
+ if (clock->clk_has_div1)
+ div *= SLCR_CLK_CTRL_DIVISOR1(ctl);
+
+ freq = zqclock_get_pll_frequency(sc, ctl);
+ freq = (freq + div / 2) / div;
+
+ mtx_leave(&zynq_slcr_lock);
+
+ return freq;
+}
+
+int
+zqclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
+{
+ static const uint32_t srcsels[] = {
+ SLCR_CLK_CTRL_SRCSEL_IO,
+ SLCR_CLK_CTRL_SRCSEL_ARM,
+ SLCR_CLK_CTRL_SRCSEL_DDR,
+ };
+ const struct zqclock_clock *clock;
+ struct zqclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+ uint32_t best_delta = ~0U;
+ uint32_t best_div1 = 0;
+ uint32_t best_si = 0;
+ uint32_t best_pllf = 0;
+ uint32_t ctl, div, div1, maxdiv1, si;
+ int error = 0;
+
+ clock = zqclock_get_clock(idx);
+ if (clock == NULL)
+ return EINVAL;
+
+ if (freq == 0)
+ return EINVAL;
+
+ mtx_enter(&zynq_slcr_lock);
+
+ maxdiv1 = 1;
+ if (clock->clk_has_div1)
+ maxdiv1 = SLCR_DIV_MASK;
+
+ /* Find PLL and divisors that give best frequency. */
+ for (si = 0; si < nitems(srcsels); si++) {
+ uint32_t delta, f, pllf;
+
+ pllf = zqclock_get_pll_frequency(sc, srcsels[si]);
+ if (freq > pllf)
+ continue;
+
+ for (div1 = 1; div1 <= maxdiv1; div1++) {
+ div = (pllf + (freq * div1 / 2)) / (freq * div1);
+ if (div > SLCR_DIV_MASK)
+ continue;
+ if (div == 0)
+ break;
+
+ f = (pllf + (div * div1 / 2)) / (div * div1);
+ delta = abs(f - freq);
+ if (best_div1 == 0 || delta < best_delta) {
+ best_delta = delta;
+ best_div1 = div1;
+ best_pllf = pllf;
+ best_si = si;
+
+ if (delta == 0)
+ goto found;
+ }
+ }
+ }
+
+ if (best_div1 == 0) {
+ error = EINVAL;
+ goto out;
+ }
+
+found:
+ div1 = best_div1;
+ div = (best_pllf + (freq * div1 / 2)) / (freq * div1);
+
+ KASSERT(div > 0 && div <= SLCR_DIV_MASK);
+ KASSERT(div1 > 0 && div1 <= SLCR_DIV_MASK);
+
+ ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
+
+ ctl &= ~SLCR_CLK_CTRL_SRCSEL_MASK;
+ ctl |= srcsels[best_si];
+ ctl &= ~(SLCR_DIV_MASK << SLCR_CLK_CTRL_DIVISOR_SHIFT);
+ ctl |= (div & SLCR_DIV_MASK) << SLCR_CLK_CTRL_DIVISOR_SHIFT;
+ if (clock->clk_has_div1) {
+ ctl &= ~(SLCR_DIV_MASK << SLCR_CLK_CTRL_DIVISOR1_SHIFT);
+ ctl |= (div1 & SLCR_DIV_MASK) << SLCR_CLK_CTRL_DIVISOR1_SHIFT;
+ }
+
+ zynq_slcr_write(sc->sc_rm, clock->clk_ctl_reg, ctl);
+
+out:
+ mtx_leave(&zynq_slcr_lock);
+
+ return error;
+}
+
+void
+zqclock_enable(void *cookie, uint32_t *cells, int on)
+{
+ const struct zqclock_clock *clock;
+ struct zqclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+ uint32_t ctl;
+
+ clock = zqclock_get_clock(idx);
+ if (clock == NULL)
+ return;
+
+ mtx_enter(&zynq_slcr_lock);
+
+ ctl = zynq_slcr_read(sc->sc_rm, clock->clk_ctl_reg);
+ if (on)
+ ctl |= SLCR_CLK_CTRL_CLKACT(clock->clk_index);
+ else
+ ctl &= ~SLCR_CLK_CTRL_CLKACT(clock->clk_index);
+ zynq_slcr_write(sc->sc_rm, clock->clk_ctl_reg, ctl);
+
+ mtx_leave(&zynq_slcr_lock);
+}
Index: sys/arch/armv7/xilinx/zqreset.c
===================================================================
RCS file: sys/arch/armv7/xilinx/zqreset.c
diff -N sys/arch/armv7/xilinx/zqreset.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/armv7/xilinx/zqreset.c 27 Apr 2021 12:42:21 -0000
@@ -0,0 +1,112 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2021 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Driver for Xilinx Zynq-7000 reset controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_misc.h>
+
+#include <armv7/xilinx/slcreg.h>
+
+extern void (*cpuresetfn)(void);
+
+struct zqreset_softc {
+ struct device sc_dev;
+ struct regmap *sc_rm;
+};
+
+int zqreset_match(struct device *, void *, void *);
+void zqreset_attach(struct device *, struct device *, void *);
+
+void zqreset_cpureset(void);
+
+const struct cfattach zqreset_ca = {
+ sizeof(struct zqreset_softc), zqreset_match, zqreset_attach
+};
+
+struct cfdriver zqreset_cd = {
+ NULL, "zqreset", DV_DULL
+};
+
+struct zqreset_softc *zqreset_sc;
+
+struct mutex zynq_slcr_lock = MUTEX_INITIALIZER(IPL_HIGH);
+
+int
+zqreset_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "xlnx,zynq-reset");
+}
+
+void
+zqreset_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ struct zqreset_softc *sc = (struct zqreset_softc *)self;
+
+ sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
+ if (sc->sc_rm == NULL) {
+ printf(": can't get regmap\n");
+ return;
+ }
+
+ printf("\n");
+
+ zqreset_sc = sc;
+ cpuresetfn = zqreset_cpureset;
+}
+
+void
+zqreset_cpureset(void)
+{
+ struct zqreset_softc *sc = zqreset_sc;
+
+ mtx_enter(&zynq_slcr_lock);
+ zynq_slcr_write(sc->sc_rm, SLCR_PSS_RST_CTRL,
+ SLCR_PSS_RST_CTRL_SOFT_RST);
+ mtx_leave(&zynq_slcr_lock);
+}
+
+uint32_t
+zynq_slcr_read(struct regmap *rm, uint32_t reg)
+{
+ return regmap_read_4(rm, reg);
+}
+
+void
+zynq_slcr_write(struct regmap *rm, uint32_t reg, uint32_t val)
+{
+ MUTEX_ASSERT_LOCKED(&zynq_slcr_lock);
+
+ regmap_write_4(rm, SLCR_UNLOCK, SLCR_UNLOCK_KEY);
+ regmap_write_4(rm, reg, val);
+ regmap_write_4(rm, SLCR_LOCK, SLCR_LOCK_KEY);
+}