From 000de5417107623925a4cf0310579f744ff43c28 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Tue, 4 Feb 2020 20:56:48 +0100 Subject: watchdog: qcom-wdt: disable pretimeout on timer platform Some platform like ipq806x doesn't support pretimeout and define some interrupts used by qcom,msm-timer. Change the driver to check and use pretimeout only on qcom,kpss-wdt as it's the only platform that actually supports it. Signed-off-by: Ansuel Smith Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200204195648.23350-1-ansuelsmth@gmail.com [groeck: Conflict resolution] Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/qcom-wdt.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index eb47fe5ed280..460967a02da3 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -40,6 +40,11 @@ static const u32 reg_offset_data_kpss[] = { [WDT_BITE_TIME] = 0x14, }; +struct qcom_wdt_match_data { + const u32 *offset; + bool pretimeout; +}; + struct qcom_wdt { struct watchdog_device wdd; unsigned long rate; @@ -179,19 +184,29 @@ static void qcom_clk_disable_unprepare(void *data) clk_disable_unprepare(data); } +static const struct qcom_wdt_match_data match_data_apcs_tmr = { + .offset = reg_offset_data_apcs_tmr, + .pretimeout = false, +}; + +static const struct qcom_wdt_match_data match_data_kpss = { + .offset = reg_offset_data_kpss, + .pretimeout = true, +}; + static int qcom_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct qcom_wdt *wdt; struct resource *res; struct device_node *np = dev->of_node; - const u32 *regs; + const struct qcom_wdt_match_data *data; u32 percpu_offset; int irq, ret; struct clk *clk; - regs = of_device_get_match_data(dev); - if (!regs) { + data = of_device_get_match_data(dev); + if (!data) { dev_err(dev, "Unsupported QCOM WDT module\n"); return -ENODEV; } @@ -247,7 +262,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) /* check if there is pretimeout support */ irq = platform_get_irq_optional(pdev, 0); - if (irq > 0) { + if (data->pretimeout && irq > 0) { ret = devm_request_irq(dev, irq, qcom_wdt_isr, IRQF_TRIGGER_RISING, "wdt_bark", &wdt->wdd); @@ -267,7 +282,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.min_timeout = 1; wdt->wdd.max_timeout = 0x10000000U / wdt->rate; wdt->wdd.parent = dev; - wdt->layout = regs; + wdt->layout = data->offset; if (readl(wdt_addr(wdt, WDT_STS)) & 1) wdt->wdd.bootstatus = WDIOF_CARDRESET; @@ -311,9 +326,9 @@ static int __maybe_unused qcom_wdt_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume); static const struct of_device_id qcom_wdt_of_table[] = { - { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr }, - { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr }, - { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss }, + { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr }, + { .compatible = "qcom,scss-timer", .data = &match_data_apcs_tmr }, + { .compatible = "qcom,kpss-wdt", .data = &match_data_kpss }, { }, }; MODULE_DEVICE_TABLE(of, qcom_wdt_of_table); -- cgit v1.2.3 From b1413e6edc5ab55d77cfa2a0b45f4918c5e97e0f Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 11 Feb 2020 16:38:03 +0100 Subject: watchdog: pm8916_wdt: Add system sleep callbacks Add suspend and resume pm operations. Tested on dragonboard-410c. Signed-off-by: Loic Poulain Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1581435483-6796-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/pm8916_wdt.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/watchdog/pm8916_wdt.c b/drivers/watchdog/pm8916_wdt.c index 1213179f863c..0937b8d33104 100644 --- a/drivers/watchdog/pm8916_wdt.c +++ b/drivers/watchdog/pm8916_wdt.c @@ -192,6 +192,7 @@ static int pm8916_wdt_probe(struct platform_device *pdev) wdt->wdev.timeout = PM8916_WDT_DEFAULT_TIMEOUT; wdt->wdev.pretimeout = 0; watchdog_set_drvdata(&wdt->wdev, wdt); + platform_set_drvdata(pdev, wdt); watchdog_init_timeout(&wdt->wdev, 0, dev); pm8916_wdt_configure_timers(&wdt->wdev); @@ -199,6 +200,29 @@ static int pm8916_wdt_probe(struct platform_device *pdev) return devm_watchdog_register_device(dev, &wdt->wdev); } +static int __maybe_unused pm8916_wdt_suspend(struct device *dev) +{ + struct pm8916_wdt *wdt = dev_get_drvdata(dev); + + if (watchdog_active(&wdt->wdev)) + return pm8916_wdt_stop(&wdt->wdev); + + return 0; +} + +static int __maybe_unused pm8916_wdt_resume(struct device *dev) +{ + struct pm8916_wdt *wdt = dev_get_drvdata(dev); + + if (watchdog_active(&wdt->wdev)) + return pm8916_wdt_start(&wdt->wdev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(pm8916_wdt_pm_ops, pm8916_wdt_suspend, + pm8916_wdt_resume); + static const struct of_device_id pm8916_wdt_id_table[] = { { .compatible = "qcom,pm8916-wdt" }, { } @@ -210,6 +234,7 @@ static struct platform_driver pm8916_wdt_driver = { .driver = { .name = "pm8916-wdt", .of_match_table = of_match_ptr(pm8916_wdt_id_table), + .pm = &pm8916_wdt_pm_ops, }, }; module_platform_driver(pm8916_wdt_driver); -- cgit v1.2.3 From cc9cc794c329a9c4d0c1056b4b1f1632e9db0b8c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 19 Feb 2020 16:20:47 -0800 Subject: watchdog: qcom: Use irq flags from firmware The DT or ACPI tables should tell the driver what the irq flags are. Given that this driver probes only on DT based platforms and those DT platforms specify the irq flags we can safely drop the forced irq flag setting here. Cc: Andy Gross Cc: Bjorn Andersson Cc: Sai Prakash Ranjan Signed-off-by: Stephen Boyd Reviewed-by: Bjorn Andersson Reviewed-by: Guenter Roeck Reviewed-by: Sai Prakash Ranjan Link: https://lore.kernel.org/r/20200220002047.115000-1-swboyd@chromium.org [groeck: Context conflict resolution] Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/qcom-wdt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 460967a02da3..ab7465d186fd 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -263,8 +263,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) /* check if there is pretimeout support */ irq = platform_get_irq_optional(pdev, 0); if (data->pretimeout && irq > 0) { - ret = devm_request_irq(dev, irq, qcom_wdt_isr, - IRQF_TRIGGER_RISING, + ret = devm_request_irq(dev, irq, qcom_wdt_isr, 0, "wdt_bark", &wdt->wdd); if (ret) return ret; -- cgit v1.2.3 From 15a2638ab46d5da1accc224e566d319d8d9a521e Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 21 Feb 2020 10:00:28 +0800 Subject: watchdog: imx_sc_wdt: Remove unused includes There is nothing in use from init.h/reboot.h, remove them. Signed-off-by: Anson Huang Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1582250430-8872-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imx_sc_wdt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c index 8ed89f032ebf..60a32469f7de 100644 --- a/drivers/watchdog/imx_sc_wdt.c +++ b/drivers/watchdog/imx_sc_wdt.c @@ -6,13 +6,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #define DEFAULT_TIMEOUT 60 -- cgit v1.2.3 From dca96e0117a040b2898899a32f9cbac3082dd3b2 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 21 Feb 2020 10:00:29 +0800 Subject: watchdog: imx7ulp: Remove unused include of init.h There is nothing in use from init.h, remove it. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1582250430-8872-2-git-send-email-Anson.Huang@nxp.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imx7ulp_wdt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c index 11b9e7c6b7f5..7993c8c41b3a 100644 --- a/drivers/watchdog/imx7ulp_wdt.c +++ b/drivers/watchdog/imx7ulp_wdt.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include -- cgit v1.2.3 From 3f9d51333129e16d77dcc9414bd548151d884c8a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 29 Feb 2020 12:50:46 +0100 Subject: watchdog: wm831x_wdt: Remove GPIO handling An attempt to convert the driver to using GPIO descriptors (see Link tag) was discouraged in favor of deleting the handling of the update GPIO altogehter since there are no in-tree users. This patch deletes the GPIO handling instead. Cc: Richard Fitzgerald Cc: Charles Keepax Cc: Mark Brown Link: https://lore.kernel.org/linux-watchdog/20200210102209.289379-1-linus.walleij@linaro.org/ Signed-off-by: Linus Walleij Reviewed-by: Guenter Roeck Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20200229115046.57781-1-linus.walleij@linaro.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/wm831x_wdt.c | 27 --------------------------- include/linux/mfd/wm831x/pdata.h | 1 - 2 files changed, 28 deletions(-) diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 030ce240620d..d96ad8f38bd2 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -29,7 +28,6 @@ struct wm831x_wdt_drvdata { struct watchdog_device wdt; struct wm831x *wm831x; struct mutex lock; - int update_gpio; int update_state; }; @@ -103,14 +101,6 @@ static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) mutex_lock(&driver_data->lock); - if (driver_data->update_gpio) { - gpio_set_value_cansleep(driver_data->update_gpio, - driver_data->update_state); - driver_data->update_state = !driver_data->update_state; - ret = 0; - goto out; - } - reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (!(reg & WM831X_WDOG_RST_SRC)) { @@ -239,23 +229,6 @@ static int wm831x_wdt_probe(struct platform_device *pdev) reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT; reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; - if (pdata->update_gpio) { - ret = devm_gpio_request_one(dev, pdata->update_gpio, - GPIOF_OUT_INIT_LOW, - "Watchdog update"); - if (ret < 0) { - dev_err(wm831x->dev, - "Failed to request update GPIO: %d\n", - ret); - return ret; - } - - driver_data->update_gpio = pdata->update_gpio; - - /* Make sure the watchdog takes hardware updates */ - reg |= WM831X_WDOG_RST_SRC; - } - ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index 986986fe4e4e..75aa94dadf1c 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -89,7 +89,6 @@ enum wm831x_watchdog_action { struct wm831x_watchdog_pdata { enum wm831x_watchdog_action primary, secondary; - int update_gpio; unsigned int software:1; }; -- cgit v1.2.3 From 9232c80659e941ffa6c7bfc96bd64c6172ef0452 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sun, 23 Feb 2020 11:49:39 +0000 Subject: watchdog: Add stop_on_reboot parameter to control reboot policy Many watchdog drivers use watchdog_stop_on_reboot() helper in order to stop the watchdog on system reboot. Unfortunately, this logic is coded in driver's probe function and doesn't allows user to decide what to do during shutdown/reboot. On the other side, Xen and Qemu watchdog drivers (xen_wdt and i6300esb) may be configured to either send NMI or turn off/reboot VM as the watchdog action. As the kernel may stuck at any state, sending NMIs can't reliably reboot the VM. At Arista, we benefited from the following set-up: the emulated watchdogs trigger VM reset and softdog is set to catch less severe conditions to generate vmcore. Just before reboot watchdog's timeout is increased to some good-enough value (3 mins). That keeps watchdog always running and guarantees that VM doesn't stuck. Provide new stop_on_reboot module parameter to let user control watchdog's reboot policy. Cc: Guenter Roeck Cc: Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org Signed-off-by: Dmitry Safonov Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200223114939.194754-1-dima@arista.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 861daf4f37b2..423844757812 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -39,6 +39,10 @@ static DEFINE_IDA(watchdog_ida); +static int stop_on_reboot = -1; +module_param(stop_on_reboot, int, 0444); +MODULE_PARM_DESC(stop_on_reboot, "Stop watchdogs on reboot (0=keep watching, 1=stop)"); + /* * Deferred Registration infrastructure. * @@ -254,6 +258,14 @@ static int __watchdog_register_device(struct watchdog_device *wdd) } } + /* Module parameter to force watchdog policy on reboot. */ + if (stop_on_reboot != -1) { + if (stop_on_reboot) + set_bit(WDOG_STOP_ON_REBOOT, &wdd->status); + else + clear_bit(WDOG_STOP_ON_REBOOT, &wdd->status); + } + if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) { wdd->reboot_nb.notifier_call = watchdog_reboot_notifier; -- cgit v1.2.3 From 436867b6469a2ae38f6b5725aeeeb8211a2aca15 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 24 Feb 2020 10:51:27 +0800 Subject: watchdog: imx2_wdt: Drop .remove callback .remove callback implementation doesn' call clk_disable_unprepare() which is buggy, actually, we can just use devm_watchdog_register_device() and devm_add_action_or_reset() to handle all necessary operations for remove action, then .remove callback can be dropped. Signed-off-by: Anson Huang Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1582512687-13312-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imx2_wdt.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index f8d58bf0bf66..1fe472f56cb3 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -244,6 +244,11 @@ static const struct regmap_config imx2_wdt_regmap_config = { .max_register = 0x8, }; +static void imx2_wdt_action(void *data) +{ + clk_disable_unprepare(data); +} + static int __init imx2_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -292,6 +297,10 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) if (ret) return ret; + ret = devm_add_action_or_reset(dev, imx2_wdt_action, wdev->clk); + if (ret) + return ret; + regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val); wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0; @@ -315,32 +324,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) */ regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0); - ret = watchdog_register_device(wdog); - if (ret) - goto disable_clk; - - dev_info(dev, "timeout %d sec (nowayout=%d)\n", - wdog->timeout, nowayout); - - return 0; - -disable_clk: - clk_disable_unprepare(wdev->clk); - return ret; -} - -static int __exit imx2_wdt_remove(struct platform_device *pdev) -{ - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); - - watchdog_unregister_device(wdog); - - if (imx2_wdt_is_running(wdev)) { - imx2_wdt_ping(wdog); - dev_crit(&pdev->dev, "Device removed: Expect reboot!\n"); - } - return 0; + return devm_watchdog_register_device(dev, wdog); } static void imx2_wdt_shutdown(struct platform_device *pdev) @@ -417,7 +401,6 @@ static const struct of_device_id imx2_wdt_dt_ids[] = { MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids); static struct platform_driver imx2_wdt_driver = { - .remove = __exit_p(imx2_wdt_remove), .shutdown = imx2_wdt_shutdown, .driver = { .name = DRIVER_NAME, -- cgit v1.2.3 From 982bb70517aef2225bad1d802887b733db492cc0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 12 Mar 2020 11:58:06 +0200 Subject: watchdog: reset last_hw_keepalive time at start Currently the watchdog core does not initialize the last_hw_keepalive time during watchdog startup. This will cause the watchdog to be pinged immediately if enough time has passed from the system boot-up time, and some types of watchdogs like K3 RTI does not like this. To avoid the issue, setup the last_hw_keepalive time during watchdog startup. Signed-off-by: Tero Kristo Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200302200426.6492-3-t-kristo@ti.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 8b5c742f24e8..7e4cd34a8c20 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -282,6 +282,7 @@ static int watchdog_start(struct watchdog_device *wdd) if (err == 0) { set_bit(WDOG_ACTIVE, &wdd->status); wd_data->last_keepalive = started_at; + wd_data->last_hw_keepalive = started_at; watchdog_update_worker(wdd); } -- cgit v1.2.3 From f667421324ed89a545b8d7efc69284059ea28d21 Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Tue, 3 Mar 2020 12:01:14 +0200 Subject: watchdog: npcm: remove whitespaces Signed-off-by: Tomer Maimon Link: https://lore.kernel.org/r/20200303100114.87786-4-tmaimon77@gmail.com Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/npcm_wdt.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c index 9c773c3d6d5d..765577f11c8d 100644 --- a/drivers/watchdog/npcm_wdt.c +++ b/drivers/watchdog/npcm_wdt.c @@ -103,30 +103,29 @@ static int npcm_wdt_stop(struct watchdog_device *wdd) return 0; } - static int npcm_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) { if (timeout < 2) wdd->timeout = 1; else if (timeout < 3) - wdd->timeout = 2; + wdd->timeout = 2; else if (timeout < 6) - wdd->timeout = 5; + wdd->timeout = 5; else if (timeout < 11) - wdd->timeout = 10; + wdd->timeout = 10; else if (timeout < 22) - wdd->timeout = 21; + wdd->timeout = 21; else if (timeout < 44) - wdd->timeout = 43; + wdd->timeout = 43; else if (timeout < 87) - wdd->timeout = 86; + wdd->timeout = 86; else if (timeout < 173) - wdd->timeout = 172; + wdd->timeout = 172; else if (timeout < 688) - wdd->timeout = 687; + wdd->timeout = 687; else - wdd->timeout = 2750; + wdd->timeout = 2750; if (watchdog_active(wdd)) npcm_wdt_start(wdd); -- cgit v1.2.3 From bb914088bd8a91c382f54d469367b2e5508b5493 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 13 Mar 2020 16:13:12 +1300 Subject: watchdog: orion: use 0 for unset heartbeat If the heartbeat module param is not specified we would get an error message watchdog: f1020300.watchdog: driver supplied timeout (4294967295) out of range watchdog: f1020300.watchdog: falling back to default timeout (171) This is because we were initialising heartbeat to -1. By removing the initialisation (thus letting the C run time initialise it to 0) we silence the warning message and the default timeout is still used. Signed-off-by: Chris Packham Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200313031312.1485-1-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/orion_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 8e6dfe76f9c9..4ddb4ea2e4a3 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -52,7 +52,7 @@ #define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) static bool nowayout = WATCHDOG_NOWAYOUT; -static int heartbeat = -1; /* module parameter (seconds) */ +static int heartbeat; /* module parameter (seconds) */ struct orion_watchdog; -- cgit v1.2.3 From e2ad9bca45496681b0e954845da49e6e1a731b79 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 13 Mar 2020 11:11:38 +0100 Subject: watchdog: ziirave_wdt: change name to be more specific The RAVE watchdog is not a full system watchdog, but is used to reset ethernet switch when required. Change the name to better reflect this usage. Signed-off-by: Lucas Stach Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200313101138.25915-1-l.stach@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/ziirave_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c index 4a363a8b2d20..cab86a08456b 100644 --- a/drivers/watchdog/ziirave_wdt.c +++ b/drivers/watchdog/ziirave_wdt.c @@ -422,7 +422,7 @@ static int ziirave_firm_upload(struct watchdog_device *wdd, static const struct watchdog_info ziirave_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, - .identity = "Zodiac RAVE Watchdog", + .identity = "RAVE Switch Watchdog", }; static const struct watchdog_ops ziirave_wdt_ops = { -- cgit v1.2.3 From 936253d7e904d64767819fc7c8c97bbe7821ff12 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 12 Mar 2020 11:58:05 +0200 Subject: dt-bindings: watchdog: Add support for TI K3 RTI watchdog TI K3 SoCs contain an RTI (Real Time Interrupt) module which can be used to implement a windowed watchdog functionality. Windowed watchdog will generate an error if it is petted outside the time window, either too early or too late. Cc: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Tero Kristo Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200312095808.19907-2-t-kristo@ti.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../devicetree/bindings/watchdog/ti,rti-wdt.yaml | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml diff --git a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml new file mode 100644 index 000000000000..e83026fef2e9 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/ti,rti-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments K3 SoC Watchdog Timer + +maintainers: + - Tero Kristo + +description: + The TI K3 SoC watchdog timer is implemented via the RTI (Real Time + Interrupt) IP module. This timer adds a support for windowed watchdog + mode, which will signal an error if it is pinged outside the watchdog + time window, meaning either too early or too late. The error signal + generated can be routed to either interrupt a safety controller or + to directly reset the SoC. + +allOf: + - $ref: "watchdog.yaml#" + +properties: + compatible: + enum: + - ti,j7-rti-wdt + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + assigned-clocks: + maxItems: 1 + + assigned-clocks-parents: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - power-domains + +examples: + - | + /* + * RTI WDT in main domain on J721e SoC. Assigned clocks are used to + * select the source clock for the watchdog, forcing it to tick with + * a 32kHz clock in this case. + */ + #include + + watchdog0: rti@2200000 { + compatible = "ti,rti-wdt"; + reg = <0x0 0x2200000 0x0 0x100>; + clocks = <&k3_clks 252 1>; + power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 252 1>; + assigned-clock-parents = <&k3_clks 252 5>; + }; -- cgit v1.2.3 From 2d63908bdbfbce0d98195b22236ad5105dc6eba2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 12 Mar 2020 11:58:07 +0200 Subject: watchdog: Add K3 RTI watchdog support Texas Instruments K3 SoCs contain an RTI (Real Time Interrupt) module which can be used as a watchdog. This IP provides a support for windowed watchdog mode, in which the watchdog must be petted within a certain time window. If it is petted either too soon, or too late, a watchdog error will be triggered. Signed-off-by: Tero Kristo Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200312095808.19907-4-t-kristo@ti.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 8 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/rti_wdt.c | 255 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 drivers/watchdog/rti_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9ea2b43d4b01..0663c604bd64 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -584,6 +584,14 @@ config DAVINCI_WATCHDOG NOTE: once enabled, this timer cannot be disabled. Say N if you are unsure. +config K3_RTI_WATCHDOG + tristate "Texas Instruments K3 RTI watchdog" + depends on ARCH_K3 || COMPILE_TEST + select WATCHDOG_CORE + help + Say Y here if you want to include support for the K3 watchdog + timer (RTI module) available in the K3 generation of processors. + config ORION_WATCHDOG tristate "Orion watchdog" depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || (COMPILE_TEST && !ARCH_EBSA110) diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 2ee352bf3372..6de2e4ceef19 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o +obj-$(CONFIG_K3_RTI_WATCHDOG) += rti_wdt.o obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c new file mode 100644 index 000000000000..d456dd72d99a --- /dev/null +++ b/drivers/watchdog/rti_wdt.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Watchdog driver for the K3 RTI module + * + * (c) Copyright 2019-2020 Texas Instruments Inc. + * All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_HEARTBEAT 60 + +/* Max heartbeat is calculated at 32kHz source clock */ +#define MAX_HEARTBEAT 1000 + +/* Timer register set definition */ +#define RTIDWDCTRL 0x90 +#define RTIDWDPRLD 0x94 +#define RTIWDSTATUS 0x98 +#define RTIWDKEY 0x9c +#define RTIDWDCNTR 0xa0 +#define RTIWWDRXCTRL 0xa4 +#define RTIWWDSIZECTRL 0xa8 + +#define RTIWWDRX_NMI 0xa + +#define RTIWWDSIZE_50P 0x50 + +#define WDENABLE_KEY 0xa98559da + +#define WDKEY_SEQ0 0xe51a +#define WDKEY_SEQ1 0xa35c + +#define WDT_PRELOAD_SHIFT 13 + +#define WDT_PRELOAD_MAX 0xfff + +#define DWDST BIT(1) + +static int heartbeat; + +/* + * struct to hold data for each WDT device + * @base - base io address of WD device + * @freq - source clock frequency of WDT + * @wdd - hold watchdog device as is in WDT core + */ +struct rti_wdt_device { + void __iomem *base; + unsigned long freq; + struct watchdog_device wdd; +}; + +static int rti_wdt_start(struct watchdog_device *wdd) +{ + u32 timer_margin; + struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); + + /* set timeout period */ + timer_margin = (u64)wdd->timeout * wdt->freq; + timer_margin >>= WDT_PRELOAD_SHIFT; + if (timer_margin > WDT_PRELOAD_MAX) + timer_margin = WDT_PRELOAD_MAX; + writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD); + + /* + * RTI only supports a windowed mode, where the watchdog can only + * be petted during the open window; not too early or not too late. + * The HW configuration options only allow for the open window size + * to be 50% or less than that; we obviouly want to configure the open + * window as large as possible so we select the 50% option. To avoid + * any glitches, we accommodate 5% safety margin also, so we setup + * the min_hw_hearbeat at 55% of the timeout period. + */ + wdd->min_hw_heartbeat_ms = 11 * wdd->timeout * 1000 / 20; + + /* Generate NMI when wdt expires */ + writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL); + + /* Open window size 50%; this is the largest window size available */ + writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL); + + readl_relaxed(wdt->base + RTIWWDSIZECTRL); + + /* enable watchdog */ + writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL); + return 0; +} + +static int rti_wdt_ping(struct watchdog_device *wdd) +{ + struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); + + /* put watchdog in service state */ + writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY); + /* put watchdog in active state */ + writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY); + + return 0; +} + +static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd) +{ + u64 timer_counter; + u32 val; + struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); + + /* if timeout has occurred then return 0 */ + val = readl_relaxed(wdt->base + RTIWDSTATUS); + if (val & DWDST) + return 0; + + timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR); + + do_div(timer_counter, wdt->freq); + + return timer_counter; +} + +static const struct watchdog_info rti_wdt_info = { + .options = WDIOF_KEEPALIVEPING, + .identity = "K3 RTI Watchdog", +}; + +static const struct watchdog_ops rti_wdt_ops = { + .owner = THIS_MODULE, + .start = rti_wdt_start, + .ping = rti_wdt_ping, + .get_timeleft = rti_wdt_get_timeleft, +}; + +static int rti_wdt_probe(struct platform_device *pdev) +{ + int ret = 0; + struct device *dev = &pdev->dev; + struct resource *wdt_mem; + struct watchdog_device *wdd; + struct rti_wdt_device *wdt; + struct clk *clk; + + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(clk); + } + + wdt->freq = clk_get_rate(clk); + + clk_put(clk); + + if (!wdt->freq) { + dev_err(dev, "Failed to get fck rate.\n"); + return -EINVAL; + } + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "runtime pm failed\n"); + return ret; + } + + platform_set_drvdata(pdev, wdt); + + wdd = &wdt->wdd; + wdd->info = &rti_wdt_info; + wdd->ops = &rti_wdt_ops; + wdd->min_timeout = 1; + wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) / + wdt->freq * 1000; + wdd->timeout = DEFAULT_HEARTBEAT; + wdd->parent = dev; + + watchdog_init_timeout(wdd, heartbeat, dev); + + watchdog_set_drvdata(wdd, wdt); + watchdog_set_nowayout(wdd, 1); + watchdog_set_restart_priority(wdd, 128); + + wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->base = devm_ioremap_resource(dev, wdt_mem); + if (IS_ERR(wdt->base)) { + ret = PTR_ERR(wdt->base); + goto err_iomap; + } + + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(dev, "cannot register watchdog device\n"); + goto err_iomap; + } + + return 0; + +err_iomap: + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static int rti_wdt_remove(struct platform_device *pdev) +{ + struct rti_wdt_device *wdt = platform_get_drvdata(pdev); + + watchdog_unregister_device(&wdt->wdd); + pm_runtime_put(&pdev->dev); + + return 0; +} + +static const struct of_device_id rti_wdt_of_match[] = { + { .compatible = "ti,j7-rti-wdt", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rti_wdt_of_match); + +static struct platform_driver rti_wdt_driver = { + .driver = { + .name = "rti-wdt", + .of_match_table = rti_wdt_of_match, + }, + .probe = rti_wdt_probe, + .remove = rti_wdt_remove, +}; + +module_platform_driver(rti_wdt_driver); + +MODULE_AUTHOR("Tero Kristo "); +MODULE_DESCRIPTION("K3 RTI Watchdog Driver"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, + "Watchdog heartbeat period in seconds from 1 to " + __MODULE_STRING(MAX_HEARTBEAT) ", default " + __MODULE_STRING(DEFAULT_HEARTBEAT)); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rti-wdt"); -- cgit v1.2.3