From: Li Hua Qian <huaqian.li@xxxxxxxxxxx> This patch adds the WDIOF_CARDRESET support for the platform watchdog whose hardware does not support this feature, to know if the board reboot is due to a watchdog reset. This is done via reserved memory(RAM), which indicates if specific info saved, triggering the watchdog reset in last boot. Signed-off-by: Li Hua Qian <huaqian.li@xxxxxxxxxxx> --- drivers/watchdog/rti_wdt.c | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index ce8f18e93aa9..77fd6b54137c 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -18,6 +18,7 @@ #include <linux/pm_runtime.h> #include <linux/types.h> #include <linux/watchdog.h> +#include <linux/of.h> #define DEFAULT_HEARTBEAT 60 @@ -52,6 +53,11 @@ #define DWDST BIT(1) +#define PON_REASON_SOF_NUM 0xBBBBCCCC +#define PON_REASON_MAGIC_NUM 0xDDDDDDDD +#define PON_REASON_EOF_NUM 0xCCCCBBBB +#define PON_REASON_ITEM_BITS 0xFFFFFFFF + static int heartbeat = DEFAULT_HEARTBEAT; /* @@ -198,6 +204,11 @@ static int rti_wdt_probe(struct platform_device *pdev) struct rti_wdt_device *wdt; struct clk *clk; u32 last_ping = 0; + u32 reserved_mem_size; + unsigned long *vaddr; + unsigned long paddr; + u32 data[3]; + u32 reg[8]; wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); if (!wdt) @@ -284,6 +295,43 @@ static int rti_wdt_probe(struct platform_device *pdev) } } + ret = of_property_read_variable_u32_array(pdev->dev.of_node, "reg", reg, + 0, ARRAY_SIZE(reg)); + if (ret < 0) { + dev_err(dev, "cannot read the reg info.\n"); + goto err_iomap; + } + + /* + * If reserved memory is defined for watchdog reset cause. + * Readout the Power-on(PON) reason and pass to bootstatus. + */ + if (ret == 8) { + paddr = reg[5]; + reserved_mem_size = reg[7]; + vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB); + if (vaddr == NULL) { + dev_err(dev, "Failed to map memory-region.\n"); + goto err_iomap; + } + + data[0] = *vaddr & PON_REASON_ITEM_BITS; + data[1] = *(vaddr + 1) & PON_REASON_ITEM_BITS; + data[2] = *(vaddr + 2) & PON_REASON_ITEM_BITS; + + dev_dbg(dev, "Watchdog: sof = %lX, data = %lX, eof = %lX\n", + data[0], data[1], data[2]); + + if ((data[0] == PON_REASON_SOF_NUM) + && (data[1] == PON_REASON_MAGIC_NUM) + && (data[1] == PON_REASON_MAGIC_NUM)) { + dev_info(dev, "Watchdog reset cause detected.\n"); + wdd->bootstatus |= WDIOF_CARDRESET; + } + memset(vaddr, 0, reserved_mem_size); + memunmap(vaddr); + } + watchdog_init_timeout(wdd, heartbeat, dev); ret = watchdog_register_device(wdd); -- 2.34.1