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 <v...@hankala.org>
> > 
> > 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);
+}

Reply via email to