From 10f5d8578aac5933e73eaf5d1b3867d798c1f026 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sun, 16 Apr 2023 16:51:38 +0000 Subject: [PATCH] Separate DesignWare watchdog driver and FDT glue. --- sys/conf/files | 6 +- sys/dev/fdt/dwcwdt_fdt.c | 143 ++------------------------------ sys/dev/fdt/files.fdt | 3 +- sys/dev/ic/dwc_wdt.c | 173 +++++++++++++++++++++++++++++++++++++++ sys/dev/ic/dwc_wdt_var.h | 42 ++++++++++ 5 files changed, 229 insertions(+), 138 deletions(-) create mode 100644 sys/dev/ic/dwc_wdt.c create mode 100644 sys/dev/ic/dwc_wdt_var.h diff --git a/sys/conf/files b/sys/conf/files index 8dd8f0d39712..5e8df5597866 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.1306 2022/12/28 18:19:44 jakllsch Exp $ +# $NetBSD: files,v 1.1307 2023/04/16 16:51:38 jmcneill Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20171118 @@ -799,6 +799,10 @@ file dev/ic/dwc_gmac.c awge device eqos: arp, ether, ifnet, mii file dev/ic/dwc_eqos.c eqos +# Synopsys DesignWare Watchdog +device dwcwdt: sysmon_wdog +file dev/ic/dwc_wdt.c dwcwdt + # 8390-family Ethernet controllers # define dp8390nic diff --git a/sys/dev/fdt/dwcwdt_fdt.c b/sys/dev/fdt/dwcwdt_fdt.c index c993e5d95271..658e78b2c9a9 100644 --- a/sys/dev/fdt/dwcwdt_fdt.c +++ b/sys/dev/fdt/dwcwdt_fdt.c @@ -1,7 +1,7 @@ -/* $NetBSD: dwcwdt_fdt.c,v 1.5 2021/01/27 03:10:21 thorpej Exp $ */ +/* $NetBSD: dwcwdt_fdt.c,v 1.6 2023/04/16 16:51:38 jmcneill Exp $ */ /*- - * Copyright (c) 2018 Jared McNeill + * Copyright (c) 2018, 2023 Jared McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: dwcwdt_fdt.c,v 1.5 2021/01/27 03:10:21 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dwcwdt_fdt.c,v 1.6 2023/04/16 16:51:38 jmcneill Exp $"); #include #include @@ -38,133 +38,17 @@ __KERNEL_RCSID(0, "$NetBSD: dwcwdt_fdt.c,v 1.5 2021/01/27 03:10:21 thorpej Exp $ #include #include +#include #include -#define WDT_CR 0x00 -#define WDT_CR_RST_PULSE_LENGTH __BITS(4,2) -#define WDT_CR_RESP_MODE __BIT(1) -#define WDT_CR_WDT_EN __BIT(0) - -#define WDT_TORR 0x04 -#define WDT_TORR_TIMEOUT_PERIOD __BITS(3,0) - -#define WDT_CCVR 0x08 - -#define WDT_CRR 0x0c -#define WDT_CRR_CNT_RESTART __BITS(7,0) -#define WDT_CRR_CNT_RESTART_MAGIC 0x76 - -#define WDT_STAT 0x10 -#define WDT_STAT_WDT_STATUS __BIT(0) - -#define WDT_EOI 0x14 -#define WDT_EOI_WDT_INT_CLR __BIT(0) - -static const uint32_t wdt_torr[] = { - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff, - 0x00ffffff, - 0x01ffffff, - 0x03ffffff, - 0x07ffffff, - 0x0fffffff, - 0x1fffffff, - 0x3fffffff, - 0x7fffffff, -}; - -#define DWCWDT_PERIOD_DEFAULT 15 - static const struct device_compatible_entry compat_data[] = { { .compat = "snps,dw-wdt" }, DEVICE_COMPAT_EOL }; -struct dwcwdt_softc { - device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; - struct sysmon_wdog sc_smw; - u_int sc_clkrate; -}; - -#define RD4(sc, reg) \ - bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) -#define WR4(sc, reg, val) \ - bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) - static int -dwcwdt_map_period(struct dwcwdt_softc *sc, u_int period, - u_int *aperiod) -{ - int i; - - if (period == 0) - return -1; - - for (i = 0; i < __arraycount(wdt_torr); i++) { - const u_int ms = (u_int)((((uint64_t)wdt_torr[i] + 1) * 1000) / sc->sc_clkrate); - if (ms >= period * 1000) { - *aperiod = ms / 1000; - return i; - } - } - - return -1; -} - -static int -dwcwdt_tickle(struct sysmon_wdog *smw) -{ - struct dwcwdt_softc * const sc = smw->smw_cookie; - const uint32_t crr = - __SHIFTIN(WDT_CRR_CNT_RESTART_MAGIC, WDT_CRR_CNT_RESTART); - - WR4(sc, WDT_CRR, crr); - - return 0; -} - -static int -dwcwdt_setmode(struct sysmon_wdog *smw) -{ - struct dwcwdt_softc * const sc = smw->smw_cookie; - uint32_t cr, torr; - int intv; - - if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { - /* Watchdog can only be disarmed by a reset */ - return EIO; - } - - if (smw->smw_period == WDOG_PERIOD_DEFAULT) - smw->smw_period = DWCWDT_PERIOD_DEFAULT; - - intv = dwcwdt_map_period(sc, smw->smw_period, - &sc->sc_smw.smw_period); - if (intv == -1) - return EINVAL; - - torr = __SHIFTIN(intv, WDT_TORR_TIMEOUT_PERIOD); - WR4(sc, WDT_TORR, torr); - dwcwdt_tickle(smw); - cr = RD4(sc, WDT_CR); - cr &= ~WDT_CR_RESP_MODE; - cr |= WDT_CR_WDT_EN; - WR4(sc, WDT_CR, cr); - - return 0; -} - -static int -dwcwdt_match(device_t parent, cfdata_t cf, void *aux) +dwcwdt_fdt_match(device_t parent, cfdata_t cf, void *aux) { struct fdt_attach_args * const faa = aux; @@ -172,7 +56,7 @@ dwcwdt_match(device_t parent, cfdata_t cf, void *aux) } static void -dwcwdt_attach(device_t parent, device_t self, void *aux) +dwcwdt_fdt_attach(device_t parent, device_t self, void *aux) { struct dwcwdt_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; @@ -213,19 +97,8 @@ dwcwdt_attach(device_t parent, device_t self, void *aux) aprint_naive("\n"); aprint_normal(": DesignWare Watchdog Timer\n"); - sc->sc_smw.smw_name = device_xname(self); - sc->sc_smw.smw_cookie = sc; - sc->sc_smw.smw_period = DWCWDT_PERIOD_DEFAULT; - sc->sc_smw.smw_setmode = dwcwdt_setmode; - sc->sc_smw.smw_tickle = dwcwdt_tickle; - - aprint_normal_dev(self, - "default watchdog period is %u seconds\n", - sc->sc_smw.smw_period); - - if (sysmon_wdog_register(&sc->sc_smw) != 0) - aprint_error_dev(self, "couldn't register with sysmon\n"); + dwcwdt_init(sc); } CFATTACH_DECL_NEW(dwcwdt_fdt, sizeof(struct dwcwdt_softc), - dwcwdt_match, dwcwdt_attach, NULL, NULL); + dwcwdt_fdt_match, dwcwdt_fdt_attach, NULL, NULL); diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 038e6880f2ba..0784e22903eb 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.67 2023/04/07 08:55:31 skrll Exp $ +# $NetBSD: files.fdt,v 1.68 2023/04/16 16:51:38 jmcneill Exp $ include "external/bsd/libfdt/conf/files.libfdt" @@ -162,7 +162,6 @@ attach dwcmmc at fdt with dwcmmc_fdt file dev/fdt/dwcmmc_fdt.c dwcmmc_fdt # Designware Watchdog Timer -device dwcwdt: sysmon_wdog attach dwcwdt at fdt with dwcwdt_fdt file dev/fdt/dwcwdt_fdt.c dwcwdt_fdt diff --git a/sys/dev/ic/dwc_wdt.c b/sys/dev/ic/dwc_wdt.c new file mode 100644 index 000000000000..89d3632e2735 --- /dev/null +++ b/sys/dev/ic/dwc_wdt.c @@ -0,0 +1,173 @@ +/* $NetBSD: dwc_wdt.c,v 1.1 2023/04/16 16:51:38 jmcneill Exp $ */ + +/*- + * Copyright (c) 2018, 2023 Jared McNeill + * All rights reserved. + * + * 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 ``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 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 +__KERNEL_RCSID(0, "$NetBSD: dwc_wdt.c,v 1.1 2023/04/16 16:51:38 jmcneill Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define WDT_CR 0x00 +#define WDT_CR_RST_PULSE_LENGTH __BITS(4,2) +#define WDT_CR_RESP_MODE __BIT(1) +#define WDT_CR_WDT_EN __BIT(0) + +#define WDT_TORR 0x04 +#define WDT_TORR_TIMEOUT_PERIOD __BITS(3,0) + +#define WDT_CCVR 0x08 + +#define WDT_CRR 0x0c +#define WDT_CRR_CNT_RESTART __BITS(7,0) +#define WDT_CRR_CNT_RESTART_MAGIC 0x76 + +#define WDT_STAT 0x10 +#define WDT_STAT_WDT_STATUS __BIT(0) + +#define WDT_EOI 0x14 +#define WDT_EOI_WDT_INT_CLR __BIT(0) + +static const uint32_t wdt_torr[] = { + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, +}; + +#define DWCWDT_PERIOD_DEFAULT 15 + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int +dwcwdt_map_period(struct dwcwdt_softc *sc, u_int period, + u_int *aperiod) +{ + int i; + + if (period == 0) + return -1; + + for (i = 0; i < __arraycount(wdt_torr); i++) { + const u_int ms = (u_int)((((uint64_t)wdt_torr[i] + 1) * 1000) / sc->sc_clkrate); + if (ms >= period * 1000) { + *aperiod = ms / 1000; + return i; + } + } + + return -1; +} + +static int +dwcwdt_tickle(struct sysmon_wdog *smw) +{ + struct dwcwdt_softc * const sc = smw->smw_cookie; + const uint32_t crr = + __SHIFTIN(WDT_CRR_CNT_RESTART_MAGIC, WDT_CRR_CNT_RESTART); + + WR4(sc, WDT_CRR, crr); + + return 0; +} + +static int +dwcwdt_setmode(struct sysmon_wdog *smw) +{ + struct dwcwdt_softc * const sc = smw->smw_cookie; + uint32_t cr, torr; + int intv; + + if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { + /* Watchdog can only be disarmed by a reset */ + return EIO; + } + + if (smw->smw_period == WDOG_PERIOD_DEFAULT) + smw->smw_period = DWCWDT_PERIOD_DEFAULT; + + intv = dwcwdt_map_period(sc, smw->smw_period, + &sc->sc_smw.smw_period); + if (intv == -1) + return EINVAL; + + torr = __SHIFTIN(intv, WDT_TORR_TIMEOUT_PERIOD); + WR4(sc, WDT_TORR, torr); + dwcwdt_tickle(smw); + cr = RD4(sc, WDT_CR); + cr &= ~WDT_CR_RESP_MODE; + cr |= WDT_CR_WDT_EN; + WR4(sc, WDT_CR, cr); + + return 0; +} + +void +dwcwdt_init(struct dwcwdt_softc *sc) +{ + if (sc->sc_clkrate == 0) { + aprint_error_dev(sc->sc_dev, "clock rate not specified\n"); + return; + } + + sc->sc_smw.smw_name = device_xname(sc->sc_dev); + sc->sc_smw.smw_cookie = sc; + sc->sc_smw.smw_period = DWCWDT_PERIOD_DEFAULT; + sc->sc_smw.smw_setmode = dwcwdt_setmode; + sc->sc_smw.smw_tickle = dwcwdt_tickle; + + aprint_normal_dev(sc->sc_dev, + "default watchdog period is %u seconds\n", + sc->sc_smw.smw_period); + + if (sysmon_wdog_register(&sc->sc_smw) != 0) { + aprint_error_dev(sc->sc_dev, "couldn't register with sysmon\n"); + } +} diff --git a/sys/dev/ic/dwc_wdt_var.h b/sys/dev/ic/dwc_wdt_var.h new file mode 100644 index 000000000000..d0345350c819 --- /dev/null +++ b/sys/dev/ic/dwc_wdt_var.h @@ -0,0 +1,42 @@ +/* $NetBSD: dwc_wdt_var.h,v 1.1 2023/04/16 16:51:38 jmcneill Exp $ */ + +/*- + * Copyright (c) 2018, 2023 Jared McNeill + * All rights reserved. + * + * 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 ``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 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 _DWC_WDT_VAR_H +#define _DWC_WDT_VAR_H + +struct dwcwdt_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + struct sysmon_wdog sc_smw; + u_int sc_clkrate; +}; + +void dwcwdt_init(struct dwcwdt_softc *); + +#endif /* !_DWC_WDT_VAR_H */