arm: msm8974: Driver to add support to disable debug image
On MSM8974, XPUs do not reset for non-watchdog resets when the
watchdog debug feature is enabled. This driver is required to
provide an interface to disable debug image for a PS HOLD reset.
Change-Id: I9e4a210475d0fff686d9d88000e8d71da1b553a1
Signed-off-by: Pushkar Joshi <pushkarj@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
new file mode 100644
index 0000000..e5fd1b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
@@ -0,0 +1,16 @@
+* Qualcomm's Watchdog Debug Image Controller
+
+The Qualcomm's Watchdog debug image controller is used for enabling/disabling of
+watchdog debug image feature.
+
+Required properties:
+- compatible : should be "qcom,msm-wdog-debug"
+- reg : base page aligned physical base address of the controller and length of
+ memory mapped region.
+
+Example:
+
+ qcom,msm-wdog-debug@fc401000 {
+ compatible = "qcom,msm-wdogi-debug";
+ reg = <0xfc401000 0x1000>;
+ };
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e59fb5b..75b73ec 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2645,4 +2645,12 @@
such as display backlight, vreg pin-ctrl, smps clock over the RPC
interface. This support is required for MSMs on which the APPS
does not have a direct access to the PMIC.
+
+config MSM_ENABLE_WDOG_DEBUG_CONTROL
+ bool "MSM Watchdog driver to disable debug Image"
+ help
+ This driver supports the configuration of the GCC_WDOG_DEBUG register
+ used to control debug image.
+ This support is currently required for MSM8974 to disable debug image
+ on PS HOLD reset
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3c44a06..ffe8b72 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -383,6 +383,7 @@
obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
obj-$(CONFIG_MSM_RPC_PMAPP) += rpc_pmapp.o
+obj-$(CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL) += wdog_debug.o
ifdef CONFIG_MSM_CPR
obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
new file mode 100644
index 0000000..82800cf
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <mach/scm.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "wdog_debug"
+#define WDOG_DEBUG_EN 17
+#define GCC_WDOG_DEBUG_OFFSET 0x780
+
+struct msm_wdog_debug_data {
+ unsigned int __iomem phys_base;
+ size_t size;
+ void __iomem *base;
+ struct device *dev;
+};
+
+static struct msm_wdog_debug_data *wdog_data;
+
+void msm_disable_wdog_debug(void)
+{
+ unsigned long int value;
+
+ if (wdog_data == NULL)
+ return;
+ value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+ value &= ~BIT(WDOG_DEBUG_EN);
+ writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_disable_wdog_debug);
+
+void msm_enable_wdog_debug(void)
+{
+ unsigned long int value;
+
+ if (wdog_data == NULL)
+ return;
+ value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+ value |= BIT(WDOG_DEBUG_EN);
+ writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_enable_wdog_debug);
+
+static int __devexit msm_wdog_debug_remove(struct platform_device *pdev)
+{
+ kfree(wdog_data);
+ wdog_data = NULL;
+ pr_info("MSM wdog_debug Exit - Deactivated\n");
+ return 0;
+}
+
+static int __devinit msm_wdog_debug_dt_to_pdata(struct platform_device *pdev,
+ struct msm_wdog_debug_data *pdata)
+{
+ struct resource *wdog_resource;
+
+ wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!wdog_resource) {
+ dev_err(&pdev->dev, \
+ "%s cannot allocate resource for wdog_debug\n", \
+ __func__);
+ return -ENXIO;
+ }
+ pdata->size = resource_size(wdog_resource);
+ pdata->phys_base = wdog_resource->start;
+ if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
+ pdata->size, "msm-wdog-debug")))) {
+ dev_err(&pdev->dev, "%s cannot reserve wdog_debug region\n",
+ __func__);
+ return -ENXIO;
+ }
+ pdata->base = devm_ioremap(&pdev->dev, pdata->phys_base,
+ pdata->size);
+ if (!pdata->base) {
+ dev_err(&pdev->dev, "%s cannot map wdog register space\n",
+ __func__);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int __devinit msm_wdog_debug_probe(struct platform_device *pdev)
+{
+ int ret;
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+ wdog_data = kzalloc(sizeof(struct msm_wdog_debug_data), GFP_KERNEL);
+ if (!wdog_data)
+ return -ENOMEM;
+ ret = msm_wdog_debug_dt_to_pdata(pdev, wdog_data);
+ if (ret)
+ goto err;
+ wdog_data->dev = &pdev->dev;
+ platform_set_drvdata(pdev, wdog_data);
+ msm_enable_wdog_debug();
+ return 0;
+err:
+ kzfree(wdog_data);
+ wdog_data = NULL;
+ return ret;
+}
+
+static struct of_device_id msm_wdog_debug_match_table[] = {
+ { .compatible = "qcom,msm-wdog-debug" },
+ {}
+};
+
+static struct platform_driver msm_wdog_debug_driver = {
+ .probe = msm_wdog_debug_probe,
+ .remove = msm_wdog_debug_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_wdog_debug_match_table,
+ },
+};
+
+static int __devinit wdog_debug_init(void)
+{
+ return platform_driver_register(&msm_wdog_debug_driver);
+}
+module_init(wdog_debug_init);
+
+static void __exit wdog_debug_exit(void)
+{
+ platform_driver_unregister(&msm_wdog_debug_driver);
+}
+module_exit(wdog_debug_exit);
+
+MODULE_DESCRIPTION("MSM Driver to disable debug Image");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wdog_debug.h b/arch/arm/mach-msm/wdog_debug.h
new file mode 100644
index 0000000..920aa89
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WDOG_DEBUG_H
+#define __WDOG_DEBUG_H
+
+#ifdef CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL
+void msm_enable_wdog_debug(void);
+void msm_disable_wdog_debug(void);
+#else
+void msm_enable_wdog_debug(void) { }
+void msm_disable_wdog_debug(void) { }
+#endif
+
+#endif