[U-Boot] [PATCH] watchdog: Implement generic watchdog_reset() version
Stefan Roese
sr at denx.de
Fri Apr 5 13:00:20 UTC 2019
Hi Michal,
On 05.04.19 14:07, Michal Simek wrote:
<snip>
>> +++ b/drivers/watchdog/wdt-uclass.c
>> @@ -10,6 +10,12 @@
>> #include <dm/device-internal.h>
>> #include <dm/lists.h>
>>
>> +#ifndef WDT_DEFAULT_TIMEOUT
>> +#define WDT_DEFAULT_TIMEOUT 60
>> +#endif
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
>> {
>> const struct wdt_ops *ops = device_get_ops(dev);
>> @@ -63,6 +69,67 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
>> return ret;
>> }
>>
>> +#if defined(CONFIG_WATCHDOG)
>
> This is not enough because you can enable it just for full u-boot but
> not for SPL.
Why not? CONFIG_WATCHDOG can be enabled with or without
CONFIG_SPL_WATCHDOG_SUPPORT being enabled.
> It means you should also handle CONFIG_SPL_WATCHDOG_SUPPORT
> macros.
>
> Just try to enable CADENCE_WDT, WDT and Watchdog for zcu100 and build
I just tried this for xilinx_zynqmp_zcu100_revC_defconfig. Per default
it has enabled:
$ grep 'WATCHDOG\|WDT' .config
# CONFIG_SPL_WATCHDOG_SUPPORT is not set
# CONFIG_SYSRESET_WATCHDOG is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_RESET_DISABLE is not set
# CONFIG_BCM2835_WDT is not set
# CONFIG_ULP_WATCHDOG is not set
CONFIG_WDT=y
# CONFIG_WDT_ASPEED is not set
# CONFIG_WDT_ORION is not set
CONFIG_WDT_CDNS=y
# CONFIG_XILINX_TB_WATCHDOG is not set
# CONFIG_IMX_WATCHDOG is not set
# CONFIG_WDT_AT91 is not set
I can also enable SPL_WATCHDOG_SUPPORT and it compiles without issues:
$ grep 'WATCHDOG\|WDT' .config
CONFIG_SPL_WATCHDOG_SUPPORT=y
# CONFIG_SYSRESET_WATCHDOG is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_RESET_DISABLE is not set
# CONFIG_BCM2835_WDT is not set
# CONFIG_ULP_WATCHDOG is not set
CONFIG_WDT=y
# CONFIG_WDT_ASPEED is not set
# CONFIG_WDT_ORION is not set
CONFIG_WDT_CDNS=y
# CONFIG_XILINX_TB_WATCHDOG is not set
# CONFIG_IMX_WATCHDOG is not set
# CONFIG_WDT_AT91 is not set
What am I missing?
>> +/*
>> + * Called by macro WATCHDOG_RESET. This function be called *very* early,
>> + * so we need to make sure, that the watchdog driver is ready before using
>> + * it in this function.
>> + */
>> +void watchdog_reset(void)
>> +{
>> + static ulong next_reset;
>> + ulong now;
>> +
>> + /* Exit if GD is not ready or watchdog is not initialized yet */
>> + if (!gd || !(gd->flags & GD_FLG_WDT_READY))
>> + return;
>> +
>> + /* Do not reset the watchdog too often */
>> + now = get_timer(0);
>> + if (now > next_reset) {
>> + next_reset = now + 1000; /* reset every 1000ms */
>> + wdt_reset(gd->watchdog_dev);
>> + }
>> +}
>> +
>> +static void watchdog_start(void)
>> +{
>> + u32 timeout = WDT_DEFAULT_TIMEOUT;
>> +
>> + /*
>> + * Use only the first watchdog device in U-Boot to trigger the
>> + * watchdog reset
>> + */
>> + if (gd->watchdog_dev) {
>
> I hope that gd structure is cleared somewhere.
I had this also in mind with respect to BSS not being cleared very
early. Its cleared in board_init_f_init_reserve(), so quite early
before board_init_f() is called.
>> + debug("Only one watchdog device used!\n");
>> + return;
>> + }
>> +
>> + /*
>> + * Init watchdog: This will call the probe function of the
>> + * watchdog driver, enabling the use of the device
>> + */
>> + if (uclass_get_device(UCLASS_WDT, 0,
>> + (struct udevice **)&gd->watchdog_dev)) {
>> + debug("Watchdog: Not found!\n");
>> + return;
>> + }
>
> I think you should c&p what I have done in zynq/zynqmp. It means check
> watchdog0 alias first because this is supposed to be the first primary
> watchdog.
>
> zynq/zynqmp/mb code
> if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
> debug("Watchdog: Not found by seq!\n");
> if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
> puts("Watchdog: Not found!\n");
> return 0;
> }
> }
In my (internal) first version, I had exactly this code included. I
removed the first part, as it makes no real sense to call it at this
stage (wdt_post_bind() for the first WDT found in the system). My
understanding is, that wdt_post_bind() will get called for all WDT
found in the system. My current logic here is, to only register the
first WDT found to the global watchdog_dev in GD. To prevent that
multiple WDT are used to service the U-Boot watchdog via WATCHDOG_RESET.
Or does the DM subsystem automatically bind the watchdog0 alias first
in its binding sequence?
I do not have a system with multiple watchdogs here, so its not that
easy to test this. I could simulate this though somehow...
>
>
>> +
>> + if (CONFIG_IS_ENABLED(OF_CONTROL)) {
>> + timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec",
>> + WDT_DEFAULT_TIMEOUT);
>> + }
>
> You should remove them from drivers.
>
> drivers/watchdog/at91sam9_wdt.c:119: priv->timeout =
> dev_read_u32_default(dev, "timeout-sec",
> drivers/watchdog/cdns_wdt.c:238: priv->timeout =
> dev_read_u32_default(dev, "timeout-sec",
Yes, its on my plan. I've also some additions for the AT91 driver on
the list since a few days, which will most likely get applied before
this patch. I'll send a cleanup patch to remove those now superfluous
DT handling later.
Thanks,
Stefan
More information about the U-Boot
mailing list