Merge "mmc: msm_sdcc: Fix compilation error" into msm-3.0
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..a33d833
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -0,0 +1,66 @@
+* 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, core-id: The core id the SPM block is attached to.
+ {0..n} for cores {0..n}
+ {0xffff} for L2
+- 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,saw2-vctl-timeout-us: The timeout value to wait for voltage to change
+ after sending the voltage command to the PMIC
+
+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-dly: The delay values for waiting on PMIC response
+- qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS
+ index to send the PMIC data to
+- qcom,saw2-vctl-port: The FTS port used for changing voltage
+- qcom,saw2-phase-port: The FTS port used for changing the number of phases
+- 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: The Power Collapse command sequence
+
+Example:
+ 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,spm-cmd-wfi = [03 0b 0f];
+ qcom,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,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 2ce5268..7dfa4df 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msmcopper_pm.dtsi"
/include/ "msm-pm8841.dtsi"
/include/ "msm-pm8941.dtsi"
/include/ "msmcopper-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
new file mode 100644
index 0000000..53ad0d1
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/ "skeleton.dtsi"
+
+/ {
+ 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,spm-cmd-wfi = [03 0b 0f];
+ qcom,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,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ 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,spm-cmd-wfi = [03 0b 0f];
+ qcom,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,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ 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,spm-cmd-wfi = [03 0b 0f];
+ qcom,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,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ 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,spm-cmd-wfi = [03 0b 0f];
+ qcom,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,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1a>;
+ 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 = <0x0>; /* TODO: Enable L2 SPM */
+ qcom,saw2-pmic-dly = <0x02020204>;
+ qcom,saw2-pmic-data0 = <0x0400009c>;
+ qcom,saw2-pmic-data1 = <0x00000060>;
+ qcom,saw2-pmic-data2 = <0x0000001c>;
+ qcom,saw2-pmic-data3 = <0x04000000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>; /* TODO: */
+ qcom,phase-port = <0x1>; /* TODO: */
+ qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
+ qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
+ 78 80 44 22 50 3b 60 02 32
+ 50 0f];
+ qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
+ 07 01 b0 78 80 12 44 a0 50
+ 3b 60 02 32 a0 50 0f];
+ };
+};
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3164281..076c609 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -243,6 +243,8 @@
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
select MSM_PIL
+ select MSM_SPM_V2
+ select MSM_L2_SPM
config ARCH_FSM9XXX
bool "FSM9XXX"
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index fbfd191..aaf1879 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -198,31 +198,6 @@
},
};
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data apq8064_rtb_pdata = {
- .size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
- int s;
-
- s = memparse(p, NULL);
- apq8064_rtb_pdata.size = ALIGN(s, SZ_4K);
- return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device apq8064_rtb_device = {
- .name = "msm_rtb",
- .id = -1,
- .dev = {
- .platform_data = &apq8064_rtb_pdata,
- },
-};
-#endif
-
static void __init reserve_rtb_memory(void)
{
#if defined(CONFIG_MSM_RTB)
@@ -1968,9 +1943,7 @@
&msm_8960_q6_lpass,
&msm_pil_vidc,
&msm_gss,
-#ifdef CONFIG_MSM_RTB
&apq8064_rtb_device,
-#endif
&apq8064_cpu_idle_device,
&apq8064_msm_gov_device,
&apq8064_device_cache_erp,
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 3729385..67e0e6f 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -19,6 +19,7 @@
#include <mach/msm_memtypes.h>
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
+#include <mach/msm_rtb.h>
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8921_GPIO_BASE NR_GPIO_IRQS
@@ -141,4 +142,5 @@
SX150X_EXP4,
};
+extern struct msm_rtb_platform_data apq8064_rtb_pdata;
#endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index dfc973c..cbb36a1 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -249,30 +249,6 @@
},
};
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data msm8930_rtb_pdata = {
- .size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
- int s;
-
- s = memparse(p, NULL);
- msm8930_rtb_pdata.size = ALIGN(s, SZ_4K);
- return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device msm8930_rtb_device = {
- .name = "msm_rtb",
- .id = -1,
- .dev = {
- .platform_data = &msm8930_rtb_pdata,
- },
-};
-#endif
static void __init reserve_rtb_memory(void)
{
@@ -1790,9 +1766,7 @@
#ifdef MSM8930_PHASE_2
&gpio_keys_8930,
#endif
-#ifdef CONFIG_MSM_RTB
&msm8930_rtb_device,
-#endif
&msm8930_cpu_idle_device,
&msm8930_msm_gov_device,
&msm_bus_8930_apps_fabric,
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index a8fad72..2bbbf80 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -22,6 +22,7 @@
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
#include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
/*
* TODO: When physical 8930/PM8038 hardware becomes
@@ -137,3 +138,5 @@
#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
#define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
#define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8930_rtb_pdata;
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index dd001bc..dddf65d 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -291,31 +291,6 @@
},
};
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data msm8960_rtb_pdata = {
- .size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
- int s;
-
- s = memparse(p, NULL);
- msm8960_rtb_pdata.size = ALIGN(s, SZ_4K);
- return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device msm8960_rtb_device = {
- .name = "msm_rtb",
- .id = -1,
- .dev = {
- .platform_data = &msm8960_rtb_pdata,
- },
-};
-#endif
-
static void __init reserve_rtb_memory(void)
{
#if defined(CONFIG_MSM_RTB)
@@ -2587,9 +2562,7 @@
#endif
&msm_device_dspcrashd_8960,
&msm8960_device_watchdog,
-#ifdef CONFIG_MSM_RTB
&msm8960_rtb_device,
-#endif
&msm8960_cpu_idle_device,
&msm8960_msm_gov_device,
&msm8960_device_cache_erp,
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 3824cfd..6a4c92e 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -20,6 +20,7 @@
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
#include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8921_GPIO_BASE NR_GPIO_IRQS
@@ -92,3 +93,5 @@
#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8960_rtb_pdata;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 1ad089d..b51fb83 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -31,6 +31,7 @@
#include <mach/mdm2.h>
#include <mach/msm_smd.h>
#include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
#include <mach/qdss.h>
#include <linux/ion.h>
#include "clock.h"
@@ -2407,5 +2408,27 @@
.id = -1,
.dev = {
.platform_data = &apq8064_iommu_domain_pdata,
+ }
+};
+
+struct msm_rtb_platform_data apq8064_rtb_pdata = {
+ .size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+ int s;
+
+ s = memparse(p, NULL);
+ apq8064_rtb_pdata.size = ALIGN(s, SZ_4K);
+ return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device apq8064_rtb_device = {
+ .name = "msm_rtb",
+ .id = -1,
+ .dev = {
+ .platform_data = &apq8064_rtb_pdata,
},
};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index b7048db..ae97189 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -23,6 +23,7 @@
#include <mach/board.h>
#include <mach/socinfo.h>
#include <mach/iommu_domains.h>
+#include <mach/msm_rtb.h>
#include "devices.h"
#include "rpm_log.h"
@@ -785,5 +786,28 @@
.id = -1,
.dev = {
.platform_data = &msm8930_iommu_domain_pdata,
+ }
+};
+
+struct msm_rtb_platform_data msm8930_rtb_pdata = {
+ .size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+ int s;
+
+ s = memparse(p, NULL);
+ msm8930_rtb_pdata.size = ALIGN(s, SZ_4K);
+ return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8930_rtb_device = {
+ .name = "msm_rtb",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm8930_rtb_pdata,
},
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 813d3c2..7fb4b01 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -32,6 +32,7 @@
#include <mach/msm_memtypes.h>
#include <mach/msm_smd.h>
#include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
@@ -3502,5 +3503,28 @@
.id = -1,
.dev = {
.platform_data = &msm8960_iommu_domain_pdata,
+ }
+};
+
+struct msm_rtb_platform_data msm8960_rtb_pdata = {
+ .size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+ int s;
+
+ s = memparse(p, NULL);
+ msm8960_rtb_pdata.size = ALIGN(s, SZ_4K);
+ return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8960_rtb_device = {
+ .name = "msm_rtb",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm8960_rtb_pdata,
},
};
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 5718fe0..8e9beb6 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -378,3 +378,7 @@
extern struct platform_device msm8960_iommu_domain_device;
extern struct platform_device msm8930_iommu_domain_device;
extern struct platform_device apq8064_iommu_domain_device;
+
+extern struct platform_device msm8960_rtb_device;
+extern struct platform_device msm8930_rtb_device;
+extern struct platform_device apq8064_rtb_device;
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 2a6294f..051d4de 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -21,6 +21,14 @@
#include "spm_driver.h"
+#define MSM_SPM_PMIC_STATE_IDLE 0
+
+#define SAW2_V1_VER_REG 0x04
+#define SAW2_V2_VER_REG 0xfd0
+
+#define SAW2_MAJOR_2 2
+
+
enum {
MSM_SPM_DEBUG_SHADOW = 1U << 0,
MSM_SPM_DEBUG_VCTL = 1U << 1,
@@ -31,35 +39,95 @@
debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
);
-#define MSM_SPM_PMIC_STATE_IDLE 0
+static uint32_t msm_spm_reg_offsets_v1[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_STS0] = 0x0C,
+ [MSM_SPM_REG_SAW2_STS1] = 0x10,
+ [MSM_SPM_REG_SAW2_VCTL] = 0x14,
+ [MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
+ [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
+ [MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
+ [MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
+ [MSM_SPM_REG_SAW2_RST] = 0x30,
+ [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+};
-static uint32_t msm_spm_reg_offsets[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_STS0] = 0x0C,
- [MSM_SPM_REG_SAW2_STS1] = 0x10,
-
- [MSM_SPM_REG_SAW2_VCTL] = 0x14,
-
- [MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
- [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
-
- [MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
- [MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
- [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
- [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
- [MSM_SPM_REG_SAW2_RST] = 0x30,
-
- [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+static uint32_t msm_spm_reg_offsets_v2[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,
};
/******************************************************************************
* Internal helper functions
*****************************************************************************/
+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)
+{
+ addr &= 0x7F;
+ addr <<= 4;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
+}
+
+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);
+
+ if (dev->major == SAW2_MAJOR_2)
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
+ else
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 18) & 0x1;
+}
+
static inline void msm_spm_drv_set_vctl(struct msm_spm_driver_data *dev,
uint32_t vlevel)
{
@@ -73,58 +141,81 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
}
-static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
+static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
+ uint32_t vlevel)
{
- __raw_writel(dev->reg_shadow[reg_index],
- dev->reg_base_addr + msm_spm_reg_offsets[reg_index]);
+ unsigned int pmic_data = 0;
+
+ 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_0] &= ~0x700FF;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
}
-static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
+static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
+ unsigned int vlevel)
{
- dev->reg_shadow[reg_index] =
- __raw_readl(dev->reg_base_addr +
- msm_spm_reg_offsets[reg_index]);
-}
-
-static inline uint32_t msm_spm_drv_get_awake_vlevel(
- struct msm_spm_driver_data *dev)
-{
- return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] & 0xFF;
+ if (dev->major == SAW2_MAJOR_2)
+ return msm_spm_drv_set_vctl2(dev, vlevel);
+ else
+ return msm_spm_drv_set_vctl(dev, vlevel);
}
static inline uint32_t msm_spm_drv_get_sts_pmic_state(
struct msm_spm_driver_data *dev)
{
- return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+ if (dev->major == SAW2_MAJOR_2) {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
+ 0x03;
+ } else {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+ }
}
static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
struct msm_spm_driver_data *dev)
{
- return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+ if (dev->major == SAW2_MAJOR_2) {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+ return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
+ } else {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
+ return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+ }
}
-static inline uint32_t msm_spm_drv_get_num_spm_entry(
- struct msm_spm_driver_data *dev)
+static inline uint32_t msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
+ uint32_t *major, uint32_t *minor)
{
- return 32;
-}
+ int ret = -ENODEV;
+ uint32_t val = 0;
-static inline void msm_spm_drv_set_start_addr(
- struct msm_spm_driver_data *dev, uint32_t addr)
-{
- addr &= 0x7F;
- addr <<= 4;
- dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
- dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
-}
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_VERSION);
+ val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
+ if (dev->ver_reg == SAW2_V2_VER_REG) {
+ *major = (val >> 28) & 0xF;
+ *minor = (val >> 16) & 0xFFF;
+ ret = 0;
+ } else if (dev->ver_reg == SAW2_V1_VER_REG) {
+ *major = (val >> 4) & 0xF;
+ *minor = val & 0xF;
+ ret = 0;
+ }
+
+ return ret;
+}
/******************************************************************************
* Public functions
*****************************************************************************/
+
inline int msm_spm_drv_set_spm_enable(
struct msm_spm_driver_data *dev, bool enable)
{
@@ -156,48 +247,42 @@
for (i = 0; i < num_spm_entry; i++) {
__raw_writel(dev->reg_seq_entry_shadow[i],
dev->reg_base_addr
- + msm_spm_reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+ + dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+ 4 * i);
}
mb();
}
int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
- uint8_t *cmd, uint32_t offset)
+ uint8_t *cmd, uint32_t *offset)
{
- uint32_t offset_w = offset / 4;
- int ret = 0;
+ uint32_t cmd_w;
+ uint32_t offset_w = *offset / 4;
+ uint8_t last_cmd;
- if (!cmd || !dev) {
- __WARN();
- goto failed_write_seq_data;
- };
+ if (!cmd)
+ return -EINVAL;
while (1) {
int i;
- uint32_t cmd_w = 0;
- uint8_t last_cmd = 0;
+ cmd_w = 0;
+ last_cmd = 0;
+ cmd_w = dev->reg_seq_entry_shadow[offset_w];
- for (i = 0; i < 4; i++) {
- last_cmd = (last_cmd == 0x0f) ? 0x0f : *(cmd + i);
- cmd_w |= last_cmd << (i * 8);
- ret++;
+ for (i = (*offset % 4) ; i < 4; i++) {
+ last_cmd = *(cmd++);
+ cmd_w |= last_cmd << (i * 8);
+ (*offset)++;
+ if (last_cmd == 0x0f)
+ break;
}
- if (offset_w >= msm_spm_drv_get_num_spm_entry(dev)) {
- __WARN();
- goto failed_write_seq_data;
- }
-
- cmd += i;
dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
if (last_cmd == 0x0f)
break;
}
- return ret;
-failed_write_seq_data:
- return -EINVAL;
+ return 0;
}
int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
@@ -218,7 +303,7 @@
int i;
for (i = 0; i < MSM_SPM_REG_NR; i++)
pr_info("%s: reg %02x = 0x%08x\n", __func__,
- msm_spm_reg_offsets[i], dev->reg_shadow[i]);
+ dev->reg_offsets[i], dev->reg_shadow[i]);
}
return 0;
@@ -231,11 +316,14 @@
if (!dev)
return -EINVAL;
+ if (!msm_spm_pmic_arb_present(dev))
+ return -ENOSYS;
+
if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
pr_info("%s: requesting vlevel 0x%x\n",
__func__, vlevel);
- msm_spm_drv_set_vctl(dev, vlevel);
+ msm_spm_drv_apcs_set_vctl(dev, vlevel);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
@@ -243,7 +331,6 @@
/* Wait for PMIC state to return to idle or until timeout */
timeout_us = dev->vctl_timeout_us;
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
if (!timeout_us)
goto set_vdd_bail;
@@ -255,11 +342,8 @@
udelay(timeout_us);
timeout_us = 0;
}
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
}
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
-
if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
goto set_vdd_bail;
@@ -275,6 +359,54 @@
return -EIO;
}
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+ unsigned int phase_cnt)
+{
+ unsigned int pmic_data = 0;
+ unsigned int timeout_us = 0;
+
+ if (dev->major != SAW2_MAJOR_2)
+ return -ENODEV;
+
+ pmic_data |= phase_cnt & 0xFF;
+ pmic_data |= (dev->phase_port & 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();
+
+ /* Wait for PMIC state to return to idle or until timeout */
+ timeout_us = dev->vctl_timeout_us;
+ while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
+ if (!timeout_us)
+ goto set_phase_bail;
+
+ if (timeout_us > 10) {
+ udelay(10);
+ timeout_us -= 10;
+ } else {
+ udelay(timeout_us);
+ timeout_us = 0;
+ }
+ }
+
+ if (msm_spm_drv_get_sts_curr_pmic_data(dev) != phase_cnt)
+ goto set_phase_bail;
+
+ if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+ pr_info("%s: done, remaining timeout %uus\n",
+ __func__, timeout_us);
+
+ return 0;
+
+set_phase_bail:
+ pr_err("%s: failed, remaining timeout %uus, phase count %d\n",
+ __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+ return -EIO;
+
+}
+
void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
{
int i;
@@ -289,12 +421,18 @@
int __init msm_spm_drv_init(struct msm_spm_driver_data *dev,
struct msm_spm_platform_data *data)
{
-
int i;
int num_spm_entry;
BUG_ON(!dev || !data);
+ if (dev->ver_reg == SAW2_V2_VER_REG)
+ dev->reg_offsets = msm_spm_reg_offsets_v2;
+ else
+ dev->reg_offsets = msm_spm_reg_offsets_v1;
+
+ dev->vctl_port = data->vctl_port;
+ dev->phase_port = data->phase_port;
dev->reg_base_addr = data->reg_base_addr;
memcpy(dev->reg_shadow, data->reg_init_values,
sizeof(data->reg_init_values));
@@ -314,18 +452,16 @@
/* barrier to ensure read completes before we proceed further*/
mb();
+ msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
+
num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
dev->reg_seq_entry_shadow =
- kmalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
+ kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
GFP_KERNEL);
if (!dev->reg_seq_entry_shadow)
return -ENOMEM;
-
- memset(dev->reg_seq_entry_shadow, 0x0f,
- num_spm_entry * sizeof(*dev->reg_seq_entry_shadow));
-
return 0;
}
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 21c7dca..154303b 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -70,19 +70,33 @@
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_VCTL,
- MSM_SPM_REG_SAW2_SEQ_ENTRY ,
+ 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
+ MSM_SPM_REG_NR,
};
struct msm_spm_seq_entry {
@@ -95,8 +109,13 @@
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;
+
uint8_t awake_vlevel;
uint32_t vctl_timeout_us;
+ uint32_t avs_timeout_us;
uint32_t num_modes;
struct msm_spm_seq_entry *modes;
@@ -105,18 +124,93 @@
#if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
+/* Public functions */
+
+/**
+ * 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);
+
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ */
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
-void msm_spm_reinit(void);
-void msm_spm_allow_x_cpu_set_vdd(bool allowed);
-int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
+ * @cpu: core id
+ */
int msm_spm_turn_on_cpu_rail(unsigned int cpu);
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_allow_x_cpu_set_vdd(): Turn on/off cross calling to set voltage
+ * @allowed: boolean to indicate on/off.
+ */
+void msm_spm_allow_x_cpu_set_vdd(bool allowed);
+
+/**
+ * msm_spm_reinit(): Reinitialize SPM registers
+ */
+void msm_spm_reinit(void);
+
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
+int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * msm_spm_device_init(): Device tree initialization function
+ */
+int msm_spm_device_init(void);
+
#if defined(CONFIG_MSM_L2_SPM)
+
+/* Public functions */
+
+/**
+ * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
+ * for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
+
+/**
+ * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
+ * @vlevel: Encoded PMIC data.
+ */
+int msm_spm_apcs_set_vdd(unsigned int vlevel);
+
+/**
+ * msm_spm_apcs_set_phase(): Set number of SMPS phases.
+ * phase_cnt: Number of phases to be set active
+ */
+int msm_spm_apcs_set_phase(unsigned int phase_cnt);
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_l2_init(): Board initialization function
+ * @data: SPM target specific register configuration
+ */
int msm_spm_l2_init(struct msm_spm_platform_data *data);
+
+/**
+ * msm_spm_l2_reinit(): Reinitialize L2 SPM registers
+ */
void msm_spm_l2_reinit(void);
+
#else
+
static inline int msm_spm_l2_set_low_power_mode(unsigned int mode,
bool notify_rpm)
{
@@ -130,10 +224,18 @@
{
/* empty */
}
+
+static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+ return -ENOSYS;
+}
+
+static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+ return -ENOSYS;
+}
#endif /* defined(CONFIG_MSM_L2_SPM) */
-
#else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
-
static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
{
return -ENOSYS;
@@ -158,6 +260,11 @@
{
return -ENOSYS;
}
-#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
+static inline int msm_spm_device_init(void)
+{
+ return -ENOSYS;
+}
+
+#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
#endif /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2b17fa3..838ec55 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -17,6 +17,9 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include "spm.h"
@@ -35,6 +38,7 @@
uint32_t num_modes;
};
+static struct msm_spm_device msm_spm_l2_device;
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
static atomic_t msm_spm_set_vdd_x_cpu_allowed = ATOMIC_INIT(1);
@@ -42,6 +46,7 @@
{
atomic_set(&msm_spm_set_vdd_x_cpu_allowed, allowed ? 1 : 0);
}
+EXPORT_SYMBOL(msm_spm_allow_x_cpu_set_vdd);
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
{
@@ -62,6 +67,7 @@
local_irq_restore(flags);
return ret;
}
+EXPORT_SYMBOL(msm_spm_set_vdd);
static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
unsigned int mode, bool notify_rpm)
@@ -100,6 +106,7 @@
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)
@@ -107,15 +114,17 @@
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);
+ 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;
- dev->modes[i].start_addr = offset;
- offset += ret;
}
msm_spm_drv_flush_seq_entry(&dev->reg_data);
return 0;
@@ -126,39 +135,6 @@
return ret;
}
-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));
-}
-
-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);
-}
-
-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;
-}
-
int msm_spm_turn_on_cpu_rail(unsigned int cpu)
{
uint32_t val = 0;
@@ -192,22 +168,227 @@
}
EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
-#if defined(CONFIG_MSM_L2_SPM)
-static struct msm_spm_device msm_spm_l2_device;
+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);
+
+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);
+
+/* Board file init function */
+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;
+}
+
+#ifdef CONFIG_MSM_L2_SPM
int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
{
return msm_spm_dev_set_low_power_mode(
&msm_spm_l2_device, mode, notify_rpm);
}
-
-int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
-{
- return msm_spm_dev_init(&msm_spm_l2_device, data);
-}
+EXPORT_SYMBOL(msm_spm_l2_set_low_power_mode);
void msm_spm_l2_reinit(void)
{
msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
}
+EXPORT_SYMBOL(msm_spm_l2_reinit);
+
+int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+ return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
+
+int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+ return msm_spm_drv_set_phase(&msm_spm_l2_device.reg_data, phase_cnt);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_phase);
+
+/* Board file init function */
+int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
+{
+ return msm_spm_dev_init(&msm_spm_l2_device, data);
+}
#endif
+
+static int __devinit 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];
+ size_t 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-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
+ {"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
+ {"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+ {"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+ {"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,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+ {"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+ {"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+ {"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+ };
+
+ BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+ memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+ memset(&modes, 0,
+ (MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto fail;
+
+ spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!spm_data.reg_base_addr)
+ return -ENOMEM;
+
+ key = "qcom,core-id";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ cpu = val;
+
+ 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;
+
+ /* optional */
+ key = "qcom,vctl-port";
+ ret = of_property_read_u32(node, key, &val);
+ if (!ret)
+ spm_data.vctl_port = val;
+
+ /* optional */
+ key = "qcom,phase-port";
+ ret = of_property_read_u32(node, key, &val);
+ if (!ret)
+ spm_data.phase_port = val;
+
+ 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;
+ mode_count++;
+ }
+
+ spm_data.modes = modes;
+ spm_data.num_modes = mode_count;
+
+ /*
+ * Device with id 0..NR_CPUS are SPM for apps cores
+ * Device with id 0xFFFF is for L2 SPM.
+ */
+ if (cpu >= 0 && cpu < num_possible_cpus())
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+ else
+ dev = &msm_spm_l2_device;
+
+ ret = msm_spm_dev_init(dev, &spm_data);
+ if (ret < 0)
+ pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
+
+ return ret;
+
+fail:
+ pr_err("%s: Failed reading node=%s, key=%s\n",
+ __func__, node->full_name, key);
+ return -EFAULT;
+}
+
+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,
+ .driver = {
+ .name = "spm-v2",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_spm_match_table,
+ },
+};
+
+int __init msm_spm_device_init(void)
+{
+ return platform_driver_register(&msm_spm_device_driver);
+}
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index 712f051..f272adb 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -15,10 +15,17 @@
#include "spm.h"
struct msm_spm_driver_data {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t ver_reg;
+ uint32_t vctl_port;
+ uint32_t phase_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,
@@ -29,9 +36,10 @@
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
unsigned int vlevel);
int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
- uint8_t *cmd, uint32_t offset);
+ 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_phase(struct msm_spm_driver_data *dev,
+ unsigned int phase_cnt);
#endif
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index b18de02..e754fe3 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -134,6 +134,7 @@
static int msm_ext_top_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
+static int msm_hdmi_rx_ch = 2;
static struct clk *codec_clk;
static int clk_users;
@@ -515,11 +516,15 @@
static const char *spk_function[] = {"Off", "On"};
static const char *slim0_rx_ch_text[] = {"One", "Two"};
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six"};
+
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(5, hdmi_rx_ch_text),
+
};
static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
@@ -560,6 +565,26 @@
return 1;
}
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ return 1;
+}
+
+
static const struct snd_kcontrol_new tabla_msm_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
msm_set_spk),
@@ -567,6 +592,9 @@
msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+
};
static void *def_tabla_mbhc_cal(void)
@@ -861,6 +889,7 @@
channels->min, channels->max);
rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_hdmi_rx_ch;
return 0;
}