diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index dfaac5995c84..49bd04841f0c 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ struct qcom_wdt_match_data { const u32 *offset; bool pretimeout; u32 max_tick_count; + u32 wdt_reason_val; }; struct qcom_wdt { @@ -185,6 +187,7 @@ static const struct qcom_wdt_match_data match_data_ipq5424 = { .offset = reg_offset_data_kpss, .pretimeout = true, .max_tick_count = 0xFFFFFU, + .wdt_reason_val = 5, }; static const struct qcom_wdt_match_data match_data_kpss = { @@ -193,6 +196,40 @@ static const struct qcom_wdt_match_data match_data_kpss = { .max_tick_count = 0xFFFFFU, }; +static int qcom_wdt_get_bootstatus(struct device *dev, struct qcom_wdt *wdt, + u32 val) +{ + struct device_node *imem; + struct resource res; + void __iomem *addr; + int ret; + + imem = of_parse_phandle(dev->of_node, "sram", 0); + if (!imem) { + /* Read the EXPIRED_STATUS bit as a fallback */ + if (readl(wdt_addr(wdt, WDT_STS)) & 1) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + + return 0; + } + + ret = of_address_to_resource(imem, 0, &res); + of_node_put(imem); + if (ret) + return ret; + + addr = ioremap(res.start, resource_size(&res)); + if (!addr) + return -ENOMEM; + + if (readl(addr) == val) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + + iounmap(addr); + + return 0; +} + static int qcom_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -273,8 +310,9 @@ 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_bootstatus(dev, wdt, data->wdt_reason_val); + if (ret) + dev_err(dev, "failed to get the bootstatus, %d\n", ret); /* * If 'timeout-sec' unspecified in devicetree, assume a 30 second