summaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorRobin Gong <yibin.gong@nxp.com>2017-10-27 09:40:30 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commitbb44c6e244b9a5c2cf710568044ec54f01c18c08 (patch)
tree12221f4da6bac25f7d1c4971c63eedcc9358d3c6 /drivers/watchdog
parentf856f2349c63c88484619e3e1d855664e4aeec18 (diff)
MLK-16704-1: watchdog: imx8_wdt: add watchdog driver for i.mx8QM/QXP
This watchdog driver is a virtual driver in Linux and call ATF interface where call SCFW eventually. In SCFW, it's done by SCU timer tick instead of hardware watchdog.This is why we have to call ATF because such system resource owned by secure patition.Currently, booard reset happen if not ping this software watchdog in time in linux side, may change to partition reboot once SCFW support this feature in the future. BuildInfo: - SCFW 93c142a9, IMX-MKIMAGE 2522fd70, ATF f2547fb - U-Boot 2017.03-00097-gd7599cf Signed-off-by: Robin Gong <yibin.gong@nxp.com> Reviewed-by: Anson Huang <Anson.Huang@nxp.com>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig11
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/imx8_wdt.c159
3 files changed, 171 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6613799bdf9f..523e6a73664e 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -565,6 +565,17 @@ config IMX7ULP_WDT
To compile this driver as a module, choose M here: the
module will be called imx7ulp_wdt.
+config IMX8_WDT
+ tristate "IMX8 Watchdog"
+ depends on OF
+ select WATCHDOG_CORE
+ help
+ This is the driver for the watchdog on i.mx8QM/QXP
+ and later processors, this virtual watch dog call
+ the interfaces which provided by SCFW.
+ If you have one of these processors and wish to have
+ watchdog support enabled, say Y, otherwise say N.
+
config UX500_WATCHDOG
tristate "ST-Ericsson Ux500 watchdog"
depends on MFD_DB8500_PRCMU
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 1954250cb07c..3d2a0f8277e5 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
obj-$(CONFIG_IMX7ULP_WDT) += imx7ulp_wdt.o
+obj-$(CONFIG_IMX8_WDT) += imx8_wdt.o
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
diff --git a/drivers/watchdog/imx8_wdt.c b/drivers/watchdog/imx8_wdt.c
new file mode 100644
index 000000000000..108337736974
--- /dev/null
+++ b/drivers/watchdog/imx8_wdt.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+#include <soc/imx/fsl_sip.h>
+
+#define DEFAULT_TIMEOUT 10
+/*
+ * Software timer tick implemented in scfw side, support 10ms to 0xffffffff ms
+ * in theory, but for normal case, 1s~60s is enough, you can change this max
+ * value in case it's not enough.
+ */
+#define MAX_TIMEOUT 60
+
+static struct watchdog_device imx8_wdd;
+
+static int imx8_wdt_ping(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_PING_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static int imx8_wdt_start(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ /* no block */
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_START_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+ if (res.a0)
+ return res.a0;
+ /* TODO: change to SC_TIMER_WDOG_ACTION_PARTITION after SCFW support */
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_WDOG_ACT,
+ SC_TIMER_WDOG_ACTION_BOARD, 0, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static int imx8_wdt_stop(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_STOP_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static int imx8_wdt_set_timeout(struct watchdog_device *wdog,
+ unsigned int timeout)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_TIMEOUT_WDOG,
+ timeout * 1000, 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static const struct watchdog_ops imx8_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = imx8_wdt_start,
+ .stop = imx8_wdt_stop,
+ .ping = imx8_wdt_ping,
+ .set_timeout = imx8_wdt_set_timeout,
+};
+
+static const struct watchdog_info imx8_wdt_info = {
+ .identity = "i.MX8 watchdog timer",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static int imx8_wdt_probe(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = &imx8_wdd;
+ int err;
+
+ platform_set_drvdata(pdev, wdt);
+ /* init the wdd */
+ wdt->info = &imx8_wdt_info;
+ wdt->ops = &imx8_wdt_ops;
+ wdt->min_timeout = 1;
+ wdt->max_timeout = MAX_TIMEOUT;
+ wdt->parent = &pdev->dev;
+ watchdog_set_drvdata(wdt, NULL);
+
+ err = watchdog_init_timeout(wdt, DEFAULT_TIMEOUT, &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init the wdog timeout:%d\n",
+ err);
+ return err;
+ }
+
+ err = watchdog_register_device(wdt);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register watchdog device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int imx8_wdt_remove(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+
+ imx8_wdt_stop(wdt);
+
+ watchdog_unregister_device(wdt);
+
+ return 0;
+}
+
+static void imx8_wdt_shutdown(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+
+ if (watchdog_active(wdt))
+ imx8_wdt_stop(wdt);
+}
+
+static const struct of_device_id imx8_wdt_dt_ids[] = {
+ { .compatible = "fsl,imx8-wdt", },
+ { /*sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8_wdt_dt_ids);
+
+static struct platform_driver imx8_wdt_driver = {
+ .probe = imx8_wdt_probe,
+ .remove = imx8_wdt_remove,
+ .shutdown = imx8_wdt_shutdown,
+ .driver = {
+ .name = "imx8-wdt",
+ .of_match_table = imx8_wdt_dt_ids,
+ },
+};
+
+module_platform_driver(imx8_wdt_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8 watchdog driver");
+MODULE_LICENSE("GPL v2");