[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250502-wdt_reset_reason-v3-4-b2dc7ace38ca@oss.qualcomm.com>
Date: Fri, 02 May 2025 18:47:52 +0530
From: Kathiravan Thirumoorthy <kathiravan.thirumoorthy@....qualcomm.com>
To: Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Bjorn Andersson <andersson@...nel.org>,
Konrad Dybcio <konradybcio@...nel.org>,
Wim Van Sebroeck <wim@...ux-watchdog.org>,
Guenter Roeck <linux@...ck-us.net>, bod.linux@...w.ie
Cc: linux-arm-msm@...r.kernel.org, devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-watchdog@...r.kernel.org,
Kathiravan Thirumoorthy <kathiravan.thirumoorthy@....qualcomm.com>
Subject: [PATCH v3 4/4] watchdog: qcom: add support to read the restart
reason from IMEM
When the system boots up after a watchdog reset, the EXPIRED_STATUS bit
in the WDT_STS register is cleared. To identify if the system was
restarted due to WDT expiry, XBL update the information in the IMEM region.
Update the driver to read the restart reason from IMEM and populate the
bootstatus accordingly.
With the CONFIG_WATCHDOG_SYSFS enabled, user can extract the information
as below:
cat /sys/devices/platform/soc@...410000.watchdog/watchdog/watchdog0/bootstatus
32
For backward compatibility, keep the EXPIRED_STATUS bit check. Add a new
function qcom_wdt_get_restart_reason() to read the restart reason from
IMEM.
Signed-off-by: Kathiravan Thirumoorthy <kathiravan.thirumoorthy@....qualcomm.com>
---
Changes in v3:
- Split the introduction of device data into separate patch
- s/bootloaders/XBL - for clarity of which bootloader is
involved
- Mention the sysfs path on to extract this information
- s/compatible/imem_compatible in the device data structure to
avoid the confusion / better naming
Changes in v2:
- Use the syscon API to access the IMEM region
- Handle the error cases returned by qcom_wdt_get_restart_reason
- Define device specific data to retrieve the IMEM compatible,
offset and the value for non secure WDT, which allows to
extend the support for other SoCs
---
drivers/watchdog/qcom-wdt.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index dfaac5995c84c1f377023e6e62770c5548528a4c..f2cb8bfdf53a5090bcfff6ea3a23005b629ef948 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -7,9 +7,11 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/watchdog.h>
enum wdt_reg {
@@ -42,6 +44,9 @@ struct qcom_wdt_match_data {
const u32 *offset;
bool pretimeout;
u32 max_tick_count;
+ const char *imem_compatible;
+ unsigned int restart_reason_offset;
+ unsigned int non_secure_wdt_val;
};
struct qcom_wdt {
@@ -185,6 +190,9 @@ static const struct qcom_wdt_match_data match_data_ipq5424 = {
.offset = reg_offset_data_kpss,
.pretimeout = true,
.max_tick_count = 0xFFFFFU,
+ .imem_compatible = "qcom,ipq5424-imem",
+ .restart_reason_offset = 0x7b0,
+ .non_secure_wdt_val = 0x5,
};
static const struct qcom_wdt_match_data match_data_kpss = {
@@ -193,6 +201,29 @@ static const struct qcom_wdt_match_data match_data_kpss = {
.max_tick_count = 0xFFFFFU,
};
+static int qcom_wdt_get_restart_reason(struct qcom_wdt *wdt,
+ const struct qcom_wdt_match_data *data)
+{
+ struct regmap *imem;
+ unsigned int val;
+ int ret;
+
+ imem = syscon_regmap_lookup_by_compatible(data->imem_compatible);
+ if (IS_ERR(imem))
+ return PTR_ERR(imem);
+
+ ret = regmap_read(imem, data->restart_reason_offset, &val);
+ if (ret) {
+ dev_err(wdt->wdd.parent, "failed to read the restart reason info\n");
+ return ret;
+ }
+
+ if (val == data->non_secure_wdt_val)
+ wdt->wdd.bootstatus = WDIOF_CARDRESET;
+
+ return 0;
+}
+
static int qcom_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -273,8 +304,13 @@ static int qcom_wdt_probe(struct platform_device *pdev)
wdt->wdd.parent = dev;
wdt->layout = data->offset;
- if (readl(wdt_addr(wdt, WDT_STS)) & 1)
- wdt->wdd.bootstatus = WDIOF_CARDRESET;
+ ret = qcom_wdt_get_restart_reason(wdt, data);
+ if (ret == -ENODEV) {
+ if (readl(wdt_addr(wdt, WDT_STS)) & 1)
+ wdt->wdd.bootstatus = WDIOF_CARDRESET;
+ } else if (ret) {
+ return ret;
+ }
/*
* If 'timeout-sec' unspecified in devicetree, assume a 30 second
--
2.34.1
Powered by blists - more mailing lists