summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gong <yibin.gong@nxp.com>2017-10-27 09:40:30 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:28:55 +0800
commit3582decf35940566ed5eb43393c422315931f183 (patch)
tree031c9c52e5e7ed088c7b1ddde6b26e6715a75c29
parent0eb7a60645d7b065b2a3fafd73b15f6fb84ca04d (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>
-rw-r--r--Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt3
-rw-r--r--drivers/watchdog/Kconfig11
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/imx8_wdt.c159
-rw-r--r--include/soc/imx/fsl_sip.h10
5 files changed, 184 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
index 107280ef0025..10771fbf9c63 100644
--- a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
@@ -5,6 +5,9 @@ Required properties:
- reg : Should contain WDT registers location and length
- interrupts : Should contain WDT interrupt
+For imx8-wdt, it's a software watchdog which implemented by timer tick
+in SCFW. In this case, only compatible name required.
+
Optional properties:
- big-endian: If present the watchdog device's registers are implemented
in big endian mode, otherwise in native mode(same with CPU), for more
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6bdcc08d7cf8..1fc695ace26a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -596,6 +596,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 991084b6050f..428cd57f9ffb 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -67,6 +67,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");
diff --git a/include/soc/imx/fsl_sip.h b/include/soc/imx/fsl_sip.h
index 75459b10dd82..1f4e31933e0e 100644
--- a/include/soc/imx/fsl_sip.h
+++ b/include/soc/imx/fsl_sip.h
@@ -22,6 +22,11 @@
#define FSL_SIP_SRTC 0xC2000002
#define FSL_SIP_SRTC_SET_TIME 0x00
+#define FSL_SIP_SRTC_START_WDOG 0x01
+#define FSL_SIP_SRTC_STOP_WDOG 0x02
+#define FSL_SIP_SRTC_SET_WDOG_ACT 0x03
+#define FSL_SIP_SRTC_PING_WDOG 0x04
+#define FSL_SIP_SRTC_SET_TIMEOUT_WDOG 0x05
#define IMX8MQ_PD_MIPI 0
#define IMX8MQ_PD_PCIE1 1
@@ -35,4 +40,9 @@
#define IMX8MQ_PD_MIPI_CSI2 9
#define IMX8MQ_PD_PCIE2 10
+#define SC_TIMER_WDOG_ACTION_PARTITION 0 /*!< Reset partition */
+#define SC_TIMER_WDOG_ACTION_WARM 1 /*!< Warm reset system */
+#define SC_TIMER_WDOG_ACTION_COLD 2 /*!< Cold reset system */
+#define SC_TIMER_WDOG_ACTION_BOARD 3 /*!< Reset board */
+
#endif