From c891ae2705fae0d3b50a61bc56bc622d6ff8dd48 Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 23 Apr 2021 12:38:00 +0000 Subject: [PATCH] Adjust support for "syscon-reboot" and "syscon-poweroff" for the updated bindings in mainline Linux. Necessary to support the QEMY RISCV target. ok jsg@ --- sys/dev/fdt/syscon.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sys/dev/fdt/syscon.c b/sys/dev/fdt/syscon.c index fe6de250120..0116d5960d0 100644 --- a/sys/dev/fdt/syscon.c +++ b/sys/dev/fdt/syscon.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syscon.c,v 1.4 2018/03/17 18:04:15 kettenis Exp $ */ +/* $OpenBSD: syscon.c,v 1.5 2021/04/23 12:38:00 kettenis Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -42,6 +42,7 @@ struct syscon_softc { uint32_t sc_regmap; bus_size_t sc_offset; uint32_t sc_mask; + uint32_t sc_value; }; struct syscon_softc *syscon_reboot_sc; @@ -110,12 +111,26 @@ syscon_attach(struct device *parent, struct device *self, void *aux) if (sc->sc_regmap == 0) return; - if (OF_getproplen(faa->fa_node, "offset") != sizeof(uint32_t) || - OF_getproplen(faa->fa_node, "mask") != sizeof(uint32_t)) + if (OF_getproplen(faa->fa_node, "offset") != sizeof(uint32_t)) + return; + + /* At least one of "mask" and "value" should be provided. */ + if (OF_getproplen(faa->fa_node, "mask") != sizeof(uint32_t) && + OF_getproplen(faa->fa_node, "value") != sizeof(uint32_t)) return; sc->sc_offset = OF_getpropint(faa->fa_node, "offset", 0); - sc->sc_mask = OF_getpropint(faa->fa_node, "mask", 0); + sc->sc_mask = OF_getpropint(faa->fa_node, "mask", 0xffffffff); + sc->sc_value = OF_getpropint(faa->fa_node, "value", 0); + + /* + * Old binding used "mask" as the value to write with + * an all-ones mask. This is still supported. + */ + if (OF_getproplen(faa->fa_node, "value") != sizeof(uint32_t)) { + sc->sc_value = sc->sc_mask; + sc->sc_mask = 0xffffffff; + } if (OF_is_compatible(faa->fa_node, "syscon-reboot")) { syscon_reboot_sc = sc; @@ -132,12 +147,16 @@ syscon_reset(void) { struct syscon_softc *sc = syscon_reboot_sc; struct regmap *rm; + uint32_t value; rm = regmap_byphandle(sc->sc_regmap); if (rm == NULL) return; - regmap_write_4(rm, sc->sc_offset, sc->sc_mask); + value = regmap_read_4(rm, sc->sc_offset); + value &= ~sc->sc_mask; + value |= sc->sc_value; + regmap_write_4(rm, sc->sc_offset, value); delay(1000000); } @@ -146,11 +165,15 @@ syscon_powerdown(void) { struct syscon_softc *sc = syscon_poweroff_sc; struct regmap *rm; + uint32_t value; rm = regmap_byphandle(sc->sc_regmap); if (rm == NULL) return; - regmap_write_4(rm, sc->sc_offset, sc->sc_mask); + value = regmap_read_4(rm, sc->sc_offset); + value &= ~sc->sc_mask; + value |= sc->sc_value; + regmap_write_4(rm, sc->sc_offset, value); delay(1000000); } -- 2.20.1