aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch')
-rw-r--r--target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch184
1 files changed, 184 insertions, 0 deletions
diff --git a/target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch b/target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch
new file mode 100644
index 0000000000..e626ff29b7
--- /dev/null
+++ b/target/linux/cns3xxx/patches-4.19/020-watchdog_support.patch
@@ -0,0 +1,184 @@
+Add a watchdog driver for ARM MPcore processors.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -375,6 +375,13 @@ config KS8695_WATCHDOG
+ Watchdog timer embedded into KS8695 processor. This will reboot your
+ system when the timeout is reached.
+
++config MPCORE_WATCHDOG
++ tristate "MPcore watchdog"
++ depends on HAVE_ARM_TWD
++ select WATCHDOG_CORE
++ help
++ Watchdog timer embedded into the MPcore system
++
+ config HAVE_S3C2410_WATCHDOG
+ bool
+ help
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -49,6 +49,7 @@ obj-$(CONFIG_977_WATCHDOG) += wdt977.o
+ obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
+ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
+ obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
++obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
+ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+ obj-$(CONFIG_SAMA5D4_WATCHDOG) += sama5d4_wdt.o
+--- /dev/null
++++ b/drivers/watchdog/mpcore_wdt.c
+@@ -0,0 +1,118 @@
++/*
++ * Watchdog driver for ARM MPcore
++ *
++ * Copyright (C) 2017 Felix Fietkau <nbd@nbd.name>
++ */
++
++#include <linux/export.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/watchdog.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <asm/smp_twd.h>
++
++static void __iomem *wdt_base;
++static int wdt_timeout = 60;
++
++static int mpcore_wdt_keepalive(struct watchdog_device *wdd)
++{
++ static int perturb;
++ u32 count;
++
++ count = (twd_timer_get_rate() / 256) * wdt_timeout;
++
++ /* Reload register needs a different value on each refresh */
++ count += perturb;
++ perturb = !perturb;
++
++ iowrite32(count, wdt_base + TWD_WDOG_LOAD);
++
++ return 0;
++}
++
++static int mpcore_wdt_start(struct watchdog_device *wdd)
++{
++ mpcore_wdt_keepalive(wdd);
++
++ /* prescale = 256, mode = 1, enable = 1 */
++ iowrite32(0x0000FF09, wdt_base + TWD_WDOG_CONTROL);
++
++ return 0;
++}
++
++static int mpcore_wdt_stop(struct watchdog_device *wdd)
++{
++ iowrite32(0x12345678, wdt_base + TWD_WDOG_DISABLE);
++ iowrite32(0x87654321, wdt_base + TWD_WDOG_DISABLE);
++ iowrite32(0x0, wdt_base + TWD_WDOG_CONTROL);
++
++ return 0;
++}
++
++static int mpcore_wdt_set_timeout(struct watchdog_device *wdd,
++ unsigned int timeout)
++{
++ mpcore_wdt_stop(wdd);
++ wdt_timeout = timeout;
++ mpcore_wdt_start(wdd);
++
++ return 0;
++}
++
++static const struct watchdog_info mpcore_wdt_info = {
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
++ .identity = "MPcore Watchdog",
++};
++
++static const struct watchdog_ops mpcore_wdt_ops = {
++ .owner = THIS_MODULE,
++ .start = mpcore_wdt_start,
++ .stop = mpcore_wdt_stop,
++ .ping = mpcore_wdt_keepalive,
++ .set_timeout = mpcore_wdt_set_timeout,
++};
++
++static struct watchdog_device mpcore_wdt = {
++ .info = &mpcore_wdt_info,
++ .ops = &mpcore_wdt_ops,
++ .min_timeout = 1,
++ .max_timeout = 65535,
++};
++
++static int mpcore_wdt_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ unsigned long rate = twd_timer_get_rate();
++
++ pr_info("MPCore WD init. clockrate: %lu prescaler: %u countrate: %lu timeout: %us\n", rate, 256, rate / 256, wdt_timeout);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENODEV;
++
++ wdt_base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(wdt_base))
++ return PTR_ERR(wdt_base);
++
++ watchdog_register_device(&mpcore_wdt);
++ return 0;
++}
++
++static int mpcore_wdt_remove(struct platform_device *dev)
++{
++ watchdog_unregister_device(&mpcore_wdt);
++ return 0;
++}
++
++static struct platform_driver mpcore_wdt_driver = {
++ .probe = mpcore_wdt_probe,
++ .remove = mpcore_wdt_remove,
++ .driver = {
++ .name = "mpcore_wdt",
++ },
++};
++
++module_platform_driver(mpcore_wdt_driver);
++MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
++MODULE_LICENSE("GPL");
+--- a/arch/arm/include/asm/smp_twd.h
++++ b/arch/arm/include/asm/smp_twd.h
+@@ -34,5 +34,6 @@ struct twd_local_timer name __initdata =
+ };
+
+ int twd_local_timer_register(struct twd_local_timer *);
++unsigned long twd_timer_get_rate(void);
+
+ #endif
+--- a/arch/arm/kernel/smp_twd.c
++++ b/arch/arm/kernel/smp_twd.c
+@@ -15,6 +15,7 @@
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/err.h>
++#include <linux/export.h>
+ #include <linux/smp.h>
+ #include <linux/jiffies.h>
+ #include <linux/clockchips.h>
+@@ -380,6 +381,14 @@ int __init twd_local_timer_register(stru
+ return twd_local_timer_common_register(NULL);
+ }
+
++/* Needed by mpcore_wdt */
++unsigned long twd_timer_get_rate(void)
++{
++ return twd_timer_rate;
++}
++EXPORT_SYMBOL_GPL(twd_timer_get_rate);
++
++
+ #ifdef CONFIG_OF
+ static int __init twd_local_timer_of_register(struct device_node *np)
+ {