linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver
@ 2014-08-08  4:00 Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 01/13] msm: scm: Move scm-boot files to drivers/soc and include/soc Lina Iyer
                   ` (13 more replies)
  0 siblings, 14 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Hello everybody,

Here are the set of patches for enabling cpuidle driver for 8074 based targets.

8074 like any ARM SoC can do architectural clock gating, that helps save on
power, but not enough of leakage power.  Leakage power of the SoC can be
further reduced by turning off power to the core. To aid this, every core (cpu
and L2) is accompanied by a Sub-system Power Manager (SPM), that can be
configured to indicate the low power mode, the core would be put into and the
SPM programs the peripheral h/w accordingly to enter low power and turn off the
power rail to the core.

The patchsets do the following

- Move scm-boot files from arm/mach-qcom to drivers/soc, following convention.
They are based on Stephen Boyd's series of patches
[http://www.spinics.net/lists/linux-arm-msm/msg10482.html]

- Add new Secure Monitor flags to support warmboot of a quad core system.

- Introduce the SPM driver to control power to the core. The SPM h/w IP works
in conjunction with the Krait CPU/L2. When the core executes WFI instruction,
the core is clockgated and the SPM state machine takes over and powers the core
down. An interrupt from GIC, resumes the SPM state machine which brings the cpu
out of the low power mode.

- Add the device tree configuration for each of the SPM nodes. There is one for
each cpu. There is one for each cpu and one for L2 and one for L2.

- Introduce the SoC driver interface layer to configure SPM per the core's idle
 state. To power down the cpu core, the SPM h/w needs to be set up correctly
to power down the core, when the core executes WFI. Linux is expected to call
into Secure Monitor to power down the core. At reset, the core will start in
Seure mode and will be returned back to Linux.  Also, when powering down the
core, let the SCM know the state of L2 as set up in Linux. This allows secure
monitor to flush the secure lines when Linux knows the cache may be powered
off. 

- Add ability to recognize the power down status of the core, to ensure that
the core is indeed powered down before powering down peripheral h/w.

- Add support for deeper idle states than just clock gating for hotplug and warmboot

- Add CPUIDLE driver for QCOM cpus. The cpuidle driver uses the SoC interface
layer to configure the SPM to allow Krait to be powered down. The driver
supports 4 low power modes, but not all SoCs, support all low power modes. The
modes supported are configured in device tree nodes.

- Provide device configuration for 8074 SoC. Current support is for WFI and
standalone power collapse, which powers only the core independent of the
other cores and caches.

- KConfig option to enable the driver

I have tested them on the Dragonboard 8074. The drivers should be fairly
extensible to 8084.

Thanks
Lina


Lina Iyer (13):
  msm: scm: Move scm-boot files to drivers/soc and include/soc
  msm: scm: Add SCM warmboot flags for quad core targets.
  qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets
  arm: dts: qcom: Add SPM device bindings for 8974
  qcom: msm-pm: Add cpu low power mode functions
  qcom: msm-pm: Add support for hotplug and secondary startup
  qcom: sleep-status: Add ability to recognize cpu power down state
  arm: dts: qcom: Add device binding for sleep status
  soc: qcom: Add QCOM Power management config
  qcom: platsmp: Enable deeper idle states for hotplug
  qcom: cpuidle: Add cpuidle driver for QCOM cpus
  qcom: cpuidle: Add cpuidle device nodes for 8974 chipset
  qcom: cpuidle: Config option to enable QCOM cpuidle driver

 .../bindings/arm/msm/qcom,cpu-sleep-status.txt     |  41 ++
 .../devicetree/bindings/arm/msm/qcom,cpuidle.txt   |  73 +++
 .../devicetree/bindings/arm/msm/spm-v2.txt         | 104 +++
 arch/arm/boot/dts/qcom-msm8974-pm.dtsi             | 146 +++++
 arch/arm/boot/dts/qcom-msm8974.dtsi                |   2 +
 arch/arm/mach-qcom/Makefile                        |   1 -
 arch/arm/mach-qcom/platsmp.c                       |  22 +-
 drivers/cpuidle/Kconfig.arm                        |   6 +
 drivers/cpuidle/Makefile                           |   1 +
 drivers/cpuidle/cpuidle-qcom.c                     | 140 ++++
 drivers/soc/qcom/Kconfig                           |   8 +
 drivers/soc/qcom/Makefile                          |   4 +-
 drivers/soc/qcom/msm-pm.c                          | 254 ++++++++
 .../arm/mach-qcom => drivers/soc/qcom}/scm-boot.c  |   4 +-
 drivers/soc/qcom/sleep-status.c                    | 178 ++++++
 drivers/soc/qcom/spm.c                             | 559 ++++++++++++++++
 drivers/soc/qcom/spm_devices.c                     | 709 +++++++++++++++++++++
 drivers/soc/qcom/spm_driver.h                      | 118 ++++
 include/soc/qcom/pm.h                              |  45 ++
 .../arm/mach-qcom => include/soc/qcom}/scm-boot.h  |   3 +
 include/soc/qcom/spm.h                             | 106 +++
 21 files changed, 2519 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt
 create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt
 create mode 100644 Documentation/devicetree/bindings/arm/msm/spm-v2.txt
 create mode 100644 arch/arm/boot/dts/qcom-msm8974-pm.dtsi
 create mode 100644 drivers/cpuidle/cpuidle-qcom.c
 create mode 100644 drivers/soc/qcom/msm-pm.c
 rename {arch/arm/mach-qcom => drivers/soc/qcom}/scm-boot.c (97%)
 create mode 100644 drivers/soc/qcom/sleep-status.c
 create mode 100644 drivers/soc/qcom/spm.c
 create mode 100644 drivers/soc/qcom/spm_devices.c
 create mode 100644 drivers/soc/qcom/spm_driver.h
 create mode 100644 include/soc/qcom/pm.h
 rename {arch/arm/mach-qcom => include/soc/qcom}/scm-boot.h (91%)
 create mode 100644 include/soc/qcom/spm.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 01/13] msm: scm: Move scm-boot files to drivers/soc and include/soc
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm/mach-qcom/Makefile                         | 1 -
 drivers/soc/qcom/Makefile                           | 2 +-
 {arch/arm/mach-qcom => drivers/soc/qcom}/scm-boot.c | 4 ++--
 {arch/arm/mach-qcom => include/soc/qcom}/scm-boot.h | 0
 4 files changed, 3 insertions(+), 4 deletions(-)
 rename {arch/arm/mach-qcom => drivers/soc/qcom}/scm-boot.c (97%)
 rename {arch/arm/mach-qcom => include/soc/qcom}/scm-boot.h (100%)

diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index db41e8c..e324375 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1,3 +1,2 @@
 obj-y			:= board.o
 obj-$(CONFIG_SMP)	+= platsmp.o
-obj-$(CONFIG_QCOM_SCM)	+= scm-boot.o
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index a39446d..70d52ed 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
-obj-$(CONFIG_QCOM_SCM) += scm.o
+obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/arch/arm/mach-qcom/scm-boot.c b/drivers/soc/qcom/scm-boot.c
similarity index 97%
rename from arch/arm/mach-qcom/scm-boot.c
rename to drivers/soc/qcom/scm-boot.c
index 5add20e..60ff7b4 100644
--- a/arch/arm/mach-qcom/scm-boot.c
+++ b/drivers/soc/qcom/scm-boot.c
@@ -17,9 +17,9 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <soc/qcom/scm.h>
 
-#include "scm-boot.h"
+#include <soc/qcom/scm.h>
+#include <soc/qcom/scm-boot.h>
 
 /*
  * Set the cold/warm boot address for one of the CPU cores.
diff --git a/arch/arm/mach-qcom/scm-boot.h b/include/soc/qcom/scm-boot.h
similarity index 100%
rename from arch/arm/mach-qcom/scm-boot.h
rename to include/soc/qcom/scm-boot.h
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets.
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 01/13] msm: scm: Move scm-boot files to drivers/soc and include/soc Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08 16:19   ` Kumar Gala
  2014-08-08  4:00 ` [RFC] [PATCH 03/13] qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets Lina Iyer
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Quad core targets like APQ8074, 78064, 8084 need SCM support set up
warm boot addresses in the Secure Monitor. Extend the SCM flags to
support warmboot addresses for seconday cores.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/soc/qcom/scm-boot.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/soc/qcom/scm-boot.h b/include/soc/qcom/scm-boot.h
index 6aabb24..7ae2152 100644
--- a/include/soc/qcom/scm-boot.h
+++ b/include/soc/qcom/scm-boot.h
@@ -18,6 +18,9 @@
 #define SCM_FLAG_COLDBOOT_CPU3		0x20
 #define SCM_FLAG_WARMBOOT_CPU0		0x04
 #define SCM_FLAG_WARMBOOT_CPU1		0x02
+#define SCM_FLAG_WARMBOOT_CPU2		0x10
+#define SCM_FLAG_WARMBOOT_CPU3		0x40
+
 
 int scm_set_boot_addr(phys_addr_t addr, int flags);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 03/13] qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 01/13] msm: scm: Move scm-boot files to drivers/soc and include/soc Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 04/13] arm: dts: qcom: Add SPM device bindings for 8974 Lina Iyer
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer, Praveen Chidamabram, Murali Nalajala

Qualcomm chipsets use an separate h/w block to control the logic around
the processor cores (cpu and L2). The SPM h/w block regulates power to
the cores and controls the power when the core enter low power modes.

Each core has its own instance of SPM. The SPM has the following key
functions
	- Configure the h/w dependencies when entering low power modes
	- Wait for interrupt and wake up on interrupt
	- Ensure the dependencies are ready before bringing the core out
	  of sleep
	- Regulating voltage to the core, interfacing with the PMIC.
	- Optimize power based on runtime recommendations.

The driver identifies and configures the SPMs, by reading the nodes and
the register values from the devicetree. The SPMs need to be configured
to allow the processor to be idled in a low power state.

Signed-off-by: Praveen Chidamabram <pchidamb@codeaurora.org>
Signed-off-by: Murali Nalajala <mnalajal@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 .../devicetree/bindings/arm/msm/spm-v2.txt         | 104 +++
 drivers/soc/qcom/Makefile                          |   2 +
 drivers/soc/qcom/spm.c                             | 559 ++++++++++++++++
 drivers/soc/qcom/spm_devices.c                     | 709 +++++++++++++++++++++
 drivers/soc/qcom/spm_driver.h                      | 118 ++++
 include/soc/qcom/spm.h                             | 106 +++
 6 files changed, 1598 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/spm-v2.txt
 create mode 100644 drivers/soc/qcom/spm.c
 create mode 100644 drivers/soc/qcom/spm_devices.c
 create mode 100644 drivers/soc/qcom/spm_driver.h
 create mode 100644 include/soc/qcom/spm.h

diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
new file mode 100644
index 0000000..ea0fc7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -0,0 +1,104 @@
+* MSM Subsystem Power Manager (spm-v2)
+
+S4 generation of MSMs have SPM hardware blocks to control the Application
+Processor Sub-System power. These SPM blocks run individual state machine
+to determine what the core (L2 or Krait/Scorpion) would do when the WFI
+instruction is executed by the core. The SAW hardware block handles SPM and
+AVS functionality for the cores.
+
+The devicetree representation of the SPM block should be:
+
+Required properties
+
+- compatible: "qcom,spm-v2"
+- reg: The physical address and the size of the SPM's memory mapped registers
+- qcom,cpu: phandle for the CPU that the SPM block is attached to. On targets
+	that dont support CPU phandles the driver would support qcom,core-id.
+	This field is required on only for SPMs that control the CPU.
+- qcom, core-id: This property will be deprecated once all targets start
+	supporting CPU phandles. This field will be used to identify SPMs
+	that control the CPU.
+	{0..n} for cores {0..n}
+- qcom,saw2-ver-reg: The location of the version register
+- qcom,saw2-cfg: SAW2 configuration register
+- qcom,saw2-avs-ctl: The AVS control register
+- qcom,saw2-avs-hysterisis: The AVS hysterisis register to delay the AVS
+	controller requests
+- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM
+	sequence
+- qcom,saw2-spm-ctl: The SPM control register
+- qcom,vctl-timeout-us: The timeout value in us to wait for voltage to change
+	after sending the voltage command to the PMIC
+- qcom,name: The name with which a SPM device is identified by the power
+management code.
+
+Optional properties
+
+- qcom,saw2-avs-limit: The AVS limit register
+- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values
+	between AVS controller requests
+- qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS
+	index to send the PMIC data to
+- qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing
+	voltage
+- qcom,phase-port: The PVC port used for changing the number of phases
+- qcom,pfm-port: The PVC port used for enabling PWM/PFM modes
+- qcom,saw2-spm-cmd-wfi: The WFI command sequence
+- qcom,saw2-spm-cmd-ret: The Retention command sequence
+- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc-no-rpm: The Power Collapse command sequence where APPS
+	proc won't inform the RPM.
+- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
+- qcom,cpu-vctl-mask: Mask of cpus, whose voltage the spm device can control.
+	Depricated: Replaced with cpu-vctl-list when cpu phandles are available.
+- qcom,cpu-vctl-list: List of cpu node phandles, whose voltage the spm device
+	can control.
+
+Example 1:
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,cpu-vctl-mask = <0xf>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+Example 2:
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 70d52ed..3de7ed9 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,3 +1,5 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
+obj-$(CONFIG_QCOM_PM) +=	spm_devices.o spm.o
+
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
new file mode 100644
index 0000000..984aca6
--- /dev/null
+++ b/drivers/soc/qcom/spm.c
@@ -0,0 +1,559 @@
+/* Copyright (c) 2011-2014, 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/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "spm_driver.h"
+
+#define MSM_SPM_PMIC_STATE_IDLE  0
+
+enum {
+	MSM_SPM_DEBUG_SHADOW = 1U << 0,
+	MSM_SPM_DEBUG_VCTL = 1U << 1,
+};
+
+static int msm_spm_debug_mask;
+module_param_named(
+	debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+struct saw2_data {
+	const char *ver_name;
+	uint32_t major;
+	uint32_t minor;
+	uint32_t *spm_reg_offset_ptr;
+};
+
+static uint32_t msm_spm_reg_offsets_saw2_v2_1[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_SPM_STS]		= 0x0C,
+	[MSM_SPM_REG_SAW2_AVS_STS]		= 0x10,
+	[MSM_SPM_REG_SAW2_PMIC_STS]		= 0x14,
+	[MSM_SPM_REG_SAW2_RST]			= 0x18,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x1C,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_AVS_LIMIT]		= 0x24,
+	[MSM_SPM_REG_SAW2_AVS_DLY]		= 0x28,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x2C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x30,
+	[MSM_SPM_REG_SAW2_SPM_DLY]		= 0x34,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x40,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x44,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_2]		= 0x48,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_3]		= 0x4C,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_4]		= 0x50,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_5]		= 0x54,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_6]		= 0x58,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_7]		= 0x5C,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x80,
+	[MSM_SPM_REG_SAW2_VERSION]		= 0xFD0,
+};
+
+static uint32_t msm_spm_reg_offsets_saw2_v3_0[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_SPM_STS]		= 0x0C,
+	[MSM_SPM_REG_SAW2_AVS_STS]		= 0x10,
+	[MSM_SPM_REG_SAW2_PMIC_STS]		= 0x14,
+	[MSM_SPM_REG_SAW2_RST]			= 0x18,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x1C,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_AVS_LIMIT]		= 0x24,
+	[MSM_SPM_REG_SAW2_AVS_DLY]		= 0x28,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x2C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x30,
+	[MSM_SPM_REG_SAW2_SPM_DLY]		= 0x34,
+	[MSM_SPM_REG_SAW2_STS2]			= 0x38,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x40,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x44,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_2]		= 0x48,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_3]		= 0x4C,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_4]		= 0x50,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_5]		= 0x54,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_6]		= 0x58,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_7]		= 0x5C,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x400,
+	[MSM_SPM_REG_SAW2_VERSION]		= 0xFD0,
+};
+
+static struct saw2_data saw2_info[] = {
+	[0] = {
+		"SAW2_v2.1",
+		0x2,
+		0x1,
+		msm_spm_reg_offsets_saw2_v2_1,
+	},
+	[1] = {
+		"SAW2_v3.0",
+		0x3,
+		0x0,
+		msm_spm_reg_offsets_saw2_v3_0,
+	},
+};
+
+static uint32_t num_pmic_data;
+
+static inline uint32_t msm_spm_drv_get_num_spm_entry(
+		struct msm_spm_driver_data *dev)
+{
+	return 32;
+}
+
+static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	__raw_writel(dev->reg_shadow[reg_index],
+		dev->reg_base_addr + dev->reg_offsets[reg_index]);
+}
+
+static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	dev->reg_shadow[reg_index] =
+		__raw_readl(dev->reg_base_addr +
+				dev->reg_offsets[reg_index]);
+}
+
+static inline void msm_spm_drv_set_start_addr(
+		struct msm_spm_driver_data *dev, uint32_t addr, bool pc_mode)
+{
+	addr &= 0x7F;
+	addr <<= 4;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
+
+	if (dev->major != 0x3)
+		return;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFEFFFF;
+	if (pc_mode)
+		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= 0x00010000;
+}
+
+static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
+	return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
+}
+
+static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
+		uint32_t vlevel)
+{
+	unsigned int pmic_data = 0;
+
+	/**
+	 * VCTL_PORT has to be 0, for PMIC_STS register to be updated.
+	 * Ensure that vctl_port is always set to 0.
+	 */
+	WARN_ON(dev->vctl_port);
+
+	pmic_data |= vlevel;
+	pmic_data |= (dev->vctl_port & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_3] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_3] |= pmic_data;
+
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_3);
+}
+
+static inline uint32_t msm_spm_drv_get_num_pmic_data(
+		struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
+	mb();
+	return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 4) & 0x7;
+}
+
+static inline uint32_t msm_spm_drv_get_sts_pmic_state(
+		struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+	return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
+				0x03;
+}
+
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+		struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+	return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
+}
+
+static inline void msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
+		uint32_t *major, uint32_t *minor)
+{
+	uint32_t val = 0;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION] =
+			__raw_readl(dev->reg_base_addr + dev->ver_reg);
+
+	val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
+
+	*major = (val >> 28) & 0xF;
+	*minor = (val >> 16) & 0xFFF;
+}
+
+inline int msm_spm_drv_set_spm_enable(
+		struct msm_spm_driver_data *dev, bool enable)
+{
+	uint32_t value = enable ? 0x01 : 0x00;
+
+	if (!dev)
+		return -EINVAL;
+
+	if ((dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] & 0x01) ^ value) {
+
+		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= ~0x1;
+		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= value;
+
+		msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
+		wmb();
+	}
+	return 0;
+}
+void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
+{
+	int i;
+	int num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
+
+	if (!dev) {
+		__WARN();
+		return;
+	}
+
+	for (i = 0; i < num_spm_entry; i++) {
+		__raw_writel(dev->reg_seq_entry_shadow[i],
+			dev->reg_base_addr
+			+ dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+			+ 4 * i);
+	}
+	mb();
+}
+
+void dump_regs(struct msm_spm_driver_data *dev, int cpu)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_SPM_STS);
+	mb();
+	pr_err("CPU%d: spm register MSM_SPM_REG_SAW2_SPM_STS: 0x%x\n", cpu,
+			dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_STS]);
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
+	mb();
+	pr_err("CPU%d: spm register MSM_SPM_REG_SAW2_SPM_CTL: 0x%x\n", cpu,
+			dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL]);
+}
+
+int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
+		uint8_t *cmd, uint32_t *offset)
+{
+	uint32_t cmd_w;
+	uint32_t offset_w = *offset / 4;
+	uint8_t last_cmd;
+
+	if (!cmd)
+		return -EINVAL;
+
+	while (1) {
+		int i;
+
+		cmd_w = 0;
+		last_cmd = 0;
+		cmd_w = dev->reg_seq_entry_shadow[offset_w];
+
+		for (i = (*offset % 4); i < 4; i++) {
+			last_cmd = *(cmd++);
+			cmd_w |=  last_cmd << (i * 8);
+			(*offset)++;
+			if (last_cmd == 0x0f)
+				break;
+		}
+
+		dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
+		if (last_cmd == 0x0f)
+			break;
+	}
+
+	return 0;
+}
+
+int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
+		uint32_t addr, bool pc_mode)
+{
+
+	/* SPM is configured to reset start address to zero after end of Program
+	 */
+	if (!dev)
+		return -EINVAL;
+
+	msm_spm_drv_set_start_addr(dev, addr, pc_mode);
+
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
+	wmb();
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
+		int i;
+
+		for (i = 0; i < MSM_SPM_REG_NR; i++)
+			pr_info("%s: reg %02x = 0x%08x\n", __func__,
+				dev->reg_offsets[i], dev->reg_shadow[i]);
+	}
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_SPM_STS);
+
+	return 0;
+}
+
+#ifdef CONFIG_MSM_AVS_HW
+static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+	return dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] & BIT(0);
+}
+
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~BIT(27);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= BIT(27);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+		unsigned int vlevel)
+{
+	vlevel &= 0x3f;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] &= ~0x7efc00;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= ((vlevel - 4) << 10);
+	dev->reg_shadow[MSM_SPM_REG_SAW2_AVS_CTL] |= (vlevel << 17);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_AVS_CTL);
+}
+
+#else
+static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
+{
+	return false;
+}
+
+static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
+
+static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
+		unsigned int vlevel) { }
+#endif
+
+int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
+{
+	uint32_t timeout_us, new_level;
+	bool avs_enabled;
+
+	if (!dev)
+		return -EINVAL;
+
+	avs_enabled  = msm_spm_drv_is_avs_enabled(dev);
+
+	if (!msm_spm_pmic_arb_present(dev))
+		return -ENOSYS;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
+
+	if (avs_enabled)
+		msm_spm_drv_disable_avs(dev);
+
+	/* Kick the state machine back to idle */
+	dev->reg_shadow[MSM_SPM_REG_SAW2_RST] = 1;
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_RST);
+
+	msm_spm_drv_set_vctl2(dev, vlevel);
+
+	timeout_us = dev->vctl_timeout_us;
+	/* Confirm the voltage we set was what hardware sent */
+	do {
+		new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
+		if (new_level == vlevel)
+			break;
+		udelay(1);
+	} while (--timeout_us);
+	if (!timeout_us) {
+		pr_info("Wrong level %#x\n", new_level);
+		goto set_vdd_bail;
+	}
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: done, remaining timeout %u us\n",
+			__func__, timeout_us);
+
+	/* Set AVS min/max */
+	if (avs_enabled) {
+		msm_spm_drv_set_avs_vlevel(dev, vlevel);
+		msm_spm_drv_enable_avs(dev);
+	}
+
+	return 0;
+
+set_vdd_bail:
+	if (avs_enabled)
+		msm_spm_drv_enable_avs(dev);
+
+	pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n",
+		__func__, vlevel, timeout_us, new_level);
+	return -EIO;
+}
+
+static int msm_spm_drv_get_pmic_port(struct msm_spm_driver_data *dev,
+		enum msm_spm_pmic_port port)
+{
+	int index = -1;
+
+	switch (port) {
+	case MSM_SPM_PMIC_VCTL_PORT:
+		index = dev->vctl_port;
+		break;
+	case MSM_SPM_PMIC_PHASE_PORT:
+		index = dev->phase_port;
+		break;
+	case MSM_SPM_PMIC_PFM_PORT:
+		index = dev->pfm_port;
+		break;
+	default:
+		break;
+	}
+
+	return index;
+}
+
+int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
+		enum msm_spm_pmic_port port, unsigned int data)
+{
+	unsigned int pmic_data = 0;
+	unsigned int timeout_us = 0;
+	int index = 0;
+
+	if (!msm_spm_pmic_arb_present(dev))
+		return -ENOSYS;
+
+	index = msm_spm_drv_get_pmic_port(dev, port);
+	if (index < 0)
+		return -ENODEV;
+
+	pmic_data |= data & 0xFF;
+	pmic_data |= (index & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
+	mb();
+
+	timeout_us = dev->vctl_timeout_us;
+	/**
+	 * Confirm the pmic data set was what hardware sent by
+	 * checking the PMIC FSM state.
+	 * We cannot use the sts_pmic_data and check it against
+	 * the value like we do fot set_vdd, since the PMIC_STS
+	 * is only updated for SAW_VCTL sent with port index 0.
+	 */
+	do {
+		if (msm_spm_drv_get_sts_pmic_state(dev) ==
+				MSM_SPM_PMIC_STATE_IDLE)
+			break;
+		udelay(1);
+	} while (--timeout_us);
+
+	if (!timeout_us) {
+		pr_err("%s: failed, remaining timeout %u us, data %d\n",
+				__func__, timeout_us, data);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
+{
+	int i;
+
+	msm_spm_drv_flush_seq_entry(dev);
+	for (i = 0; i < MSM_SPM_REG_SAW2_PMIC_DATA_0 + num_pmic_data; i++)
+		msm_spm_drv_flush_shadow(dev, i);
+
+	mb();
+
+	for (i = MSM_SPM_REG_NR_INITIALIZE + 1; i < MSM_SPM_REG_NR; i++)
+		msm_spm_drv_load_shadow(dev, i);
+}
+
+int msm_spm_drv_init(struct msm_spm_driver_data *dev,
+		struct msm_spm_platform_data *data)
+{
+	int i;
+	int num_spm_entry;
+	bool found = false;
+
+	BUG_ON(!dev || !data);
+
+	dev->vctl_port = data->vctl_port;
+	dev->phase_port = data->phase_port;
+	dev->pfm_port = data->pfm_port;
+	dev->reg_base_addr = data->reg_base_addr;
+	memcpy(dev->reg_shadow, data->reg_init_values,
+			sizeof(data->reg_init_values));
+
+	dev->vctl_timeout_us = data->vctl_timeout_us;
+
+	msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
+
+	for (i = 0; i < ARRAY_SIZE(saw2_info); i++)
+		if (dev->major == saw2_info[i].major &&
+			dev->minor == saw2_info[i].minor) {
+			pr_debug("%s: Version found\n",
+					saw2_info[i].ver_name);
+			dev->reg_offsets = saw2_info[i].spm_reg_offset_ptr;
+			found = true;
+			break;
+		}
+
+	if (!found) {
+		pr_err("%s: No SAW2 version found\n", __func__);
+		BUG_ON(!found);
+	}
+
+	if (!num_pmic_data)
+		num_pmic_data = msm_spm_drv_get_num_pmic_data(dev);
+
+	num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
+
+	dev->reg_seq_entry_shadow =
+		kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
+				GFP_KERNEL);
+
+	if (!dev->reg_seq_entry_shadow)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/drivers/soc/qcom/spm_devices.c b/drivers/soc/qcom/spm_devices.c
new file mode 100644
index 0000000..755c165
--- /dev/null
+++ b/drivers/soc/qcom/spm_devices.c
@@ -0,0 +1,709 @@
+/* Copyright (c) 2011-2014, 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/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <soc/qcom/spm.h>
+
+#include "spm_driver.h"
+
+#define VDD_DEFAULT 0xDEADF00D
+
+struct msm_spm_power_modes {
+	uint32_t mode;
+	bool notify_rpm;
+	uint32_t start_addr;
+};
+
+struct msm_spm_device {
+	struct list_head list;
+	bool initialized;
+	const char *name;
+	struct msm_spm_driver_data reg_data;
+	struct msm_spm_power_modes *modes;
+	uint32_t num_modes;
+	uint32_t cpu_vdd;
+	struct cpumask mask;
+	void __iomem *q2s_reg;
+};
+
+struct msm_spm_vdd_info {
+	struct msm_spm_device *vctl_dev;
+	uint32_t vlevel;
+	int err;
+};
+
+static LIST_HEAD(spm_list);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
+static DEFINE_PER_CPU(struct msm_spm_device *, cpu_vctl_device);
+
+static void msm_spm_smp_set_vdd(void *data)
+{
+	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
+	struct msm_spm_device *dev = info->vctl_dev;
+
+	dev->cpu_vdd = info->vlevel;
+	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+}
+
+/**
+ * msm_spm_probe_done(): Verify and return the status of the cpu(s) and l2
+ * probe.
+ * Return: 0 if all spm devices have been probed, else return -EPROBE_DEFER.
+ * if probe failed, then return the err number for that failure.
+ */
+int msm_spm_probe_done(void)
+{
+	struct msm_spm_device *dev;
+	int cpu;
+	int ret = 0;
+
+	for_each_possible_cpu(cpu) {
+		dev = per_cpu(cpu_vctl_device, cpu);
+		if (!dev)
+			return -EPROBE_DEFER;
+
+		ret = IS_ERR(dev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_spm_probe_done);
+
+void msm_spm_dump_regs(unsigned int cpu)
+{
+	dump_regs(&per_cpu(msm_cpu_spm_device, cpu).reg_data, cpu);
+}
+
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ *
+ * Return: 0 on success or -(ERRNO) on failure.
+ */
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	struct msm_spm_vdd_info info;
+	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);
+	int ret;
+
+	if (!dev)
+		return -EPROBE_DEFER;
+
+	ret = IS_ERR(dev);
+	if (ret)
+		return ret;
+
+	info.vctl_dev = dev;
+	info.vlevel = vlevel;
+
+	ret = smp_call_function_any(&dev->mask, msm_spm_smp_set_vdd, &info,
+					true);
+	if (ret)
+		return ret;
+
+	return info.err;
+}
+EXPORT_SYMBOL(msm_spm_set_vdd);
+
+/**
+ * msm_spm_get_vdd(): Get core voltage
+ * @cpu: core id
+ * @return: Returns encoded PMIC data.
+ */
+unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+	int ret;
+	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);
+
+	if (!dev)
+		return -EPROBE_DEFER;
+
+	ret = IS_ERR(dev);
+	if (ret)
+		return ret;
+
+	return dev->cpu_vdd;
+}
+EXPORT_SYMBOL(msm_spm_get_vdd);
+
+static void msm_spm_config_q2s(struct msm_spm_device *dev, unsigned int mode)
+{
+	uint32_t spm_legacy_mode = 0;
+	uint32_t qchannel_ignore = 0;
+	uint32_t val = 0;
+
+	if (!dev->q2s_reg)
+		return;
+
+	switch (mode) {
+	case MSM_SPM_MODE_DISABLED:
+	case MSM_SPM_MODE_CLOCK_GATING:
+		qchannel_ignore = 1;
+		spm_legacy_mode = 0;
+		break;
+	case MSM_SPM_MODE_RETENTION:
+		qchannel_ignore = 0;
+		spm_legacy_mode = 0;
+		break;
+	case MSM_SPM_MODE_GDHS:
+	case MSM_SPM_MODE_POWER_COLLAPSE:
+		qchannel_ignore = 0;
+		spm_legacy_mode = 1;
+		break;
+	default:
+		break;
+	}
+
+	val = spm_legacy_mode << 2 | qchannel_ignore << 1;
+	__raw_writel(val, dev->q2s_reg);
+	mb();
+}
+
+static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
+		unsigned int mode, bool notify_rpm)
+{
+	uint32_t i;
+	uint32_t start_addr = 0;
+	int ret = -EINVAL;
+	bool pc_mode = false;
+
+	if (!dev->initialized)
+		return -ENXIO;
+
+	if ((mode == MSM_SPM_MODE_POWER_COLLAPSE)
+			|| (mode == MSM_SPM_MODE_GDHS))
+		pc_mode = true;
+
+	if (mode == MSM_SPM_MODE_DISABLED) {
+		ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
+	} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
+		for (i = 0; i < dev->num_modes; i++) {
+			if ((dev->modes[i].mode == mode) &&
+				(dev->modes[i].notify_rpm == notify_rpm)) {
+				start_addr = dev->modes[i].start_addr;
+				break;
+			}
+		}
+		ret = msm_spm_drv_set_low_power_mode(&dev->reg_data,
+					start_addr, pc_mode);
+	}
+
+	msm_spm_config_q2s(dev, mode);
+
+	return ret;
+}
+
+static int msm_spm_dev_init(struct msm_spm_device *dev,
+		struct msm_spm_platform_data *data)
+{
+	int i, ret = -ENOMEM;
+	uint32_t offset = 0;
+
+	dev->cpu_vdd = VDD_DEFAULT;
+	dev->num_modes = data->num_modes;
+	dev->modes = kmalloc(
+			sizeof(struct msm_spm_power_modes) * dev->num_modes,
+			GFP_KERNEL);
+
+	if (!dev->modes)
+		goto spm_failed_malloc;
+
+	dev->reg_data.ver_reg = data->ver_reg;
+	ret = msm_spm_drv_init(&dev->reg_data, data);
+
+	if (ret)
+		goto spm_failed_init;
+
+	for (i = 0; i < dev->num_modes; i++) {
+
+		/* Default offset is 0 and gets updated as we write more
+		 * sequences into SPM
+		 */
+		dev->modes[i].start_addr = offset;
+		ret = msm_spm_drv_write_seq_data(&dev->reg_data,
+						data->modes[i].cmd, &offset);
+		if (ret < 0)
+			goto spm_failed_init;
+
+		dev->modes[i].mode = data->modes[i].mode;
+		dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
+	}
+	msm_spm_drv_reinit(&dev->reg_data);
+	dev->initialized = true;
+	return 0;
+
+spm_failed_init:
+	kfree(dev->modes);
+spm_failed_malloc:
+	return ret;
+}
+
+/**
+ * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
+ * @base: The SAW VCTL register which would set the voltage up.
+ * @val: The value to be set on the rail
+ * @cpu: The cpu for this with rail is being powered on
+ */
+int msm_spm_turn_on_cpu_rail(void __iomem *base, unsigned int val, int cpu)
+{
+	uint32_t timeout = 2000; /* delay for voltage to settle on the core */
+	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);
+
+	/*
+	 * If clock drivers have already set up the voltage,
+	 * do not overwrite that value.
+	 */
+	if (dev && (dev->cpu_vdd != VDD_DEFAULT))
+		return 0;
+
+	/* Set the CPU supply regulator voltage */
+	val = (val & 0xFF);
+	writel_relaxed(val, base);
+	mb();
+	udelay(timeout);
+
+	/* Enable the CPU supply regulator*/
+	val = 0x30080;
+	writel_relaxed(val, base);
+	mb();
+	udelay(timeout);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
+
+void msm_spm_reinit(void)
+{
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu)
+		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
+}
+EXPORT_SYMBOL(msm_spm_reinit);
+
+/*
+ * msm_spm_is_mode_avail() - Specifies if a mode is available for the cpu
+ * It should only be used to decide a mode before lpm driver is probed.
+ * @mode: SPM LPM mode to be selected
+ */
+bool msm_spm_is_mode_avail(unsigned int mode)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
+	int i;
+
+	for (i = 0; i < dev->num_modes; i++) {
+		if (dev->modes[i].mode == mode)
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
+
+	return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
+}
+EXPORT_SYMBOL(msm_spm_set_low_power_mode);
+
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
+int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
+{
+	unsigned int cpu;
+	int ret = 0;
+
+	BUG_ON((nr_devs < num_possible_cpus()) || !data);
+
+	for_each_possible_cpu(cpu) {
+		struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+		ret = msm_spm_dev_init(dev, &data[cpu]);
+		if (ret < 0) {
+			pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
+					cpu, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+struct msm_spm_device *msm_spm_get_device_by_name(const char *name)
+{
+	struct list_head *list;
+
+	list_for_each(list, &spm_list) {
+		struct msm_spm_device *dev
+			= list_entry(list, typeof(*dev), list);
+		if (dev->name && !strcmp(dev->name, name))
+			return dev;
+	}
+	return ERR_PTR(-ENODEV);
+}
+
+int msm_spm_config_low_power_mode(struct msm_spm_device *dev,
+		unsigned int mode, bool notify_rpm)
+{
+	return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
+}
+#ifdef CONFIG_MSM_L2_SPM
+
+/**
+ * msm_spm_apcs_set_phase(): Set number of SMPS phases.
+ * @cpu: cpu which is requesting the change in number of phases.
+ * @phase_cnt: Number of phases to be set active
+ */
+int msm_spm_apcs_set_phase(int cpu, unsigned int phase_cnt)
+{
+	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);
+
+	if (!dev)
+		return -ENXIO;
+
+	return msm_spm_drv_set_pmic_data(&dev->reg_data,
+			MSM_SPM_PMIC_PHASE_PORT, phase_cnt);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_phase);
+
+/** msm_spm_enable_fts_lpm() : Enable FTS to switch to low power
+ *                             when the cores are in low power modes
+ * @cpu: cpu that is entering low power mode.
+ * @mode: The mode configuration for FTS
+ */
+int msm_spm_enable_fts_lpm(int cpu, uint32_t mode)
+{
+	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);
+
+	if (!dev)
+		return -ENXIO;
+
+	return msm_spm_drv_set_pmic_data(&dev->reg_data,
+			MSM_SPM_PMIC_PFM_PORT, mode);
+}
+EXPORT_SYMBOL(msm_spm_enable_fts_lpm);
+
+#endif
+
+static int get_cpu_id(struct device_node *node)
+{
+	struct device_node *cpu_node;
+	u32 cpu;
+	int ret = -EINVAL;
+	char *key = "qcom,cpu";
+
+	cpu_node = of_parse_phandle(node, key, 0);
+	if (cpu_node) {
+		for_each_possible_cpu(cpu) {
+			if (of_get_cpu_node(cpu, NULL) == cpu_node)
+				return cpu;
+		}
+	} else {
+		char *key = "qcom,core-id";
+
+		ret = of_property_read_u32(node, key, &cpu);
+		if (!ret)
+			return cpu;
+	}
+	return ret;
+}
+
+static struct msm_spm_device *msm_spm_get_device(struct platform_device *pdev)
+{
+	struct msm_spm_device *dev = NULL;
+	const char *val = NULL;
+	char *key = "qcom,name";
+	int cpu = get_cpu_id(pdev->dev.of_node);
+
+	if ((cpu >= 0) && cpu < num_possible_cpus())
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+	else if ((cpu == 0xffff) || (cpu < 0))
+		dev = devm_kzalloc(&pdev->dev, sizeof(struct msm_spm_device),
+					GFP_KERNEL);
+
+	if (!dev)
+		return NULL;
+
+	if (of_property_read_string(pdev->dev.of_node, key, &val)) {
+		pr_err("%s(): Cannot find a required node key:%s\n",
+				__func__, key);
+		return NULL;
+	}
+	dev->name = val;
+	list_add(&dev->list, &spm_list);
+
+	return dev;
+}
+
+static void get_cpumask(struct device_node *node, struct cpumask *mask)
+{
+	unsigned long vctl_mask = 0;
+	unsigned c = 0;
+	int idx = 0;
+	struct device_node *cpu_node = NULL;
+	int ret = 0;
+	char *key = "qcom,cpu-vctl-list";
+	bool found = false;
+
+	cpu_node = of_parse_phandle(node, key, idx++);
+	while (cpu_node) {
+		found = true;
+		for_each_possible_cpu(c) {
+			if (of_get_cpu_node(c, NULL) == cpu_node)
+				cpumask_set_cpu(c, mask);
+		}
+		cpu_node = of_parse_phandle(node, key, idx++);
+	};
+
+	if (found)
+		return;
+
+	key = "qcom,cpu-vctl-mask";
+	ret = of_property_read_u32(node, key, (u32 *) &vctl_mask);
+	if (!ret) {
+		for_each_set_bit(c, &vctl_mask, num_possible_cpus()) {
+			cpumask_set_cpu(c, mask);
+		}
+	}
+}
+
+static int msm_spm_dev_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int cpu = 0;
+	int i = 0;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_spm_platform_data spm_data;
+	char *key = NULL;
+	uint32_t val = 0;
+	struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
+	int len = 0;
+	struct msm_spm_device *dev = NULL;
+	struct resource *res = NULL;
+	uint32_t mode_count = 0;
+
+	struct spm_of {
+		char *key;
+		uint32_t id;
+	};
+
+	struct spm_of spm_of_data[] = {
+		{"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
+		{"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
+		{"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
+		{"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+		{"qcom,saw2-avs-dly", MSM_SPM_REG_SAW2_AVS_DLY},
+		{"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+		{"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
+		{"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
+		{"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
+		{"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
+		{"qcom,saw2-pmic-data3", MSM_SPM_REG_SAW2_PMIC_DATA_3},
+		{"qcom,saw2-pmic-data4", MSM_SPM_REG_SAW2_PMIC_DATA_4},
+		{"qcom,saw2-pmic-data5", MSM_SPM_REG_SAW2_PMIC_DATA_5},
+		{"qcom,saw2-pmic-data6", MSM_SPM_REG_SAW2_PMIC_DATA_6},
+		{"qcom,saw2-pmic-data7", MSM_SPM_REG_SAW2_PMIC_DATA_7},
+	};
+
+	struct mode_of {
+		char *key;
+		uint32_t id;
+		uint32_t notify_rpm;
+	};
+
+	struct mode_of mode_of_data[] = {
+		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_RETENTION, 0},
+		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_MODE_GDHS, 1},
+		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+		{"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+	};
+
+	dev = msm_spm_get_device(pdev);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+	get_cpumask(node, &dev->mask);
+
+	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+	memset(&modes, 0,
+		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+	key = "qcom,saw2-ver-reg";
+	ret = of_property_read_u32(node, key, &val);
+	if (ret)
+		goto fail;
+	spm_data.ver_reg = val;
+
+	key = "qcom,vctl-timeout-us";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.vctl_timeout_us = val;
+
+	/* SAW start address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EFAULT;
+		goto fail;
+	}
+
+	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!spm_data.reg_base_addr) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	spm_data.vctl_port = -1;
+	spm_data.phase_port = -1;
+	spm_data.pfm_port = -1;
+
+	key = "qcom,vctl-port";
+	of_property_read_u32(node, key, &spm_data.vctl_port);
+
+	key = "qcom,phase-port";
+	of_property_read_u32(node, key, &spm_data.phase_port);
+
+	key = "qcom,pfm-port";
+	of_property_read_u32(node, key, &spm_data.pfm_port);
+
+	/* Q2S (QChannel-2-SPM) register */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		dev->q2s_reg = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+		if (!dev->q2s_reg) {
+			pr_err("%s(): Unable to iomap Q2S register\n",
+					__func__);
+			ret = -EADDRNOTAVAIL;
+			goto fail;
+		}
+	}
+	/*
+	 * At system boot, cpus and or clusters can remain in reset. CCI SPM
+	 * will not be triggered unless SPM_LEGACY_MODE bit is set for the
+	 * cluster in reset. Initialize q2s registers and set the
+	 * SPM_LEGACY_MODE bit.
+	 */
+	msm_spm_config_q2s(dev, MSM_SPM_MODE_POWER_COLLAPSE);
+
+	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
+		ret = of_property_read_u32(node, spm_of_data[i].key, &val);
+		if (ret)
+			continue;
+		spm_data.reg_init_values[spm_of_data[i].id] = val;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+		key = mode_of_data[i].key;
+		modes[mode_count].cmd =
+			(uint8_t *)of_get_property(node, key, &len);
+		if (!modes[mode_count].cmd)
+			continue;
+		modes[mode_count].mode = mode_of_data[i].id;
+		modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
+		pr_debug("%s(): dev: %s cmd:%s, mode:%d rpm:%d\n", __func__,
+				dev->name, key, modes[mode_count].mode,
+				modes[mode_count].notify_rpm);
+		mode_count++;
+	}
+
+	spm_data.modes = modes;
+	spm_data.num_modes = mode_count;
+
+	ret = msm_spm_dev_init(dev, &spm_data);
+	if (ret)
+		goto fail;
+
+	platform_set_drvdata(pdev, dev);
+
+	for_each_cpu(cpu, &dev->mask)
+		per_cpu(cpu_vctl_device, cpu) = dev;
+
+	return ret;
+
+fail:
+	cpu = get_cpu_id(pdev->dev.of_node);
+	if (dev && (cpu >= num_possible_cpus() || (cpu < 0))) {
+		for_each_cpu(cpu, &dev->mask)
+			per_cpu(cpu_vctl_device, cpu) = ERR_PTR(ret);
+	}
+
+	pr_err("%s: CPU%d SPM device probe failed: %d\n", __func__, cpu, ret);
+
+	return ret;
+}
+
+static int msm_spm_dev_remove(struct platform_device *pdev)
+{
+	struct msm_spm_device *dev = platform_get_drvdata(pdev);
+
+	list_del(&dev->list);
+
+	return 0;
+}
+
+static struct of_device_id msm_spm_match_table[] = {
+	{.compatible = "qcom,spm-v2"},
+	{},
+};
+
+static struct platform_driver msm_spm_device_driver = {
+	.probe = msm_spm_dev_probe,
+	.remove = msm_spm_dev_remove,
+	.driver = {
+		.name = "spm-v2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_spm_match_table,
+	},
+};
+
+/**
+ * msm_spm_device_init(): Device tree initialization function
+ */
+int __init msm_spm_device_init(void)
+{
+	static bool registered;
+
+	if (registered)
+		return 0;
+
+	registered = true;
+
+	return platform_driver_register(&msm_spm_device_driver);
+}
+device_initcall(msm_spm_device_init);
diff --git a/drivers/soc/qcom/spm_driver.h b/drivers/soc/qcom/spm_driver.h
new file mode 100644
index 0000000..49cd16a
--- /dev/null
+++ b/drivers/soc/qcom/spm_driver.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2011-2014, 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 __ARCH_ARM_MACH_MSM_SPM_DRIVER_H
+#define __ARCH_ARM_MACH_MSM_SPM_DRIVER_H
+
+#include <soc/qcom/spm.h>
+
+enum {
+	MSM_SPM_REG_SAW2_CFG,
+	MSM_SPM_REG_SAW2_AVS_CTL,
+	MSM_SPM_REG_SAW2_AVS_HYSTERESIS,
+	MSM_SPM_REG_SAW2_SPM_CTL,
+	MSM_SPM_REG_SAW2_PMIC_DLY,
+	MSM_SPM_REG_SAW2_AVS_LIMIT,
+	MSM_SPM_REG_SAW2_AVS_DLY,
+	MSM_SPM_REG_SAW2_SPM_DLY,
+	MSM_SPM_REG_SAW2_PMIC_DATA_0,
+	MSM_SPM_REG_SAW2_PMIC_DATA_1,
+	MSM_SPM_REG_SAW2_PMIC_DATA_2,
+	MSM_SPM_REG_SAW2_PMIC_DATA_3,
+	MSM_SPM_REG_SAW2_PMIC_DATA_4,
+	MSM_SPM_REG_SAW2_PMIC_DATA_5,
+	MSM_SPM_REG_SAW2_PMIC_DATA_6,
+	MSM_SPM_REG_SAW2_PMIC_DATA_7,
+	MSM_SPM_REG_SAW2_RST,
+
+	MSM_SPM_REG_NR_INITIALIZE = MSM_SPM_REG_SAW2_RST,
+
+	MSM_SPM_REG_SAW2_ID,
+	MSM_SPM_REG_SAW2_SECURE,
+	MSM_SPM_REG_SAW2_STS0,
+	MSM_SPM_REG_SAW2_STS1,
+	MSM_SPM_REG_SAW2_STS2,
+	MSM_SPM_REG_SAW2_VCTL,
+	MSM_SPM_REG_SAW2_SEQ_ENTRY,
+	MSM_SPM_REG_SAW2_SPM_STS,
+	MSM_SPM_REG_SAW2_AVS_STS,
+	MSM_SPM_REG_SAW2_PMIC_STS,
+	MSM_SPM_REG_SAW2_VERSION,
+
+	MSM_SPM_REG_NR,
+};
+
+struct msm_spm_seq_entry {
+	uint32_t mode;
+	uint8_t *cmd;
+	bool  notify_rpm;
+};
+
+struct msm_spm_platform_data {
+	void __iomem *reg_base_addr;
+	uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
+
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
+	uint32_t pfm_port;
+
+	uint8_t awake_vlevel;
+	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
+
+	uint32_t num_modes;
+	struct msm_spm_seq_entry *modes;
+};
+
+enum msm_spm_pmic_port {
+	MSM_SPM_PMIC_VCTL_PORT,
+	MSM_SPM_PMIC_PHASE_PORT,
+	MSM_SPM_PMIC_PFM_PORT,
+};
+
+struct msm_spm_driver_data {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
+	uint32_t pfm_port;
+	void __iomem *reg_base_addr;
+	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
+	uint32_t reg_shadow[MSM_SPM_REG_NR];
+	uint32_t *reg_seq_entry_shadow;
+	uint32_t *reg_offsets;
+};
+
+int msm_spm_drv_init(struct msm_spm_driver_data *dev,
+		struct msm_spm_platform_data *data);
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev);
+int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
+		uint32_t addr, bool pc_mode);
+int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
+		unsigned int vlevel);
+void dump_regs(struct msm_spm_driver_data *dev, int cpu);
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+		struct msm_spm_driver_data *dev);
+int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
+		uint8_t *cmd, uint32_t *offset);
+void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
+int msm_spm_drv_set_spm_enable(struct msm_spm_driver_data *dev,
+		bool enable);
+int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
+		enum msm_spm_pmic_port port, unsigned int data);
+
+void msm_spm_reinit(void);
+int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+#endif
diff --git a/include/soc/qcom/spm.h b/include/soc/qcom/spm.h
new file mode 100644
index 0000000..185ddaf
--- /dev/null
+++ b/include/soc/qcom/spm.h
@@ -0,0 +1,106 @@
+/* Copyright (c) 2010-2014, 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 __MSM_SPM_H
+#define __MSM_SPM_H
+
+enum {
+	MSM_SPM_MODE_DISABLED,
+	MSM_SPM_MODE_CLOCK_GATING,
+	MSM_SPM_MODE_RETENTION,
+	MSM_SPM_MODE_GDHS,
+	MSM_SPM_MODE_POWER_COLLAPSE,
+	MSM_SPM_MODE_NR
+};
+
+struct msm_spm_device;
+
+#if defined(CONFIG_QCOM_PM)
+
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
+int msm_spm_probe_done(void);
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
+unsigned int msm_spm_get_vdd(unsigned int cpu);
+int msm_spm_turn_on_cpu_rail(void __iomem *base, unsigned int val, int cpu);
+struct msm_spm_device *msm_spm_get_device_by_name(const char *name);
+int msm_spm_config_low_power_mode(struct msm_spm_device *dev,
+		unsigned int mode, bool notify_rpm);
+int msm_spm_device_init(void);
+bool msm_spm_is_mode_avail(unsigned int mode);
+void msm_spm_dump_regs(unsigned int cpu);
+int msm_spm_apcs_set_phase(int cpu, unsigned int phase_cnt);
+int msm_spm_enable_fts_lpm(int cpu, uint32_t mode);
+
+#else /* defined(CONFIG_QCOM_PM) */
+static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_probe_done(void)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	return -ENOSYS;
+}
+
+static inline unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+	return 0;
+}
+
+static inline int msm_spm_turn_on_cpu_rail(void __iomem *base,
+		unsigned int val, int cpu)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_device_init(void)
+{
+	return -ENOSYS;
+}
+
+static void msm_spm_dump_regs(unsigned int cpu)
+{
+}
+
+static inline int msm_spm_config_low_power_mode(struct msm_spm_device *dev,
+		unsigned int mode, bool notify_rpm)
+{
+	return -ENODEV;
+}
+static inline struct msm_spm_device *msm_spm_get_device_by_name(
+		const char *name)
+{
+	return NULL;
+}
+
+static inline bool msm_spm_is_mode_avail(unsigned int mode)
+{
+	return false;
+}
+
+static inline int msm_spm_apcs_set_phase(int cpu, unsigned int phase_cnt)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_enable_fts_lpm(int cpu, uint32_t mode)
+{
+	return -ENOSYS;
+}
+
+#endif  /* defined (CONFIG_QCOM_PM) */
+#endif  /* __MSM_SPM_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 04/13] arm: dts: qcom: Add SPM device bindings for 8974
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (2 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 03/13] qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 05/13] qcom: msm-pm: Add cpu low power mode functions Lina Iyer
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer, Praveen Chidambaram

Add SPM device bindings for QCOM 8974 based cpus. SPM is the sub-system
power manager and controls the logic around the cores (cpu and L2).

Each core has an instance of SPM and controls only that core. Each cpu
SPM is configured to support WFI and SPC (standalone-power collapse) and
L2 can do retention (clock-gating).

Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm/boot/dts/qcom-msm8974-pm.dtsi | 118 +++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/qcom-msm8974.dtsi    |   2 +
 2 files changed, 120 insertions(+)
 create mode 100644 arch/arm/boot/dts/qcom-msm8974-pm.dtsi

diff --git a/arch/arm/boot/dts/qcom-msm8974-pm.dtsi b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
new file mode 100644
index 0000000..8eb934e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
@@ -0,0 +1,118 @@
+/* Copyright (c) 2013-2014, 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.
+ */
+
+&soc {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,name = "core0";
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,name = "core1";
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,name = "core2";
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,name = "core3";
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,name = "system-l2";
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,cpu-vctl-mask = <0xf>;
+		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+	};
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 69dca2a..964ecd2 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -238,3 +238,5 @@
 		};
 	};
 };
+
+#include "qcom-msm8974-pm.dtsi"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 05/13] qcom: msm-pm: Add cpu low power mode functions
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (3 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 04/13] arm: dts: qcom: Add SPM device bindings for 8974 Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 06/13] qcom: msm-pm: Add support for hotplug and secondary startup Lina Iyer
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer, Venkat Devarasetty

Add interface layer to abstract and handle hardware specific
functionality for executing various cpu low power modes in QCOM
chipsets.

Signed-off-by: Venkat Devarasetty <vdevaras@codeaurora.org>
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/soc/qcom/Makefile |   2 +-
 drivers/soc/qcom/msm-pm.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++
 include/soc/qcom/pm.h     |  39 +++++++++
 3 files changed, 258 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/qcom/msm-pm.c
 create mode 100644 include/soc/qcom/pm.h

diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 3de7ed9..87c3b9704 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
-obj-$(CONFIG_QCOM_PM) +=	spm_devices.o spm.o
+obj-$(CONFIG_QCOM_PM) +=	spm_devices.o spm.o msm-pm.o
 
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/drivers/soc/qcom/msm-pm.c b/drivers/soc/qcom/msm-pm.c
new file mode 100644
index 0000000..17a7c8c
--- /dev/null
+++ b/drivers/soc/qcom/msm-pm.c
@@ -0,0 +1,218 @@
+/* Copyright (c) 2010-2014, 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/init.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <linux/tick.h>
+#include <linux/platform_device.h>
+#include <linux/cpu_pm.h>
+#include <linux/uaccess.h>
+
+#include <soc/qcom/spm.h>
+#include <soc/qcom/pm.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/scm-boot.h>
+
+#include <asm/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/system_misc.h>
+
+#define SCM_CMD_TERMINATE_PC	(0x2)
+#define SCM_CMD_CORE_HOTPLUGGED (0x10)
+#define SCM_FLUSH_FLAG_MASK	(0x3)
+
+static bool msm_pm_is_L1_writeback(void)
+{
+	u32 cache_id = 0;
+
+#if defined(CONFIG_CPU_V7)
+	u32 sel = 0;
+
+	asm volatile ("mcr p15, 2, %[ccselr], c0, c0, 0\n\t"
+		      "isb\n\t"
+		      "mrc p15, 1, %[ccsidr], c0, c0, 0\n\t"
+		      :[ccsidr]"=r" (cache_id)
+		      :[ccselr]"r" (sel)
+		     );
+	return cache_id & BIT(30);
+#elif defined(CONFIG_ARM64)
+	u32 sel = 0;
+	asm volatile("msr csselr_el1, %[ccselr]\n\t"
+		     "isb\n\t"
+		     "mrs %[ccsidr],ccsidr_el1\n\t"
+		     :[ccsidr]"=r" (cache_id)
+		     :[ccselr]"r" (sel)
+		    );
+	return cache_id & BIT(30);
+#else
+#error No valid CPU arch selected
+#endif
+}
+
+static inline void msm_arch_idle(void)
+{
+	mb();
+	wfi();
+}
+
+static bool msm_pm_swfi(bool from_idle)
+{
+	msm_arch_idle();
+	return true;
+}
+
+static bool msm_pm_retention(bool from_idle)
+{
+	int ret = 0;
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_RETENTION, false);
+	WARN_ON(ret);
+
+	msm_arch_idle();
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+
+	return true;
+}
+
+static int msm_pm_collapse(unsigned long from_idle)
+{
+	enum msm_pm_l2_scm_flag flag = MSM_SCM_L2_ON;
+
+	/**
+	 * Single core processors need to have L2
+	 * flushed when powering down the core.
+	 * Notify SCM to flush secure L2 lines.
+	 */
+	if (num_possible_cpus() == 1)
+		flag = MSM_SCM_L2_OFF;
+
+	if (flag == MSM_SCM_L2_OFF)
+		flush_cache_all();
+	else if (msm_pm_is_L1_writeback())
+		flush_cache_louis();
+
+	flag &= SCM_FLUSH_FLAG_MASK;
+	if (!from_idle)
+		flag |= SCM_CMD_CORE_HOTPLUGGED;
+
+	scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC, flag);
+
+	return 0;
+}
+
+static void set_up_boot_address(void *entry, int cpu, bool from_idle)
+{
+	static int flags[NR_CPUS] = {
+		SCM_FLAG_WARMBOOT_CPU0,
+		SCM_FLAG_WARMBOOT_CPU1,
+		SCM_FLAG_WARMBOOT_CPU2,
+		SCM_FLAG_WARMBOOT_CPU3,
+	};
+
+	scm_set_boot_addr(virt_to_phys(entry), flags[cpu]);
+}
+
+static bool __ref msm_pm_spm_power_collapse(
+	unsigned int cpu, bool from_idle)
+{
+	static DEFINE_PER_CPU(void *, last_known_entry);
+	void *entry;
+	bool collapsed = 0;
+	int ret;
+	bool save_cpu_regs = (cpu_online(cpu) || from_idle);
+
+	if (from_idle)
+		cpu_pm_enter();
+
+	ret = msm_spm_set_low_power_mode(
+			MSM_SPM_MODE_POWER_COLLAPSE, false);
+	WARN_ON(ret);
+
+	entry = save_cpu_regs ? cpu_resume : secondary_startup;
+	if (entry != per_cpu(last_known_entry, cpu)) {
+		per_cpu(last_known_entry, cpu) = entry;
+		set_up_boot_address(entry, cpu, from_idle);
+	}
+
+#ifdef CONFIG_CPU_V7
+	collapsed = !cpu_suspend(from_idle, msm_pm_collapse);
+#else
+	collapsed = !cpu_suspend(0);
+#endif
+
+	if (collapsed)
+		local_fiq_enable();
+
+	if (from_idle)
+		cpu_pm_exit();
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+
+	return collapsed;
+}
+
+static bool msm_pm_power_collapse_standalone(bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	bool collapsed;
+
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle);
+
+	return collapsed;
+}
+
+static bool msm_pm_power_collapse(bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	bool collapsed;
+
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle);
+
+	return collapsed;
+}
+
+static bool (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = msm_pm_swfi,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		msm_pm_power_collapse_standalone,
+	[MSM_PM_SLEEP_MODE_RETENTION] = msm_pm_retention,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = msm_pm_power_collapse,
+};
+
+/**
+ * msm_cpu_pm_enter_sleep(): Enter a low power mode on current cpu
+ *
+ * @mode - sleep mode to enter
+ * @from_idle - bool to indicate that the mode is exercised during idle/suspend
+ *
+ * The code should be with interrupts disabled and on the core on which the
+ * low power is to be executed.
+ *
+ */
+bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
+{
+	bool exit_stat = false;
+
+	if (execute[mode])
+		exit_stat = execute[mode](from_idle);
+
+	return exit_stat;
+}
+EXPORT_SYMBOL(msm_cpu_pm_enter_sleep);
diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h
new file mode 100644
index 0000000..01872ad
--- /dev/null
+++ b/include/soc/qcom/pm.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __QCOM_PM_H
+#define __QCOM_PM_H
+
+enum msm_pm_sleep_mode {
+	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+	MSM_PM_SLEEP_MODE_RETENTION,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+	MSM_PM_SLEEP_MODE_NR,
+};
+
+enum msm_pm_l2_scm_flag {
+	MSM_SCM_L2_ON = 0,
+	MSM_SCM_L2_OFF = 1,
+};
+
+#ifdef CONFIG_QCOM_PM
+bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
+#else
+static inline bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode,
+						bool from_idle)
+{ return true; }
+#endif
+
+#endif  /* __QCOM_PM_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 06/13] qcom: msm-pm: Add support for hotplug and secondary startup
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (4 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 05/13] qcom: msm-pm: Add cpu low power mode functions Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 07/13] qcom: sleep-status: Add ability to recognize cpu power down state Lina Iyer
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Add hotplug and secondary startup entry point to cold or warm boot
secondary cpus.

Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/soc/qcom/msm-pm.c | 36 ++++++++++++++++++++++++++++++++++++
 include/soc/qcom/pm.h     |  4 ++++
 2 files changed, 40 insertions(+)

diff --git a/drivers/soc/qcom/msm-pm.c b/drivers/soc/qcom/msm-pm.c
index 17a7c8c..4a6471d 100644
--- a/drivers/soc/qcom/msm-pm.c
+++ b/drivers/soc/qcom/msm-pm.c
@@ -216,3 +216,39 @@ bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
 	return exit_stat;
 }
 EXPORT_SYMBOL(msm_cpu_pm_enter_sleep);
+
+/**
+ * msm_pm_cpu_hotplug_enter - Entry point for SoC hotplug interface
+ * Set up cores to enter deeper sleep modes than just clock gating
+ * Find the best deepest low power mode that can enter
+ *
+ * @cpu - The cpu that is being hotplugged off
+ */
+int msm_pm_cpu_hotplug_enter(unsigned int cpu)
+{
+	enum msm_pm_sleep_mode mode = MSM_PM_SLEEP_MODE_NR;
+	int ret;
+
+	if (msm_spm_is_mode_avail(MSM_SPM_MODE_POWER_COLLAPSE))
+		mode = MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
+	else if (msm_spm_is_mode_avail( MSM_SPM_MODE_RETENTION))
+		mode = MSM_PM_SLEEP_MODE_RETENTION;
+	else
+		mode = MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT;
+
+	ret = msm_cpu_pm_enter_sleep(mode, false) ? 0 : -EFAULT;
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_pm_cpu_hotplug_enter);
+
+/**
+ * msm_pm_secondary_startup() - Restore after hotplug resume
+ *
+ * @ cpu: the cpu thats coming up.
+ */
+int msm_pm_secondary_startup(unsigned int cpu)
+{
+	return msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+}
+EXPORT_SYMBOL(msm_pm_secondary_startup);
diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h
index 01872ad..ed6124a 100644
--- a/include/soc/qcom/pm.h
+++ b/include/soc/qcom/pm.h
@@ -30,10 +30,14 @@ enum msm_pm_l2_scm_flag {
 
 #ifdef CONFIG_QCOM_PM
 bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
+int msm_pm_cpu_hotplug_enter(unsigned int cpu);
+int msm_pm_secondary_startup(unsigned int cpu);
 #else
 static inline bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode,
 						bool from_idle)
 { return true; }
+static inline int msm_pm_cpu_hotplug_enter(unsigned int cpu) { return 0; }
+static inline int msm_pm_secondary_startup(unsigned int cpu) { return 0; }
 #endif
 
 #endif  /* __QCOM_PM_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 07/13] qcom: sleep-status: Add ability to recognize cpu power down state
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (5 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 06/13] qcom: msm-pm: Add support for hotplug and secondary startup Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 08/13] arm: dts: qcom: Add device binding for sleep status Lina Iyer
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

QCOM processors get notified by the processor subsystem logic that
recognizes when a processor has entered the low power state. This is
used by PM to guarantee that the processor is indeed in its low
power state, before powering down the associated resources.

Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 .../bindings/arm/msm/qcom,cpu-sleep-status.txt     |  41 +++++
 drivers/soc/qcom/Makefile                          |   2 +-
 drivers/soc/qcom/sleep-status.c                    | 178 +++++++++++++++++++++
 include/soc/qcom/pm.h                              |   2 +
 4 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt
 create mode 100644 drivers/soc/qcom/sleep-status.c

diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt b/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt
new file mode 100644
index 0000000..3d2974e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt
@@ -0,0 +1,41 @@
+* MSM Sleep Status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,cpu-sleep-status"
+
+- reg:
+	Usage: required
+	Value type: <register address>
+	Definition: The physical address of the sleep status register for
+	core0, the second element is the size of the register.
+
+- qcom,cpu-alias-addr:
+	Usage: required
+	Value type: <integer>
+	Definition: On MSM chipset, the each cores registers are at a
+	fixed offset each other.
+
+- qcom,cpu-sleep-status-mask:
+	Usage: required
+	Value type: <integer>
+	Definition: The bit mask within the status register that
+	indicates the Core's sleep state.
+
+Example:
+	qcom,cpu-sleep-status@f9088008 {
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x4>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask = <0x80000>;
+	};
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 87c3b9704..d2cc9c0 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
-obj-$(CONFIG_QCOM_PM) +=	spm_devices.o spm.o msm-pm.o
+obj-$(CONFIG_QCOM_PM) +=	spm_devices.o spm.o msm-pm.o sleep-status.o
 
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/drivers/soc/qcom/sleep-status.c b/drivers/soc/qcom/sleep-status.c
new file mode 100644
index 0000000..aa6340c
--- /dev/null
+++ b/drivers/soc/qcom/sleep-status.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2010-2014, 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <soc/qcom/spm.h>
+#include <soc/qcom/pm.h>
+
+struct msm_pm_sleep_status_data {
+	void *base_addr;
+	uint32_t cpu_offset;
+	uint32_t mask;
+};
+
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+
+/**
+ * msm_pm_wait_cpu_shutdown() - Wait for a core to be power collapsed during
+ *				hotplug
+ *
+ * @ cpu - cpu to wait on.
+ *
+ * Blocking function call that waits on the core to be power collapsed. This
+ * function is called from platform_cpu_die to ensure that a core is power
+ * collapsed before sending the CPU_DEAD notification so the drivers could
+ * remove the resource votes for this CPU(regulator and clock)
+ */
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+	int timeout = 0;
+
+	if (!msm_pm_slp_sts)
+		return 0;
+
+	if (!msm_pm_slp_sts[cpu].base_addr)
+		return 0;
+
+	while (1) {
+		/*
+		 * Check for the SPM of the core being hotplugged to set
+		 * its sleep state.The SPM sleep state indicates that the
+		 * core has been power collapsed.
+		 */
+		int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+		if (acc_sts & msm_pm_slp_sts[cpu].mask)
+			return 0;
+
+		udelay(100);
+		/*
+		 * Dump spm registers for debugging
+		 */
+		if (++timeout == 20) {
+			msm_spm_dump_regs(cpu);
+			__WARN_printf(
+			"CPU%u didn't collapse in 2ms, sleep status: 0x%x\n",
+					cpu, acc_sts);
+		}
+	}
+
+	return -EBUSY;
+}
+
+static int msm_cpu_status_probe(struct platform_device *pdev)
+{
+	struct msm_pm_sleep_status_data *pdata;
+	char *key;
+	u32 cpu;
+
+	if (!pdev)
+		return -EFAULT;
+
+	msm_pm_slp_sts = devm_kcalloc(&pdev->dev, num_possible_cpus(),
+					sizeof(*msm_pm_slp_sts), GFP_KERNEL);
+
+	if (!msm_pm_slp_sts)
+		return -ENOMEM;
+
+	if (pdev->dev.of_node) {
+		struct resource *res;
+		u32 offset;
+		int rc;
+		u32 mask;
+		bool offset_available = true;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -ENODEV;
+
+		key = "qcom,cpu-alias-addr";
+		rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+		if (rc)
+			offset_available = false;
+
+		key = "qcom,sleep-status-mask";
+		rc = of_property_read_u32(pdev->dev.of_node, key, &mask);
+
+		if (rc)
+			return -ENODEV;
+
+		for_each_possible_cpu(cpu) {
+			phys_addr_t base_c;
+
+			if (offset_available)
+				base_c = res->start + cpu * offset;
+			else {
+				res = platform_get_resource(pdev,
+							IORESOURCE_MEM, cpu);
+				if (!res)
+					return -ENODEV;
+				base_c = res->start;
+			}
+
+			msm_pm_slp_sts[cpu].base_addr =
+				devm_ioremap(&pdev->dev, base_c,
+						resource_size(res));
+			msm_pm_slp_sts[cpu].mask = mask;
+
+			if (!msm_pm_slp_sts[cpu].base_addr)
+				return -ENOMEM;
+		}
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdev->dev.platform_data)
+			return -EINVAL;
+
+		for_each_possible_cpu(cpu) {
+			msm_pm_slp_sts[cpu].base_addr =
+				pdata->base_addr + cpu * pdata->cpu_offset;
+			msm_pm_slp_sts[cpu].mask = pdata->mask;
+		}
+	}
+
+	return 0;
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+	{.compatible = "qcom,cpu-sleep-status"},
+	{},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+	.probe = msm_cpu_status_probe,
+	.driver = {
+		.name = "qcom,cpu-sleep-status",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_slp_sts_match_tbl,
+	},
+};
+
+int __init msm_pm_sleep_status_init(void)
+{
+	static bool registered;
+
+	if (registered)
+		return 0;
+	registered = true;
+
+	return platform_driver_register(&msm_cpu_status_driver);
+}
+arch_initcall(msm_pm_sleep_status_init);
diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h
index ed6124a..3de04b8 100644
--- a/include/soc/qcom/pm.h
+++ b/include/soc/qcom/pm.h
@@ -32,12 +32,14 @@ enum msm_pm_l2_scm_flag {
 bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
 int msm_pm_cpu_hotplug_enter(unsigned int cpu);
 int msm_pm_secondary_startup(unsigned int cpu);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
 #else
 static inline bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode,
 						bool from_idle)
 { return true; }
 static inline int msm_pm_cpu_hotplug_enter(unsigned int cpu) { return 0; }
 static inline int msm_pm_secondary_startup(unsigned int cpu) { return 0; }
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
 #endif
 
 #endif  /* __QCOM_PM_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 08/13] arm: dts: qcom: Add device binding for sleep status
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (6 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 07/13] qcom: sleep-status: Add ability to recognize cpu power down state Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 09/13] soc: qcom: Add QCOM Power management config Lina Iyer
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

QCOM processors get the feedback on the processor subsystem logic that
notifies when the processor has entered the low power state. This is
used for pm to gaurantee that the processor is indeed in its low
power state before the associated resources can be turned off.

Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm/boot/dts/qcom-msm8974-pm.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974-pm.dtsi b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
index 8eb934e..8fe00f1 100644
--- a/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
@@ -115,4 +115,11 @@
 		qcom,cpu-vctl-mask = <0xf>;
 		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
 	};
+
+	qcom,cpu-sleep-status@f9088008 {
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x100>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 09/13] soc: qcom: Add QCOM Power management config
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (7 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 08/13] arm: dts: qcom: Add device binding for sleep status Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 10/13] qcom: platsmp: Enable deeper idle states for hotplug Lina Iyer
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Allow power management drivers for QCOM chipsets.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/soc/qcom/Kconfig | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 7dcd554..1569410 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -11,3 +11,11 @@ config QCOM_GSBI
 
 config QCOM_SCM
 	bool
+
+config QCOM_PM
+	tristate "Qualcomm Power Management"
+	depends on PM && ARCH_QCOM && OF
+	help
+	  QCOM Platform specific power driver to manage cores and L2 low power
+	  modes. It interface with various system drivers to put the cores in
+	  low power modes.
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 10/13] qcom: platsmp: Enable deeper idle states for hotplug
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (8 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 09/13] soc: qcom: Add QCOM Power management config Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 11/13] qcom: cpuidle: Add cpuidle driver for QCOM cpus Lina Iyer
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Allow cpu and system deeper sleep modes when a cpu is hotplugged.
Calling wfi() executes architectural clock gating supported by the ARM
core, while this is useful, it does not save leakage power and does not
help in reducing power in the peripheral logic surrounding the cpu.

QCOM platforms have a sub-system power manager to control the logic
around the core. Pass the hotplug call over to SoC idle interface driver
to allow for the core and the peripheral logic to enter low power when
hotplugged.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm/mach-qcom/platsmp.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index d690856..c40f220 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -20,7 +20,8 @@
 
 #include <asm/smp_plat.h>
 
-#include "scm-boot.h"
+#include <soc/qcom/scm-boot.h>
+#include <soc/qcom/pm.h>
 
 #define VDD_SC1_ARRAY_CLAMP_GFS_CTL	0x35a0
 #define SCSS_CPU1CORE_RESET		0x2d80
@@ -51,12 +52,30 @@ static DEFINE_SPINLOCK(boot_lock);
 #ifdef CONFIG_HOTPLUG_CPU
 static void __ref qcom_cpu_die(unsigned int cpu)
 {
+#if defined CONFIG_QCOM_PM
+	for (;;)
+		msm_pm_cpu_hotplug_enter(cpu);
+#else
 	wfi();
+#endif
+}
+
+static int __ref qcom_cpu_kill(unsigned int cpu)
+{
+	int ret = 0;
+
+#if defined CONFIG_QCOM_PM
+	ret = msm_pm_wait_cpu_shutdown(cpu) ? 0 : 1;
+#endif
+	return ret;
 }
+
 #endif
 
 static void qcom_secondary_init(unsigned int cpu)
 {
+	msm_pm_secondary_startup(cpu);
+
 	/*
 	 * Synchronise with the boot thread.
 	 */
@@ -373,6 +392,7 @@ static struct smp_operations qcom_smp_kpssv2_ops __initdata = {
 	.smp_boot_secondary	= kpssv2_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
 	.cpu_die		= qcom_cpu_die,
+	.cpu_kill		= qcom_cpu_kill,
 #endif
 };
 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 11/13] qcom: cpuidle: Add cpuidle driver for QCOM cpus
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (9 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 10/13] qcom: platsmp: Enable deeper idle states for hotplug Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 12/13] qcom: cpuidle: Add cpuidle device nodes for 8974 chipset Lina Iyer
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Add cpuidle driver interface to allow cpus to go into C-States.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 .../devicetree/bindings/arm/msm/qcom,cpuidle.txt   |  73 +++++++++++
 drivers/cpuidle/Makefile                           |   1 +
 drivers/cpuidle/cpuidle-qcom.c                     | 140 +++++++++++++++++++++
 3 files changed, 214 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt
 create mode 100644 drivers/cpuidle/cpuidle-qcom.c

diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt b/Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt
new file mode 100644
index 0000000..b094baf
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt
@@ -0,0 +1,73 @@
+Qualcomm CPUIdle driver
+
+The Qualcomm cpuidle driver enables the processor to enter low power modes
+when idle. The processors support 4 low power modes.
+	wfi - also known as clock gating
+	retention - processor clock gated and processor power is reduced.
+	standalone-pc - processor is powered down and when reset, the core
+		boots into secure mode and trampolines back to the kernel.
+		Every core can individually enter this low power mode without
+		affecting the state of the other cores.
+	pc - essentially standalone power collapse, but indicates that the
+		latency to put SoC into a low power state is tolerable.
+
+The cpuidle node is comprised of nodes, each of which represent a C-State the
+processor can achieve. Each node provides the latency and residency which
+helps the cpuidle governor to choose the appropriate low power mode based on
+the time available. Not all SoCs may support all the above low power modes.
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,cpuidle"
+
+- qcom,cpu-level:
+	Usage: required
+	Value type: { Node }
+	Definition: Describes a C-State of the processor
+
+	PROPERTIES of qcom,cpu-level
+
+	- reg:
+		Usage: required
+		Value type: <integer>
+		Definition: Index of the C-State
+
+	- qcom,state-name:
+		Usage: required
+		Value type: <string>
+		Definition: C-State moniker
+
+	- qcom,spm-cpu-mode:
+		Usage: required
+		Value type: <string>
+		Definition: The description of the h/w mode that will be
+			achieved in this C-State.
+
+	- qcom,latency-us:
+		Usage: required
+		Value type: <integer>
+		Defintion: Time taken to exit from the C-State
+
+	- qcom,residency-us:
+		Usage: required
+		Value type: <integer>
+		Defintion: Time to be spent in this C-State for the power
+			saving to be beneficial.
+
+Example:
+
+	qcom,cpuidle {
+		compatible = "qcom,cpuidle";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		qcom,cpu-level@0 {
+			reg = <0x0>;
+			qcom,state-name = "C1";
+			qcom,spm-cpu-mode = "wfi";
+			qcom,latency-us = <1>;
+			qcom,residency-us = <1>;
+		};
+	};
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 11edb31..4a2c446 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
 obj-$(CONFIG_ARM_EXYNOS_CPUIDLE)        += cpuidle-exynos.o
+obj-$(CONFIG_ARM_QCOM_CPUIDLE)		+= cpuidle-qcom.o
 
 ###############################################################################
 # MIPS drivers
diff --git a/drivers/cpuidle/cpuidle-qcom.c b/drivers/cpuidle/cpuidle-qcom.c
new file mode 100644
index 0000000..8e70a88
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-qcom.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014 Linaro.
+ *
+ * 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/platform_device.h>
+#include <linux/of.h>
+#include <linux/cpuidle.h>
+
+#include <soc/qcom/pm.h>
+
+struct lookup {
+	enum msm_pm_sleep_mode mode;
+	char *name;
+};
+
+static enum msm_pm_sleep_mode spm_sleep_modes[MSM_PM_SLEEP_MODE_NR];
+
+static int qcom_lpm_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	return msm_cpu_pm_enter_sleep(spm_sleep_modes[index], true);
+}
+
+static struct cpuidle_driver qcom_cpuidle_driver = {
+	.name	= "qcom_cpuidle",
+	.owner	= THIS_MODULE,
+};
+
+static int qcom_cpuidle_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *top = pdev->dev.of_node;
+	struct device_node *n;
+	char *key;
+	const char *val;
+	int index = 0;
+	int i;
+	struct cpuidle_state *state;
+	static const struct lookup pm_sm_lookup[] = {
+		{MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+			"wfi"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+			"standalone_pc"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+			"pc"},
+		{MSM_PM_SLEEP_MODE_RETENTION,
+			"retention"},
+	};
+
+	if (!top)
+		return -ENODEV;
+
+	for_each_child_of_node(top, n) {
+		key = "qcom,cpu-level";
+		if (of_node_cmp(n->name, key))
+			continue;
+
+		state = &qcom_cpuidle_driver.states[index];
+
+		key = "qcom,spm-cpu-mode";
+		ret = of_property_read_string(n, key, &val);
+		if (ret)
+			goto failed;
+		for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
+			if (!strcmp(val, pm_sm_lookup[i].name)) {
+				spm_sleep_modes[index] = pm_sm_lookup[i].mode;
+				break;
+			}
+		}
+		if (i == ARRAY_SIZE(pm_sm_lookup)) {
+			ret = -EFAULT;
+			goto failed;
+		}
+
+		strncpy(state->desc, val, CPUIDLE_DESC_LEN);
+
+		key = "qcom,state-name";
+		ret = of_property_read_string(n, key, &val);
+		if (ret)
+			goto failed;
+		strncpy(state->name, val, CPUIDLE_NAME_LEN);
+
+		key = "qcom,latency-us";
+		ret = of_property_read_u32(n, key, &state->exit_latency);
+		if (ret)
+			goto failed;
+
+		key = "qcom,residency-us";
+		ret = of_property_read_u32(n, key, &state->target_residency);
+		if (ret)
+			goto failed;
+
+		state->flags = CPUIDLE_FLAG_TIME_VALID;
+		state->enter = qcom_lpm_enter;
+		index++;
+	}
+
+	qcom_cpuidle_driver.state_count = index;
+	qcom_cpuidle_driver.safe_state_index = 0;
+
+	ret = cpuidle_register(&qcom_cpuidle_driver, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register cpuidle driver\n");
+		return ret;
+	}
+
+	return 0;
+
+failed:
+	dev_err(&pdev->dev, "error parsing key: %s\n", key);
+	return ret;
+}
+
+static struct of_device_id qcom_cpuidle_match_tbl[] = {
+	{.compatible = "qcom,cpuidle"},
+	{},
+};
+
+static struct platform_driver qcom_cpuidle_platform_driver = {
+	.probe	= qcom_cpuidle_probe,
+	.driver	= {
+		.name = "qcom,cpuidle",
+		.owner = THIS_MODULE,
+		.of_match_table = qcom_cpuidle_match_tbl,
+	},
+};
+
+module_platform_driver(qcom_cpuidle_platform_driver);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 12/13] qcom: cpuidle: Add cpuidle device nodes for 8974 chipset
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (10 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 11/13] qcom: cpuidle: Add cpuidle driver for QCOM cpus Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08  4:00 ` [RFC] [PATCH 13/13] qcom: cpuidle: Config option to enable QCOM cpuidle driver Lina Iyer
  2014-08-08 14:33 ` [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Add C-States and the respective residencies supported by the QCOM 8974
chipset. Current support is for WFI (clock gating) and Standlone-PC
(power down of the core).

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm/boot/dts/qcom-msm8974-pm.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974-pm.dtsi b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
index 8fe00f1..4e3c206 100644
--- a/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974-pm.dtsi
@@ -122,4 +122,25 @@
 		qcom,cpu-alias-addr = <0x10000>;
 		qcom,sleep-status-mask= <0x80000>;
 	};
+
+	qcom,cpuidle {
+		compatible = "qcom,cpuidle";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		qcom,cpu-level@0 {
+			reg = <0x0>;
+			qcom,state-name = "C1";
+			qcom,spm-cpu-mode = "wfi";
+			qcom,latency-us = <1>;
+			qcom,residency-us = <1>;
+		};
+
+		qcom,cpu-level@2 {
+			reg = <0x1>;
+			qcom,state-name = "C2";
+			qcom,spm-cpu-mode = "standalone_pc";
+			qcom,latency-us = <300>;
+			qcom,residency-us = <2000>;
+		};
+	};
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 13/13] qcom: cpuidle: Config option to enable QCOM cpuidle driver
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (11 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 12/13] qcom: cpuidle: Add cpuidle device nodes for 8974 chipset Lina Iyer
@ 2014-08-08  4:00 ` Lina Iyer
  2014-08-08 14:33 ` [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:00 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel
  Cc: msivasub, bryanh, Lina Iyer

Allow cpuidle framework to determine the C-State of the QCOM cpus.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/cpuidle/Kconfig.arm | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index 38cff69..ad52605 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -62,3 +62,9 @@ config ARM_MVEBU_V7_CPUIDLE
 	depends on ARCH_MVEBU
 	help
 	  Select this to enable cpuidle on Armada 370, 38x and XP processors.
+
+config ARM_QCOM_CPUIDLE
+	bool "CPU Idle drivers for Qualcomm processors"
+	depends on QCOM_PM
+	help
+	  Select this to enable cpuidle for QCOM processors
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets.
  2014-08-08  4:05 [RFC] [PATCH 00/13] QCOM: 8074 " Lina Iyer
@ 2014-08-08  4:05 ` Lina Iyer
  0 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08  4:05 UTC (permalink / raw)
  To: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm
  Cc: msivasub, bryanh, Lina Iyer

Quad core targets like APQ8074, 78064, 8084 need SCM support set up
warm boot addresses in the Secure Monitor. Extend the SCM flags to
support warmboot addresses for seconday cores.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/soc/qcom/scm-boot.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/soc/qcom/scm-boot.h b/include/soc/qcom/scm-boot.h
index 6aabb24..7ae2152 100644
--- a/include/soc/qcom/scm-boot.h
+++ b/include/soc/qcom/scm-boot.h
@@ -18,6 +18,9 @@
 #define SCM_FLAG_COLDBOOT_CPU3		0x20
 #define SCM_FLAG_WARMBOOT_CPU0		0x04
 #define SCM_FLAG_WARMBOOT_CPU1		0x02
+#define SCM_FLAG_WARMBOOT_CPU2		0x10
+#define SCM_FLAG_WARMBOOT_CPU3		0x40
+
 
 int scm_set_boot_addr(phys_addr_t addr, int flags);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver
  2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
                   ` (12 preceding siblings ...)
  2014-08-08  4:00 ` [RFC] [PATCH 13/13] qcom: cpuidle: Config option to enable QCOM cpuidle driver Lina Iyer
@ 2014-08-08 14:33 ` Lina Iyer
  13 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08 14:33 UTC (permalink / raw)
  To: Lina Iyer
  Cc: daniel.lezcano, khilman, amit.kucheria, sboyd, davidb, galak,
	linux-arm-msm, linux-arm-kernel, msivasub, bryanh


Sorry for spamming, please ignore this series. The email address I used
was incorrect and also the subject.

I apologize.

Lina

On Thu, 7 Aug 2014, Lina Iyer wrote:

> Hello everybody,
> 
> Here are the set of patches for enabling cpuidle driver for 8074 based targets.
> 
> 8074 like any ARM SoC can do architectural clock gating, that helps save on
> power, but not enough of leakage power.  Leakage power of the SoC can be
> further reduced by turning off power to the core. To aid this, every core (cpu
> and L2) is accompanied by a Sub-system Power Manager (SPM), that can be
> configured to indicate the low power mode, the core would be put into and the
> SPM programs the peripheral h/w accordingly to enter low power and turn off the
> power rail to the core.
> 
> The patchsets do the following
> 
> - Move scm-boot files from arm/mach-qcom to drivers/soc, following convention.
> They are based on Stephen Boyd's series of patches
> [http://www.spinics.net/lists/linux-arm-msm/msg10482.html]
> 
> - Add new Secure Monitor flags to support warmboot of a quad core system.
> 
> - Introduce the SPM driver to control power to the core. The SPM h/w IP works
> in conjunction with the Krait CPU/L2. When the core executes WFI instruction,
> the core is clockgated and the SPM state machine takes over and powers the core
> down. An interrupt from GIC, resumes the SPM state machine which brings the cpu
> out of the low power mode.
> 
> - Add the device tree configuration for each of the SPM nodes. There is one for
> each cpu. There is one for each cpu and one for L2 and one for L2.
> 
> - Introduce the SoC driver interface layer to configure SPM per the core's idle
>  state. To power down the cpu core, the SPM h/w needs to be set up correctly
> to power down the core, when the core executes WFI. Linux is expected to call
> into Secure Monitor to power down the core. At reset, the core will start in
> Seure mode and will be returned back to Linux.  Also, when powering down the
> core, let the SCM know the state of L2 as set up in Linux. This allows secure
> monitor to flush the secure lines when Linux knows the cache may be powered
> off. 
> 
> - Add ability to recognize the power down status of the core, to ensure that
> the core is indeed powered down before powering down peripheral h/w.
> 
> - Add support for deeper idle states than just clock gating for hotplug and warmboot
> 
> - Add CPUIDLE driver for QCOM cpus. The cpuidle driver uses the SoC interface
> layer to configure the SPM to allow Krait to be powered down. The driver
> supports 4 low power modes, but not all SoCs, support all low power modes. The
> modes supported are configured in device tree nodes.
> 
> - Provide device configuration for 8074 SoC. Current support is for WFI and
> standalone power collapse, which powers only the core independent of the
> other cores and caches.
> 
> - KConfig option to enable the driver
> 
> I have tested them on the Dragonboard 8074. The drivers should be fairly
> extensible to 8084.
> 
> Thanks
> Lina
> 
> 
> Lina Iyer (13):
>   msm: scm: Move scm-boot files to drivers/soc and include/soc
>   msm: scm: Add SCM warmboot flags for quad core targets.
>   qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets
>   arm: dts: qcom: Add SPM device bindings for 8974
>   qcom: msm-pm: Add cpu low power mode functions
>   qcom: msm-pm: Add support for hotplug and secondary startup
>   qcom: sleep-status: Add ability to recognize cpu power down state
>   arm: dts: qcom: Add device binding for sleep status
>   soc: qcom: Add QCOM Power management config
>   qcom: platsmp: Enable deeper idle states for hotplug
>   qcom: cpuidle: Add cpuidle driver for QCOM cpus
>   qcom: cpuidle: Add cpuidle device nodes for 8974 chipset
>   qcom: cpuidle: Config option to enable QCOM cpuidle driver
> 
>  .../bindings/arm/msm/qcom,cpu-sleep-status.txt     |  41 ++
>  .../devicetree/bindings/arm/msm/qcom,cpuidle.txt   |  73 +++
>  .../devicetree/bindings/arm/msm/spm-v2.txt         | 104 +++
>  arch/arm/boot/dts/qcom-msm8974-pm.dtsi             | 146 +++++
>  arch/arm/boot/dts/qcom-msm8974.dtsi                |   2 +
>  arch/arm/mach-qcom/Makefile                        |   1 -
>  arch/arm/mach-qcom/platsmp.c                       |  22 +-
>  drivers/cpuidle/Kconfig.arm                        |   6 +
>  drivers/cpuidle/Makefile                           |   1 +
>  drivers/cpuidle/cpuidle-qcom.c                     | 140 ++++
>  drivers/soc/qcom/Kconfig                           |   8 +
>  drivers/soc/qcom/Makefile                          |   4 +-
>  drivers/soc/qcom/msm-pm.c                          | 254 ++++++++
>  .../arm/mach-qcom => drivers/soc/qcom}/scm-boot.c  |   4 +-
>  drivers/soc/qcom/sleep-status.c                    | 178 ++++++
>  drivers/soc/qcom/spm.c                             | 559 ++++++++++++++++
>  drivers/soc/qcom/spm_devices.c                     | 709 +++++++++++++++++++++
>  drivers/soc/qcom/spm_driver.h                      | 118 ++++
>  include/soc/qcom/pm.h                              |  45 ++
>  .../arm/mach-qcom => include/soc/qcom}/scm-boot.h  |   3 +
>  include/soc/qcom/spm.h                             | 106 +++
>  21 files changed, 2519 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpuidle.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/msm/spm-v2.txt
>  create mode 100644 arch/arm/boot/dts/qcom-msm8974-pm.dtsi
>  create mode 100644 drivers/cpuidle/cpuidle-qcom.c
>  create mode 100644 drivers/soc/qcom/msm-pm.c
>  rename {arch/arm/mach-qcom => drivers/soc/qcom}/scm-boot.c (97%)
>  create mode 100644 drivers/soc/qcom/sleep-status.c
>  create mode 100644 drivers/soc/qcom/spm.c
>  create mode 100644 drivers/soc/qcom/spm_devices.c
>  create mode 100644 drivers/soc/qcom/spm_driver.h
>  create mode 100644 include/soc/qcom/pm.h
>  rename {arch/arm/mach-qcom => include/soc/qcom}/scm-boot.h (91%)
>  create mode 100644 include/soc/qcom/spm.h
> 
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets.
  2014-08-08  4:00 ` [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer
@ 2014-08-08 16:19   ` Kumar Gala
  2014-08-08 22:06     ` Lina Iyer
  0 siblings, 1 reply; 18+ messages in thread
From: Kumar Gala @ 2014-08-08 16:19 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Daniel Lezcano, Kevin Hilman, Amit Kucheria, Stephen Boyd,
	David Brown, linux-arm-msm, linux-arm-kernel, msivasub, bryanh


On Aug 7, 2014, at 11:00 PM, Lina Iyer <lina.iyer@linaro.org> wrote:

> Quad core targets like APQ8074, 78064, 8084 need SCM support set up
> warm boot addresses in the Secure Monitor. Extend the SCM flags to
> support warmboot addresses for seconday cores.

Fix comment message, 78064 should probably be APQ8064 and 8084 should probably be APQ8084.

> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
> include/soc/qcom/scm-boot.h | 3 +++
> 1 file changed, 3 insertions(+)
> 
> diff --git a/include/soc/qcom/scm-boot.h b/include/soc/qcom/scm-boot.h
> index 6aabb24..7ae2152 100644
> --- a/include/soc/qcom/scm-boot.h
> +++ b/include/soc/qcom/scm-boot.h
> @@ -18,6 +18,9 @@
> #define SCM_FLAG_COLDBOOT_CPU3		0x20
> #define SCM_FLAG_WARMBOOT_CPU0		0x04
> #define SCM_FLAG_WARMBOOT_CPU1		0x02
> +#define SCM_FLAG_WARMBOOT_CPU2		0x10
> +#define SCM_FLAG_WARMBOOT_CPU3		0x40
> +
> 
> int scm_set_boot_addr(phys_addr_t addr, int flags);
> 
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets.
  2014-08-08 16:19   ` Kumar Gala
@ 2014-08-08 22:06     ` Lina Iyer
  0 siblings, 0 replies; 18+ messages in thread
From: Lina Iyer @ 2014-08-08 22:06 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Daniel Lezcano, Kevin Hilman, Amit Kucheria, Stephen Boyd,
	David Brown, linux-arm-msm, linux-arm-kernel, msivasub, bryanh

On Fri, Aug 08, 2014 at 11:19:07AM -0500, Kumar Gala wrote:
>
>On Aug 7, 2014, at 11:00 PM, Lina Iyer <lina.iyer@linaro.org> wrote:
>
>> Quad core targets like APQ8074, 78064, 8084 need SCM support set up
>> warm boot addresses in the Secure Monitor. Extend the SCM flags to
>> support warmboot addresses for seconday cores.
>
>Fix comment message, 78064 should probably be APQ8064 and 8084 should probably be APQ8084.
Sure.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-08-08 22:06 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-08  4:00 [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 01/13] msm: scm: Move scm-boot files to drivers/soc and include/soc Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer
2014-08-08 16:19   ` Kumar Gala
2014-08-08 22:06     ` Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 03/13] qcom: spm: Add Subsystem Power Manager driver for QCOM chipsets Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 04/13] arm: dts: qcom: Add SPM device bindings for 8974 Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 05/13] qcom: msm-pm: Add cpu low power mode functions Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 06/13] qcom: msm-pm: Add support for hotplug and secondary startup Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 07/13] qcom: sleep-status: Add ability to recognize cpu power down state Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 08/13] arm: dts: qcom: Add device binding for sleep status Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 09/13] soc: qcom: Add QCOM Power management config Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 10/13] qcom: platsmp: Enable deeper idle states for hotplug Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 11/13] qcom: cpuidle: Add cpuidle driver for QCOM cpus Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 12/13] qcom: cpuidle: Add cpuidle device nodes for 8974 chipset Lina Iyer
2014-08-08  4:00 ` [RFC] [PATCH 13/13] qcom: cpuidle: Config option to enable QCOM cpuidle driver Lina Iyer
2014-08-08 14:33 ` [RFC] [PATCH 00/13] QCOM: 8087 CPUIDLE driver Lina Iyer
  -- strict thread matches above, loose matches on Subject: below --
2014-08-08  4:05 [RFC] [PATCH 00/13] QCOM: 8074 " Lina Iyer
2014-08-08  4:05 ` [RFC] [PATCH 02/13] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).