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); +}