msm: pm-boot: Add devicetree support for pm-boot

pm-boot driver abstracts warm boot configurations for the power
management drivers. Add device tree support to read the boot
configuration information from DTS file.

Change-Id: I1135f796ddb054bb1ea4b64b9ff323736157bdc8
Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
new file mode 100644
index 0000000..cce9d0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
@@ -0,0 +1,40 @@
+* Power Management boot configuration (pm-boot)
+
+Low power management drivers need to specify the warmboot entry path for the
+application processors to resume from sleep/suspend. The boot configuration
+can vary if the core does/does not support a secure boot mode. The secure
+boot configuration boots the core sets up the core sub system registers and
+calls into the kernel entry point. In the absence of a secure boot mode, the
+core when powered on from reset will need to be configured with the warmboot
+entry pointer. The physical and the virtual address for the entry pointer
+need to provided to the driver.
+
+
+The device tree parameters for pm-boot are:
+
+Required parameters:
+
+- compatible: Must be "qcom,pm-boot"
+- qcom,mode: The mode that the target will use for booting
+	MSM_PM_BOOT_CONFIG_TZ                = 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+
+Optional parameters (based on the mode chosen):
+
+- qcom,phy-addr: The physical address that will be used for warmboot entry if
+	the processor remap register can be programmed.
+	Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+				MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+- qcom,virt-addr: The virtual address at which the processor start booting from
+	Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+				MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+
+
+Example:
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 21b7b9e..0da3200 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -272,4 +272,9 @@
 			qcom,time-overhead = <30000>;
 		};
 	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
 };
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index b5f0fdc..f6105af1 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -15,6 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <asm/mach-types.h>
@@ -200,3 +204,69 @@
 
 	return ret;
 }
+
+static int __devinit msm_pm_boot_probe(struct platform_device *pdev)
+{
+	struct msm_pm_boot_platform_data pdata;
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+	int flag = 0;
+
+	key = "qcom,mode";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret) {
+		pr_err("Unable to read boot mode Err(%d).\n", ret);
+		return -ENODEV;
+	}
+	pdata.mode = val;
+
+	key = "qcom,phy-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
+		goto fail;
+	if (!ret) {
+		pdata.p_addr = val;
+		flag++;
+	}
+
+	key = "qcom,virt-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
+		goto fail;
+	if (!ret) {
+		pdata.v_addr = (void *)val;
+		flag++;
+	}
+
+	if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
+		key = "addresses for boot remap";
+		goto fail;
+	}
+
+	return msm_pm_boot_init(&pdata);
+
+fail:
+	pr_err("Error reading %s\n", key);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_pm_match_table[] = {
+	{.compatible = "qcom,pm-boot"},
+	{},
+};
+
+static struct platform_driver msm_pm_boot_driver = {
+	.probe = msm_pm_boot_probe,
+	.driver = {
+		.name = "pm-boot",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pm_match_table,
+	},
+};
+
+static int __init msm_pm_boot_module_init(void)
+{
+	return platform_driver_register(&msm_pm_boot_driver);
+}
+module_init(msm_pm_boot_module_init);