Message ID | 20250515-vt8500-timer-updates-v3-4-2197a1b062bd@gmail.com |
---|---|
State | New |
Headers | show |
Series | clocksource/drivers/timer-vt8500: clean up and add watchdog function | expand |
Hi Alexey, kernel test robot noticed the following build warnings: [auto build test WARNING on 92a09c47464d040866cf2b4cd052bc60555185fb] url: https://github.com/intel-lab-lkp/linux/commits/Alexey-Charkov/dt-bindings-timer-via-vt8500-timer-Convert-to-YAML/20250516-025729 base: 92a09c47464d040866cf2b4cd052bc60555185fb patch link: https://lore.kernel.org/r/20250515-vt8500-timer-updates-v3-4-2197a1b062bd%40gmail.com patch subject: [PATCH v3 4/4] watchdog: Add support for VIA/WonderMedia SoC watchdog functionality config: sparc-allmodconfig (https://download.01.org/0day-ci/archive/20250516/202505161430.wdURc0TG-lkp@intel.com/config) compiler: sparc64-linux-gcc (GCC) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250516/202505161430.wdURc0TG-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202505161430.wdURc0TG-lkp@intel.com/ All warnings (new ones prefixed by >>): drivers/watchdog/vt8500-wdt.c: In function 'vt8500_wdt_probe': >> drivers/watchdog/vt8500-wdt.c:98:44: warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '6148914691236517' to '3287081637' [-Woverflow] 98 | drvdata->wdd.max_hw_heartbeat_ms = -1UL / (VT8500_TIMER_HZ / 1000); | ^ vim +98 drivers/watchdog/vt8500-wdt.c 75 76 static int vt8500_wdt_probe(struct platform_device *pdev) 77 { 78 struct device *dev = &pdev->dev; 79 struct vt8500_wdt *drvdata; 80 81 drvdata = devm_kzalloc(dev, sizeof(struct vt8500_wdt), GFP_KERNEL); 82 if (!drvdata) 83 return -ENOMEM; 84 85 /* 86 * The register area where the timer and watchdog reside is disarranged. 87 * Hence mapping individual register blocks for the timer and watchdog 88 * is not recommended as they would have access to each others 89 * registers. The timer driver creates the watchdog as a child device. 90 * During the watchdogs creation, the timer driver passes the base 91 * address to the watchdog over the private interface. 92 */ 93 94 drvdata->regbase = (void __iomem *)dev->platform_data; 95 96 drvdata->wdd.info = &vt8500_watchdog_info; 97 drvdata->wdd.ops = &vt8500_watchdog_ops; > 98 drvdata->wdd.max_hw_heartbeat_ms = -1UL / (VT8500_TIMER_HZ / 1000); 99 drvdata->wdd.parent = dev; 100 101 watchdog_set_drvdata(&drvdata->wdd, drvdata); 102 103 return devm_watchdog_register_device(dev, &drvdata->wdd); 104 } 105
On Fri, May 16, 2025 at 9:56 AM kernel test robot <lkp@intel.com> wrote: > > Hi Alexey, > > kernel test robot noticed the following build warnings: > > [auto build test WARNING on 92a09c47464d040866cf2b4cd052bc60555185fb] > > url: https://github.com/intel-lab-lkp/linux/commits/Alexey-Charkov/dt-bindings-timer-via-vt8500-timer-Convert-to-YAML/20250516-025729 > base: 92a09c47464d040866cf2b4cd052bc60555185fb > patch link: https://lore.kernel.org/r/20250515-vt8500-timer-updates-v3-4-2197a1b062bd%40gmail.com > patch subject: [PATCH v3 4/4] watchdog: Add support for VIA/WonderMedia SoC watchdog functionality > config: sparc-allmodconfig (https://download.01.org/0day-ci/archive/20250516/202505161430.wdURc0TG-lkp@intel.com/config) > compiler: sparc64-linux-gcc (GCC) 14.2.0 > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250516/202505161430.wdURc0TG-lkp@intel.com/reproduce) > > If you fix the issue in a separate patch/commit (i.e. not just a new version of > the same patch/commit), kindly add following tags > | Reported-by: kernel test robot <lkp@intel.com> > | Closes: https://lore.kernel.org/oe-kbuild-all/202505161430.wdURc0TG-lkp@intel.com/ > > All warnings (new ones prefixed by >>): > > drivers/watchdog/vt8500-wdt.c: In function 'vt8500_wdt_probe': > >> drivers/watchdog/vt8500-wdt.c:98:44: warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '6148914691236517' to '3287081637' [-Woverflow] > 98 | drvdata->wdd.max_hw_heartbeat_ms = -1UL / (VT8500_TIMER_HZ / 1000); Will change to U32_MAX in the next version. Best regards, Alexey
diff --git a/MAINTAINERS b/MAINTAINERS index b8b2843491c47182a4fc6c76f5c29b6c411830a6..d809643b76ad299ca1c08804540b08cc4a7184a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3446,6 +3446,7 @@ F: drivers/tty/serial/vt8500_serial.c F: drivers/video/fbdev/vt8500lcdfb.* F: drivers/video/fbdev/wm8505fb* F: drivers/video/fbdev/wmt_ge_rops.* +F: drivers/watchdog/vt8500-wdt.c ARM/ZYNQ ARCHITECTURE M: Michal Simek <michal.simek@amd.com> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0d8d37f712e8cfb4bf8156853baa13c23a57d6d9..429e4e775f1f458fd457067a3a039a5d544b4818 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2003,6 +2003,20 @@ config PIC32_DMT To compile this driver as a loadable module, choose M here. The module will be called pic32-dmt. +config VT8500_WATCHDOG + tristate "VIA/WonderMedia VT8500 watchdog support" + depends on ARCH_VT8500 || COMPILE_TEST + select WATCHDOG_CORE + help + VIA/WonderMedia SoCs can use their system timer as a hardware + watchdog, as long as the first timer channel is free from other + uses and respective function is enabled in its registers. To + make use of it, say Y here and ensure that the device tree + lists at least two interrupts for the VT8500 timer device. + + To compile this driver as a module, choose M here. + The module will be called vt8500-wdt. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index c9482904bf870a085c7fce2a439ac5089b6e6fee..3072786bf226c357102be3734fe6e701f753d45b 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o obj-$(CONFIG_MARVELL_GTI_WDT) += marvell_gti_wdt.o +obj-$(CONFIG_VT8500_WATCHDOG) += vt8500-wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/vt8500-wdt.c b/drivers/watchdog/vt8500-wdt.c new file mode 100644 index 0000000000000000000000000000000000000000..8e605c850dd9f42c90104f362b74adac63dd9fdb --- /dev/null +++ b/drivers/watchdog/vt8500-wdt.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2025 Alexey Charkov <alchark@gmail.com */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/watchdog.h> + +#define TIMER_MATCH_REG(x) (4 * (x)) +#define TIMER_COUNT_REG 0x0010 /* clocksource counter */ + +#define TIMER_WATCHDOG_EN_REG 0x0018 +#define TIMER_WD_EN BIT(0) + +#define TIMER_CTRL_REG 0x0020 +#define TIMER_CTRL_ENABLE BIT(0) /* enable clocksource counter */ +#define TIMER_CTRL_RD_REQ BIT(1) /* request counter read */ + +#define TIMER_ACC_STS_REG 0x0024 /* access status */ +#define TIMER_ACC_WR_MATCH(x) BIT((x)) /* writing Match (x) value */ +#define TIMER_ACC_WR_COUNTER BIT(4) /* writing clocksource counter */ +#define TIMER_ACC_RD_COUNTER BIT(5) /* reading clocksource counter */ + +#define VT8500_TIMER_HZ 3000000 +#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) + +struct vt8500_wdt { + void __iomem *regbase; + struct watchdog_device wdd; +}; + +static u64 vt8500_timer_read(void __iomem *regbase) +{ + int loops = msecs_to_loops(10); + + writel(TIMER_CTRL_ENABLE | TIMER_CTRL_RD_REQ, regbase + TIMER_CTRL_REG); + while (readl(regbase + TIMER_ACC_STS_REG) & TIMER_ACC_RD_COUNTER + && --loops) + cpu_relax(); + return readl(regbase + TIMER_COUNT_REG); +} + +static int vt8500_watchdog_start(struct watchdog_device *wdd) +{ + struct vt8500_wdt *drvdata = watchdog_get_drvdata(wdd); + u64 cycles = wdd->timeout * VT8500_TIMER_HZ; + u64 deadline = vt8500_timer_read(drvdata->regbase) + cycles; + + writel((u32)deadline, drvdata->regbase + TIMER_MATCH_REG(0)); + writel(TIMER_WD_EN, drvdata->regbase + TIMER_WATCHDOG_EN_REG); + return 0; +} + +static int vt8500_watchdog_stop(struct watchdog_device *wdd) +{ + struct vt8500_wdt *drvdata = watchdog_get_drvdata(wdd); + + writel(0, drvdata->regbase + TIMER_WATCHDOG_EN_REG); + return 0; +} + +static const struct watchdog_ops vt8500_watchdog_ops = { + .start = vt8500_watchdog_start, + .stop = vt8500_watchdog_stop, +}; + +static const struct watchdog_info vt8500_watchdog_info = { + .identity = "VIA VT8500 watchdog", + .options = WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT, +}; + +static int vt8500_wdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vt8500_wdt *drvdata; + + drvdata = devm_kzalloc(dev, sizeof(struct vt8500_wdt), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + /* + * The register area where the timer and watchdog reside is disarranged. + * Hence mapping individual register blocks for the timer and watchdog + * is not recommended as they would have access to each others + * registers. The timer driver creates the watchdog as a child device. + * During the watchdogs creation, the timer driver passes the base + * address to the watchdog over the private interface. + */ + + drvdata->regbase = (void __iomem *)dev->platform_data; + + drvdata->wdd.info = &vt8500_watchdog_info; + drvdata->wdd.ops = &vt8500_watchdog_ops; + drvdata->wdd.max_hw_heartbeat_ms = -1UL / (VT8500_TIMER_HZ / 1000); + drvdata->wdd.parent = dev; + + watchdog_set_drvdata(&drvdata->wdd, drvdata); + + return devm_watchdog_register_device(dev, &drvdata->wdd); +} + +static struct platform_driver vt8500_wdt_driver = { + .probe = vt8500_wdt_probe, + .driver = { + .name = "vt8500-wdt", + }, +}; +module_platform_driver(vt8500_wdt_driver); + +MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); +MODULE_DESCRIPTION("Driver for the VIA VT8500 watchdog timer"); +MODULE_LICENSE("GPL");
VIA/WonderMedia SoCs can use their system timer's first channel as a watchdog device which will reset the system if the clocksource counter matches the value given in its match register 0 and if the watchdog function is enabled. Since the watchdog function is tightly coupled to the timer itself, it is implemented as a child platform device of the timer device, and just reuses the MMIO registers already remapped by the timer driver. This is similar to the approach taken by gxp-wdt.c Signed-off-by: Alexey Charkov <alchark@gmail.com> --- MAINTAINERS | 1 + drivers/watchdog/Kconfig | 14 +++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/vt8500-wdt.c | 116 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+)