watchdog: add sl28cpld watchdog driver
The watchdog timer is part of the sl28cpld management controller. The watchdog timer usually supervises the bootloader boot-up and if it bites the failsafe bootloader will be activated. Apart from that it supports the usual board level reset and one SMARC speciality: driving the WDT_TIMEOUT# signal. Signed-off-by: Michael Walle <michael@walle.cc> Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
This commit is contained in:
parent
42595eb706
commit
f606c9a895
@ -1165,6 +1165,7 @@ SL28CLPD
|
|||||||
M: Michael Walle <michael@walle.cc>
|
M: Michael Walle <michael@walle.cc>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/misc/sl28cpld.c
|
F: drivers/misc/sl28cpld.c
|
||||||
|
F: drivers/watchdog/sl28cpld-wdt.c
|
||||||
|
|
||||||
SPI
|
SPI
|
||||||
M: Jagan Teki <jagan@amarulasolutions.com>
|
M: Jagan Teki <jagan@amarulasolutions.com>
|
||||||
|
@ -35,23 +35,6 @@ The board is fully failsafe, you can't break anything. But because you've
|
|||||||
disabled the builtin watchdog you might have to manually enter failsafe
|
disabled the builtin watchdog you might have to manually enter failsafe
|
||||||
mode by asserting the ``FORCE_RECOV#`` line during board reset.
|
mode by asserting the ``FORCE_RECOV#`` line during board reset.
|
||||||
|
|
||||||
Disable the builtin watchdog
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- boot into the failsafe bootloader, either by asserting the
|
|
||||||
``FORCE_RECOV#`` line or if you still have the original bootloader
|
|
||||||
installed you can use the command::
|
|
||||||
|
|
||||||
> wdt dev cpld_watchdog@4a; wdt expire 1
|
|
||||||
|
|
||||||
- in the failsafe bootloader use the "sl28 nvm" command to disable
|
|
||||||
the automatic start of the builtin watchdog::
|
|
||||||
|
|
||||||
> sl28 nvm 0008
|
|
||||||
|
|
||||||
- power-cycle the board
|
|
||||||
|
|
||||||
|
|
||||||
Update image
|
Update image
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@ -82,6 +65,42 @@ u-boot (yet). But you can use the i2c command to access it.
|
|||||||
> i2c md 4a 3.1 1
|
> i2c md 4a 3.1 1
|
||||||
|
|
||||||
|
|
||||||
|
Builtin watchdog
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The builtin watchdog will supervise the bootloader startup. If anything
|
||||||
|
goes wrong it will reset the board and boot into the failsafe bootloader.
|
||||||
|
|
||||||
|
Once the bootloader is started successfully, it will disable the watchdog
|
||||||
|
timer.
|
||||||
|
|
||||||
|
wdt command flags
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The `wdt start` as well as the `wdt expire` command take a flags argument.
|
||||||
|
The supported bitmask is as follows.
|
||||||
|
|
||||||
|
| Bit | Description |
|
||||||
|
| --- | ----------------------------- |
|
||||||
|
| 0 | Enable failsafe mode |
|
||||||
|
| 1 | Lock the control register |
|
||||||
|
| 2 | Disable board reset |
|
||||||
|
| 3 | Enable WDT_TIME_OUT# line |
|
||||||
|
|
||||||
|
For example, you can use `wdt expire 1` to issue a reset and boot into the
|
||||||
|
failsafe bootloader.
|
||||||
|
|
||||||
|
Disable the builtin watchdog
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If for some reason, this isn't a desired behavior, the watchdog can also
|
||||||
|
be configured to not be enabled on board reset. It's configuration is saved
|
||||||
|
in the non-volatile board configuration bits. To change these you can use
|
||||||
|
the `sl28 nvm` command.
|
||||||
|
|
||||||
|
For more information on the non-volatile board configuration bits, see the
|
||||||
|
following section.
|
||||||
|
|
||||||
Non-volatile Board Configuration Bits
|
Non-volatile Board Configuration Bits
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
@ -266,6 +266,13 @@ config WDT_SBSA
|
|||||||
In the single stage mode, when the timeout is reached, your system
|
In the single stage mode, when the timeout is reached, your system
|
||||||
will be reset by WS1. The first signal (WS0) is ignored.
|
will be reset by WS1. The first signal (WS0) is ignored.
|
||||||
|
|
||||||
|
config WDT_SL28CPLD
|
||||||
|
bool "sl28cpld watchdog timer support"
|
||||||
|
depends on WDT && SL28CPLD
|
||||||
|
help
|
||||||
|
Enable support for the watchdog timer in the Kontron sl28cpld
|
||||||
|
management controller.
|
||||||
|
|
||||||
config WDT_SP805
|
config WDT_SP805
|
||||||
bool "SP805 watchdog timer support"
|
bool "SP805 watchdog timer support"
|
||||||
depends on WDT
|
depends on WDT
|
||||||
|
@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o
|
|||||||
obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
|
obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
|
||||||
obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
|
obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
|
||||||
obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
|
obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
|
||||||
|
obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
|
||||||
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
|
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
|
||||||
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
|
||||||
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
|
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
|
||||||
|
109
drivers/watchdog/sl28cpld-wdt.c
Normal file
109
drivers/watchdog/sl28cpld-wdt.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Watchdog driver for the sl28cpld
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Michael Walle <michael@walle.cc>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <wdt.h>
|
||||||
|
#include <sl28cpld.h>
|
||||||
|
#include <div64.h>
|
||||||
|
|
||||||
|
#define SL28CPLD_WDT_CTRL 0x00
|
||||||
|
#define WDT_CTRL_EN0 BIT(0)
|
||||||
|
#define WDT_CTRL_EN1 BIT(1)
|
||||||
|
#define WDT_CTRL_EN_MASK GENMASK(1, 0)
|
||||||
|
#define WDT_CTRL_LOCK BIT(2)
|
||||||
|
#define WDT_CTRL_ASSERT_SYS_RESET BIT(6)
|
||||||
|
#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7)
|
||||||
|
#define SL28CPLD_WDT_TIMEOUT 0x01
|
||||||
|
#define SL28CPLD_WDT_KICK 0x02
|
||||||
|
#define WDT_KICK_VALUE 0x6b
|
||||||
|
|
||||||
|
static int sl28cpld_wdt_reset(struct udevice *dev)
|
||||||
|
{
|
||||||
|
return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
||||||
|
{
|
||||||
|
int ret, val;
|
||||||
|
|
||||||
|
val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
/* (1) disable watchdog */
|
||||||
|
val &= ~WDT_CTRL_EN_MASK;
|
||||||
|
ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* (2) set timeout */
|
||||||
|
ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* (3) kick it, will reset timer to the timeout value */
|
||||||
|
ret = sl28cpld_wdt_reset(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* (4) enable either recovery or normal one */
|
||||||
|
if (flags & BIT(0))
|
||||||
|
val |= WDT_CTRL_EN1;
|
||||||
|
else
|
||||||
|
val |= WDT_CTRL_EN0;
|
||||||
|
|
||||||
|
if (flags & BIT(1))
|
||||||
|
val |= WDT_CTRL_LOCK;
|
||||||
|
|
||||||
|
if (flags & BIT(2))
|
||||||
|
val &= ~WDT_CTRL_ASSERT_SYS_RESET;
|
||||||
|
else
|
||||||
|
val |= WDT_CTRL_ASSERT_SYS_RESET;
|
||||||
|
|
||||||
|
if (flags & BIT(3))
|
||||||
|
val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
|
||||||
|
else
|
||||||
|
val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT;
|
||||||
|
|
||||||
|
return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sl28cpld_wdt_stop(struct udevice *dev)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags)
|
||||||
|
{
|
||||||
|
return sl28cpld_wdt_start(dev, 0, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wdt_ops sl28cpld_wdt_ops = {
|
||||||
|
.start = sl28cpld_wdt_start,
|
||||||
|
.reset = sl28cpld_wdt_reset,
|
||||||
|
.stop = sl28cpld_wdt_stop,
|
||||||
|
.expire_now = sl28cpld_wdt_expire_now,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct udevice_id sl28cpld_wdt_ids[] = {
|
||||||
|
{ .compatible = "kontron,sl28cpld-wdt", },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sl28cpld_wdt) = {
|
||||||
|
.name = "sl28cpld-wdt",
|
||||||
|
.id = UCLASS_WDT,
|
||||||
|
.of_match = sl28cpld_wdt_ids,
|
||||||
|
.ops = &sl28cpld_wdt_ops,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user