watchdog:rit_wdt: Add support for WDIOF_CARDRESET
[linux-2.6-microblaze.git] / drivers / watchdog / rti_wdt.c
index ce8f18e..8e1be7b 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/types.h>
 
 #define DWDST                  BIT(1)
 
+#define PON_REASON_SOF_NUM     0xBBBBCCCC
+#define PON_REASON_MAGIC_NUM   0xDDDDDDDD
+#define PON_REASON_EOF_NUM     0xCCCCBBBB
+#define RESERVED_MEM_MIN_SIZE  12
+
 static int heartbeat = DEFAULT_HEARTBEAT;
 
 /*
@@ -198,6 +205,11 @@ static int rti_wdt_probe(struct platform_device *pdev)
        struct rti_wdt_device *wdt;
        struct clk *clk;
        u32 last_ping = 0;
+       struct device_node *node;
+       u32 reserved_mem_size;
+       struct resource res;
+       u32 *vaddr;
+       u64 paddr;
 
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
@@ -284,6 +296,42 @@ static int rti_wdt_probe(struct platform_device *pdev)
                }
        }
 
+       node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+       if (node) {
+               ret = of_address_to_resource(node, 0, &res);
+               if (ret) {
+                       dev_err(dev, "No memory address assigned to the region.\n");
+                       goto err_iomap;
+               }
+
+               /*
+                * If reserved memory is defined for watchdog reset cause.
+                * Readout the Power-on(PON) reason and pass to bootstatus.
+                */
+               paddr = res.start;
+               reserved_mem_size = resource_size(&res);
+               if (reserved_mem_size < RESERVED_MEM_MIN_SIZE) {
+                       dev_err(dev, "The size of reserved memory is too small.\n");
+                       ret = -EINVAL;
+                       goto err_iomap;
+               }
+
+               vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB);
+               if (!vaddr) {
+                       dev_err(dev, "Failed to map memory-region.\n");
+                       ret = -ENOMEM;
+                       goto err_iomap;
+               }
+
+               if (vaddr[0] == PON_REASON_SOF_NUM &&
+                   vaddr[1] == PON_REASON_MAGIC_NUM &&
+                   vaddr[2] == PON_REASON_EOF_NUM) {
+                       wdd->bootstatus |= WDIOF_CARDRESET;
+               }
+               memset(vaddr, 0, reserved_mem_size);
+               memunmap(vaddr);
+       }
+
        watchdog_init_timeout(wdd, heartbeat, dev);
 
        ret = watchdog_register_device(wdd);