Merge "ASoC: msm: Add FE DAI for QCHAT"
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 195a98d..f57d928 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -3,10 +3,8 @@
The application processor in MSM can do a variety of C-States for low power
management. These C-States are invoked by the CPUIdle framework when the core
becomes idle. But based on the time available until the next scheduled wakeup,
-the system can do a combination of low power modes of different resources -
-L2, XO, Vdd Dig and Vdd Mem. The combination is captured in the device tree as
-lpm-level. The units for voltage are dependent on the PMIC used on the target
-and are in uV.
+the system can do several low power modes. The combination is captured in the
+device tree as lpm-level.
The required nodes for lpm-levels are:
@@ -20,20 +18,11 @@
"retention" - Retention
"pc_suspend" - Suspended Power Collapse
"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
-- qcom,xo: The state of XO clock. Values are "xo_on" and "xo_off"
- qcom,l2: The state of L2 cache. Values are:
"l2_cache_pc" - L2 cache in power collapse
"l2_cache_retenetion" - L2 cache in retention
"l2_cache_gdhs" - L2 cache in GDHS
"l2_cache_active" - L2 cache in active mode
-- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
-- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
-- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
- or an RBCPR (Rapid Bridge Core Power Reduction)
- corner voltage.
-- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
- or an RBCPR (Rapid Bridge Core Power Reduction)
- corner voltage.
- qcom,latency-us: The latency in handling the interrupt if this level was
chosen, in uSec
- qcom,ss-power: The steady state power expelled when the processor is in this
@@ -42,29 +31,18 @@
in mWatts.uSec
- qcom,time-overhead: The time spent in entering and exiting this level in uS
-Optional properties
-- qcom,irqs-detectable: The field indicates whether the IRQs are detectable by
- the GIC controller when entering a low power mode.
-- qcom,gpio-detectable: The field indicates whether the GPIOs can be detected
- by the GPIO interrupt controller during a given low
- power mode.
-- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
+The optional nodes for lpm-levels are :
+- qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
+- qcom,default-l2-state: Indicates what the default low power state of the L2 SAW should be. This property is used only when there is an L2 SAW.
Example:
qcom,lpm-levels {
- qcom,use-qtimer;
+ qcom,no-l2-saw;
qcom,lpm-level@0 {
reg = <0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <100>;
qcom,ss-power = <650>;
qcom,energy-overhead = <801>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
deleted file mode 100644
index 7b5fda3..0000000
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-* Low Power Management Resources
-
-The application processor in the MSM can enter several different low power
-states depending on the sleep time and on the required system resources. The
-MSM cannot enter a given low power state if that state involves turning off
-some shared resources which are required by some components of the
-system.The lpm-resources device tree node represents the shared resources
-that need to be monitored for usage requirement to check if a given low power
-state can be entered.Each resource is identified by a combination of the name,
-id,type and key which is also used by the RPM to identify a shared resource.
-The name and resource-type are required nodes; the type, id and key are
-optional nodes which are needed if the resource type is RPM shared resource
-(MSM_LPM_RPM_RS_TYPE).
-
-The nodes for lpm-resources are:
-
-Required Nodes:
-
-- compatible: "qcom,lpm-resources"
-- reg: The numeric level id
-- qcom,name: The name of the low power resource represented
- as a string.
-- qcom,init-value: Initialization value of the LPM resource represented as
- decimal value for vdd-dig and vdd-mem resources and
- as string for pxo and l2 resources.
-
-
-Optional Nodes:
-
-- qcom,type: The type of resource used like smps or pxo
- represented as a hex value.
-- qcom,id: The id representing a device within a resource type.
-- qcom,key: The key is the specific attribute of the resource being
- monitored represented as a hex value.
-- qcom,local-resource-type: The property exists only for locally managed
- resource and is represented as a bool.
-
-Example:
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value= <5>; /* Active Corner*/
- };
-
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index d24e671..7f7ee25 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -118,6 +118,12 @@
- qcom,setb-gpios-pull : active pull configuration for set B gpios
- qcom,setb-gpios-dir : active direction for set B gpios
- qcom,hwevent-clks : list of clocks required by hardware event driver
+- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
+ the device. Only relevant in case of tmc-etr device.
+- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
+ spi/ppi, b is the interrupt number and c is the mask,
+- interrupt-names : a list of strings that map in order to the list of
+ interrupts specified in the 'interrupts' property.
Examples:
@@ -128,6 +134,11 @@
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ qcom,byte-cntr-absent;
+
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 0f35e73..3720172 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -20,6 +20,7 @@
- synaptics,panel-x : panel x dimension
- synaptics,panel-y : panel y dimension
- synaptics,fw-image-name : name of firmware .img file in /etc/firmware
+ - synaptics,power-down : fully power down regulators in suspend
Example:
i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 7acb1fe..d94b41d 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -35,6 +35,7 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
};
@@ -75,7 +76,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 11f6369..cbfdfc9 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index ddb61bc..825e853 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -35,6 +35,7 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
};
@@ -86,7 +87,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 0fc6af4..ef0a55e 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -101,62 +101,16 @@
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x61706d73>; /* "smpa" */
- qcom,id = <0x01>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x03>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_active";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_active";
#address-cells = <1>;
#size-cells = <0>;
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <3000>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <8000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <9000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <9500>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <16300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <24200>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <24000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <33000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <26000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <38000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 9bf37af..55d8691 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -31,6 +31,7 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
+ synaptics,power-down;
};
focaltech@38 {
compatible = "focaltech,5x06";
@@ -98,7 +99,7 @@
compatible = "micrel,ks8851";
reg = <3>;
interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
+ interrupts = <115 0x8>;
spi-max-frequency = <4800000>;
rst-gpio = <&msmgpio 114 0>;
vdd-io-supply = <&pm8226_lvs1>;
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index c531740..d31a65c 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -101,62 +101,16 @@
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x61706d73>; /* "smpa" */
- qcom,id = <0x01>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x03>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* SVS SOC */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_active";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_active";
#address-cells = <1>;
#size-cells = <0>;
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -166,14 +120,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <3000>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -183,15 +130,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <8000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <9200>;
@@ -200,64 +140,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <9000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <9500>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <16300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <24200>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <24000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <33000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <26000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <38000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
index 220f642..aeaf8ca 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
@@ -40,3 +40,8 @@
qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
};
};
+
+&pm8110_bms {
+ status = "ok";
+ qcom,batt-type = <5>;
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index e41adac..9fd0cd9 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 288a703..7362b64 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -129,64 +129,16 @@
50 02 32 50 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <6>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -196,14 +148,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "retention";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <75>;
qcom,ss-power = <735>;
qcom,energy-overhead = <77341>;
@@ -214,14 +159,7 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <95>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -231,15 +169,8 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <2000>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
qcom,time-overhead = <3200>;
@@ -248,79 +179,12 @@
qcom,lpm-level@4 {
reg = <0x4>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <3000>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
qcom,time-overhead = <3500>;
};
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <3000>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <1350200>;
- qcom,time-overhead = <4000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <10300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <18200>;
- };
-
- qcom,lpm-level@7 {
- reg = <0x7>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
- };
-
- qcom,lpm-level@8 {
- reg = <0x8>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <20000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <32000>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index cfacac6..7b801da 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -65,6 +65,7 @@
/* CoreSight */
&tmc_etr {
qcom,reset-flush-race;
+ qcom,byte-cntr-absent;
};
&stm {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 03f7e80..5efa17d 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -42,14 +42,14 @@
0x2034
0x2038>;
- qcom,iommu-bfb-data = <0xFFFFFFFF
- 0xFFFFFFFF
- 0x00000004
- 0x00000008
- 0x00000000
- 0x00013205
- 0x00004000
- 0x00014020
+ qcom,iommu-bfb-data = <0xffffffff
+ 0xffffffff
+ 0x4
+ 0x8
+ 0x0
+ 0x13205
+ 0x4000
+ 0x14020
0x0
0x94
0x114
@@ -116,8 +116,8 @@
0x2010
0x2014>;
- qcom,iommu-bfb-data = <0x3FFF
- 0x00000000
+ qcom,iommu-bfb-data = <0xffff
+ 0x0
0x4
0x4
0x0
@@ -125,8 +125,8 @@
0x10
0x50
0x0
- 0x00002804
- 0x00009614
+ 0x2804
+ 0x9614
0x0
0x0
0x0
@@ -157,14 +157,14 @@
0x201c
0x2020>;
- qcom,iommu-bfb-data = <0xFFFFF
- 0x00000000
- 0x00000004
- 0x00000010
- 0x00000000
- 0x00006800
- 0x00006221
- 0x00016231
+ qcom,iommu-bfb-data = <0xffffffff
+ 0x0
+ 0x4
+ 0x10
+ 0x0
+ 0x6800
+ 0x6221
+ 0x16231
0x0
0x34
0x74
@@ -197,14 +197,14 @@
0x2414
0x2008>;
- qcom,iommu-bfb-data = <0x00000003
+ qcom,iommu-bfb-data = <0x3
0x0
- 0x00000004
- 0x00000010
- 0x00000000
- 0x00000000
- 0x00000000
- 0x00000020
+ 0x4
+ 0x10
+ 0x0
+ 0x0
+ 0x0
+ 0x20
0x0
0x1
0x81
@@ -236,7 +236,7 @@
0x2020>;
qcom,iommu-bfb-data = <0xffffffff
- 0x00000000
+ 0x0
0x4
0x8
0x0
@@ -244,8 +244,8 @@
0x20
0x78
0x0
- 0x00003c08
- 0x0000b41e
+ 0x3c08
+ 0xb41e
0x0
0x0
0x0
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index a162bb7..1235c6e 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -125,64 +125,16 @@
50 02 32 50 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <6>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,local-resource-type;
- qcom,init-value = "l2_cache_retention";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <1>;
qcom,ss-power = <715>;
qcom,energy-overhead = <17700>;
@@ -192,14 +144,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "retention";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <35>;
qcom,ss-power = <542>;
qcom,energy-overhead = <34920>;
@@ -210,14 +155,7 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
- qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
+ qcom,l2 = "l2_cache_retention";
qcom,latency-us = <300>;
qcom,ss-power = <476>;
qcom,energy-overhead = <225300>;
@@ -227,32 +165,19 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <300>;
+ qcom,latency-us = <320>;
qcom,ss-power = <476>;
qcom,energy-overhead = <225300>;
- qcom,time-overhead = <350>;
+ qcom,time-overhead = <375>;
};
qcom,lpm-level@4 {
reg = <0x4>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <2817>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <163>;
qcom,energy-overhead = <1577736>;
qcom,time-overhead = <5067>;
@@ -261,64 +186,12 @@
qcom,lpm-level@5 {
reg = <0x5>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <3922>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <83>;
qcom,energy-overhead = <2274420>;
qcom,time-overhead = <6605>;
};
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <4922>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <2568180>;
- qcom,time-overhead = <8812>;
- };
-
- qcom,lpm-level@7 {
- reg = <0x7>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <5890>;
- qcom,ss-power = <60>;
- qcom,energy-overhead = <2675900>;
- qcom,time-overhead = <10140>;
- };
-
- qcom,lpm-level@8 {
- reg = <0x8>;
- qcom,mode= "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <8500>;
- qcom,ss-power = <18>;
- qcom,energy-overhead = <3286600>;
- qcom,time-overhead = <15760>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 60472c8..4a903b7 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index e18e143..7989f2b 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -28,57 +28,16 @@
3e 0f];
};
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x0A>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,type = <0x616F646C>; /* "ldoa" */
- qcom,id = <0x0C>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = "xo_on";
- };
- };
-
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
+ qcom,no-l2-saw;
#address-cells = <1>;
#size-cells = <0>;
- qcom,use-qtimer;
-
qcom,lpm-level@0 {
reg = <0x0>;
qcom,mode = "wfi";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <100>;
qcom,ss-power = <8000>;
qcom,energy-overhead = <100000>;
@@ -88,14 +47,7 @@
qcom,lpm-level@1 {
reg = <0x1>;
qcom,mode = "standalone_pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
qcom,latency-us = <2000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60100000>;
@@ -105,15 +57,8 @@
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <3500>;
+ qcom,latency-us = <20000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60350000>;
qcom,time-overhead = <6300>;
@@ -122,66 +67,12 @@
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
- qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,gpio-detectable;
- qcom,latency-us = <4500>;
+ qcom,latency-us = <30000>;
qcom,ss-power = <5000>;
qcom,energy-overhead = <60350000>;
qcom,time-overhead = <7300>;
};
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom,latency-us = <6800>;
- qcom,ss-power = <2000>;
- qcom,energy-overhead = <71850000>;
- qcom,time-overhead = <13300>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom,latency-us = <8000>;
- qcom,ss-power = <1800>;
- qcom,energy-overhead = <71950000>;
- qcom,time-overhead = <15300>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <9800>;
- qcom,ss-power = <0>;
- qcom,energy-overhead = <76350000>;
- qcom,time-overhead = <28300>;
- };
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index b238ba5..daf774b 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -48,6 +48,7 @@
/* CoreSight */
&tmc_etr {
qcom,reset-flush-race;
+ qcom,byte-cntr-absent;
};
&stm {
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 3549307..fef6543 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -52,6 +52,8 @@
CONFIG_MSM_RPM_REGULATOR_SMD=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_VENUS=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 7615eb2..f49b5f7 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -223,6 +223,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 7b2d38b..aced8f2 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -225,6 +225,7 @@
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
+CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
@@ -458,6 +459,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2a8bc91..cfd346e 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -422,6 +422,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_KEYS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8447dd55..0c28cc4 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -499,6 +499,7 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DYNAMIC_DEBUG=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 10e580b..b80949c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -282,7 +282,6 @@
select QMI_ENCDEC
select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_ULTRASOUND_B
- select MSM_LPM_TEST
select MSM_RPM_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
@@ -307,6 +306,10 @@
select MEMORY_HOLE_CARVEOUT
select DONT_MAP_HOLE_AFTER_MEMBANK0
select QMI_ENCDEC
+ select MSM_SPM_V2
+ select MSM_L2_SPM
+ select MSM_PM8X60 if PM
+ select MSM_RPM_SMD
config ARCH_MPQ8092
bool "MPQ8092"
@@ -430,6 +433,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MEMORY_HOLE_CARVEOUT
+ select QMI_ENCDEC
config ARCH_MSM8610
bool "MSM8610"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 56fb625..8c42b8d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -331,7 +331,7 @@
obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
-obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o lpm_resources.o
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 2a6bbb7..8f35a29 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -29,6 +29,8 @@
#include <mach/socinfo.h>
#include <mach/clk-provider.h>
#include <mach/msm_smem.h>
+#include <mach/rpm-smd.h>
+#include "spm.h"
#include "board-dt.h"
#include "clock.h"
#include "devices.h"
@@ -88,6 +90,8 @@
msm_smem_init();
msm_init_modem_notifier_list();
msm_smd_init();
+ msm_rpm_driver_init();
+ msm_spm_device_init();
msm_clock_init(&msm8084_clock_init_data);
tsens_tm_init_driver();
}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 0d62b7a..aff2d75 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -51,7 +51,6 @@
#include "platsmp.h"
#include "spm.h"
#include "pm.h"
-#include "lpm_resources.h"
#include "modem_notifier.h"
static struct memtype_reserve msm8226_reserve_table[] __initdata = {
@@ -116,7 +115,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_spm_device_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index f8ca143..01f1468 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -531,7 +531,8 @@
}
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
- msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
+ msm_gpiomux_install_nowrite(msm_lcd_configs,
+ ARRAY_SIZE(msm_lcd_configs));
msm_gpiomux_install(msm_keypad_configs,
ARRAY_SIZE(msm_keypad_configs));
msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index c6c9d14..d175bb4 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -52,7 +52,6 @@
#include "platsmp.h"
#include "spm.h"
#include "pm.h"
-#include "lpm_resources.h"
#include "modem_notifier.h"
static struct memtype_reserve msm8610_reserve_table[] __initdata = {
@@ -107,7 +106,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_spm_device_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 68af757..80a957f 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -45,8 +45,8 @@
#include "clock.h"
#include "devices.h"
#include "spm.h"
+#include "pm.h"
#include "modem_notifier.h"
-#include "lpm_resources.h"
#include "platsmp.h"
@@ -96,7 +96,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 36ad755..058789a 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -42,7 +42,6 @@
#include <mach/msm_smem.h>
#include "clock.h"
#include "modem_notifier.h"
-#include "lpm_resources.h"
#include "spm.h"
#define MSM_KERNEL_EBI_SIZE 0x51000
@@ -240,7 +239,6 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_rpm_driver_init();
- msm_lpmrs_module_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
msm_clock_init(&msm9625_clock_init_data);
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index be09b54..6133983 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -44,6 +44,8 @@
CLK_DUMMY("core_clk", USB_HS_SYSTEM_CLK, "msm_otg", OFF),
CLK_DUMMY("iface_clk", USB_HS_AHB_CLK, "msm_otg", OFF),
CLK_DUMMY("xo", CXO_OTG_CLK, "msm_otg", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
+ CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index f52bc28..97b8448 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/cpu.h>
+#include <linux/seq_file.h>
#include <linux/io.h>
#include <mach/msm-krait-l2-accessors.h>
#include <mach/msm_iomap.h>
@@ -159,25 +160,23 @@
return cesynr;
}
-static int proc_read_status(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int cache_erp_show(struct seq_file *m, void *v)
{
struct msm_l1_err_stats *l1_stats;
- char *p = page;
- int len, cpu, ret, bytes_left = PAGE_SIZE;
+ int cpu;
for_each_present_cpu(cpu) {
l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
- ret = snprintf(p, bytes_left,
- "CPU %d:\n" \
- "\tD-cache tag parity errors:\t%u\n" \
- "\tD-cache data parity errors:\t%u\n" \
- "\tI-cache tag parity errors:\t%u\n" \
- "\tI-cache data parity errors:\t%u\n" \
- "\tD-cache timing errors:\t\t%u\n" \
- "\tI-cache timing errors:\t\t%u\n" \
- "\tTLB multi-hit errors:\t\t%u\n\n", \
+ seq_printf(m,
+ "CPU %d:\n"
+ "\tD-cache tag parity errors:\t%u\n"
+ "\tD-cache data parity errors:\t%u\n"
+ "\tI-cache tag parity errors:\t%u\n"
+ "\tI-cache data parity errors:\t%u\n"
+ "\tD-cache timing errors:\t\t%u\n"
+ "\tI-cache timing errors:\t\t%u\n"
+ "\tTLB multi-hit errors:\t\t%u\n\n",
cpu,
l1_stats->dctpe,
l1_stats->dcdpe,
@@ -186,18 +185,16 @@
l1_stats->dcte,
l1_stats->icte,
l1_stats->tlbmh);
- p += ret;
- bytes_left -= ret;
}
- p += snprintf(p, bytes_left,
- "L2 master port decode errors:\t\t%u\n" \
- "L2 master port slave errors:\t\t%u\n" \
- "L2 tag soft errors, single-bit:\t\t%u\n" \
- "L2 tag soft errors, double-bit:\t\t%u\n" \
- "L2 data soft errors, single-bit:\t%u\n" \
- "L2 data soft errors, double-bit:\t%u\n" \
- "L2 modified soft errors:\t\t%u\n" \
+ seq_printf(m,
+ "L2 master port decode errors:\t\t%u\n"
+ "L2 master port slave errors:\t\t%u\n"
+ "L2 tag soft errors, single-bit:\t\t%u\n"
+ "L2 tag soft errors, double-bit:\t\t%u\n"
+ "L2 data soft errors, single-bit:\t%u\n"
+ "L2 data soft errors, double-bit:\t%u\n"
+ "L2 modified soft errors:\t\t%u\n"
"L2 master port LDREX NOK errors:\t%u\n",
msm_l2_erp_stats.mpdcd,
msm_l2_erp_stats.mpslv,
@@ -208,16 +205,21 @@
msm_l2_erp_stats.mse,
msm_l2_erp_stats.mplxrexnok);
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ return 0;
}
+static int cache_erp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cache_erp_show, NULL);
+}
+
+static const struct file_operations cache_erp_fops = {
+ .open = cache_erp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int msm_erp_dump_regions(void)
{
int i = 0;
@@ -235,26 +237,30 @@
}
#ifdef CONFIG_MSM_L1_ERR_LOG
-static int proc_read_log(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int cache_erp_log_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len, log_value;
+ int log_value;
+
log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
ERP_LOG_MAGIC ? 1 : 0;
- p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+ seq_printf(m, "%d\n", log_value);
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ return 0;
}
+static int cache_erp_log_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cache_erp_log_show, NULL);
+}
+
+static const struct file_operations cache_erp_log_fops = {
+ .open = cache_erp_log_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void log_cpu_event(void)
{
__raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
@@ -263,11 +269,10 @@
static int procfs_event_log_init(void)
{
- procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
-
+ procfs_log_entry = proc_create("cpu/msm_erp_log", S_IRUGO, NULL,
+ &cache_erp_log_fops);
if (!procfs_log_entry)
return -ENODEV;
- procfs_log_entry->read_proc = proc_read_log;
return 0;
}
@@ -561,7 +566,8 @@
goto fail_l1;
}
- procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+ procfs_entry = proc_create("cpu/msm_cache_erp", S_IRUGO, NULL,
+ &cache_erp_fops);
if (!procfs_entry) {
pr_err("Failed to create procfs node for cache error reporting\n");
@@ -580,8 +586,6 @@
smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
put_online_cpus();
- procfs_entry->read_proc = proc_read_status;
-
ret = procfs_event_log_init();
if (ret)
pr_err("Failed to create procfs node for ERP log access\n");
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
index b92c039..e76a6a9 100644
--- a/arch/arm/mach-msm/include/mach/mpm.h
+++ b/arch/arm/mach-msm/include/mach/mpm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -163,4 +163,23 @@
static inline void msm_mpm_exit_sleep(bool from_idle) {}
static inline void __init of_mpm_init(struct device_node *node) {}
#endif
+#ifdef CONFIG_MSM_MPM_OF
+/** msm_mpm_suspend_prepare() - Called at prepare_late() op during suspend
+ *
+ *
+ * When called the MPM driver checks if the wakeup interrupts can be monitored
+ * by MPM hardware and program them accordingly. If wake up interrupts cannot
+ * be monitored then it disallows system low power modes.
+ */
+void msm_mpm_suspend_prepare(void);
+/** msm_mpm_suspend_wake - Called during wake() op in suspend.
+ *
+ * When called MPM drivers sets the vote for system low power modes depending
+ * on the active interrupts.
+ */
+void msm_mpm_suspend_wake(void);
+#else
+static inline void msm_mpm_suspend_prepare(void){}
+static inline void msm_mpm_suspend_wake(void) {}
+#endif
#endif /* __ARCH_ARM_MACH_MSM_MPM_H */
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index aa33f2c..4d7c3d4 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -16,19 +16,60 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
#include <linux/of.h>
#include <mach/mpm.h>
-#include "lpm_resources.h"
#include "pm.h"
#include "rpm-notifier.h"
-
+#include "spm.h"
+#include "idle.h"
enum {
MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
};
-#define MAX_STR_LEN 30
+enum {
+ MSM_SCM_L2_ON = 0,
+ MSM_SCM_L2_OFF = 1,
+ MSM_SCM_L2_GDHS = 3,
+};
+
+struct msm_rpmrs_level {
+ enum msm_pm_sleep_mode sleep_mode;
+ uint32_t l2_cache;
+ bool available;
+ uint32_t latency_us;
+ uint32_t steady_state_power;
+ uint32_t energy_overhead;
+ uint32_t time_overhead_us;
+};
+
+struct lpm_lookup_table {
+ uint32_t modes;
+ const char *mode_name;
+};
+
+static void msm_lpm_level_update(void);
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+ unsigned long action, void *hcpu);
+
+static struct notifier_block __refdata msm_lpm_cpu_nblk = {
+ .notifier_call = msm_lpm_cpu_callback,
+};
+
+static uint32_t allowed_l2_mode;
+static uint32_t sysfs_dbg_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+static uint32_t default_l2_mode;
+
+static bool no_l2_saw;
+
+static ssize_t msm_lpm_levels_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count);
static int msm_lpm_lvl_dbg_msk;
@@ -39,9 +80,54 @@
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
-static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
-static DEFINE_PER_CPU(int , lpm_permitted_level);
-static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+static struct kobj_attribute lpm_l2_kattr = __ATTR(l2, S_IRUGO|S_IWUSR,\
+ msm_lpm_levels_attr_show, msm_lpm_levels_attr_store);
+
+static struct attribute *lpm_levels_attr[] = {
+ &lpm_l2_kattr.attr,
+ NULL,
+};
+
+static struct attribute_group lpm_levels_attr_grp = {
+ .attrs = lpm_levels_attr,
+};
+
+/* SYSFS */
+static ssize_t msm_lpm_levels_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct kernel_param kp;
+ int rc;
+
+ kp.arg = &sysfs_dbg_l2_mode;
+
+ rc = param_get_uint(buf, &kp);
+
+ if (rc > 0) {
+ strlcat(buf, "\n", PAGE_SIZE);
+ rc++;
+ }
+
+ return rc;
+}
+
+static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct kernel_param kp;
+ unsigned int temp;
+ int rc;
+
+ kp.arg = &temp;
+ rc = param_set_uint(buf, &kp);
+ if (rc)
+ return rc;
+
+ sysfs_dbg_l2_mode = temp;
+ msm_lpm_level_update();
+
+ return count;
+}
static int msm_pm_get_sleep_mode_value(struct device_node *node,
const char *key, uint32_t *sleep_mode_val)
@@ -74,8 +160,7 @@
if (!ret) {
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
- if (!strncmp(mode_name, pm_sm_lookup[i].mode_name,
- MAX_STR_LEN)) {
+ if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
*sleep_mode_val = pm_sm_lookup[i].modes;
ret = 0;
break;
@@ -85,16 +170,61 @@
return ret;
}
+static int msm_lpm_set_l2_mode(int sleep_mode)
+{
+ int lpm = sleep_mode;
+ int rc = 0;
+
+ if (no_l2_saw)
+ goto bail_set_l2_mode;
+
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
+
+ switch (sleep_mode) {
+ case MSM_SPM_L2_MODE_POWER_COLLAPSE:
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
+ break;
+ case MSM_SPM_L2_MODE_GDHS:
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
+ break;
+ case MSM_SPM_L2_MODE_RETENTION:
+ case MSM_SPM_L2_MODE_DISABLED:
+ break;
+ default:
+ lpm = MSM_SPM_L2_MODE_DISABLED;
+ break;
+ }
+
+ rc = msm_spm_l2_set_low_power_mode(lpm, true);
+
+ if (rc) {
+ if (rc == -ENXIO)
+ WARN_ON_ONCE(1);
+ else
+ pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
+ __func__, lpm, rc);
+ }
+
+bail_set_l2_mode:
+ return rc;
+}
+
static void msm_lpm_level_update(void)
{
- unsigned int lpm_level;
+ int lpm_level;
struct msm_rpmrs_level *level = NULL;
+ uint32_t max_l2_mode;
+ static DEFINE_MUTEX(lpm_lock);
+
+ mutex_lock(&lpm_lock);
+
+ max_l2_mode = min(allowed_l2_mode, sysfs_dbg_l2_mode);
for (lpm_level = 0; lpm_level < msm_lpm_level_count; lpm_level++) {
level = &msm_lpm_levels[lpm_level];
- level->available =
- !msm_lpm_level_beyond_limit(&level->rs_limits);
+ level->available = !(level->l2_cache > max_l2_mode);
}
+ mutex_unlock(&lpm_lock);
}
int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
@@ -102,13 +232,7 @@
{
int ret = 0;
int debug_mask;
- struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
- struct msm_lpm_sleep_data sleep_data;
-
- sleep_data.limits = limits;
- sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
- atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
- MSM_LPM_STATE_ENTER, &sleep_data);
+ uint32_t l2 = *(uint32_t *)limits;
if (from_idle)
debug_mask = msm_lpm_lvl_dbg_msk &
@@ -118,19 +242,20 @@
MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
if (debug_mask)
- pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
- __func__, l->pxo, l->l2_cache,
- l->vdd_mem_lower_bound,
- l->vdd_mem_upper_bound,
- l->vdd_dig_lower_bound,
- l->vdd_dig_upper_bound);
+ pr_info("%s(): l2:%d", __func__, l2);
- ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+ ret = msm_lpm_set_l2_mode(l2);
+
if (ret) {
- pr_warn("%s() LPM resources failed to enter sleep\n",
- __func__);
- goto bail;
+ if (ret == -ENXIO)
+ ret = 0;
+ else {
+ pr_warn("%s(): Failed to set L2 SPM Mode %d",
+ __func__, l2);
+ goto bail;
+ }
}
+
if (notify_rpm) {
ret = msm_rpm_enter_sleep(debug_mask);
if (ret) {
@@ -138,6 +263,8 @@
__func__, ret);
goto bail;
}
+
+ msm_mpm_enter_sleep(sclk_count, from_idle);
}
bail:
return ret;
@@ -147,12 +274,12 @@
bool notify_rpm, bool collapsed)
{
- msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
- from_idle, notify_rpm, collapsed);
- if (notify_rpm)
+ msm_lpm_set_l2_mode(default_l2_mode);
+
+ if (notify_rpm) {
+ msm_mpm_exit_sleep(from_idle);
msm_rpm_exit_sleep();
- atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
- MSM_LPM_STATE_EXIT, NULL);
+ }
}
void msm_lpm_show_resources(void)
@@ -161,48 +288,6 @@
return;
}
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
-{
- return limits->pxo;
-}
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
-{
- return limits->l2_cache;
-}
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- return limits->vdd_mem_upper_bound;
-}
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- return limits->vdd_dig_upper_bound;
-}
-
-static bool lpm_level_permitted(int cur_level_count)
-{
- if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
- return true;
- return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
-}
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
- struct notifier_block *nb, bool is_latency_measure)
-{
- per_cpu(lpm_permitted_level, cpu) = level_iter;
- return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
- cpu), nb);
-}
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
-{
- per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
- return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
- nb);
-}
-
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
@@ -225,17 +310,26 @@
}
return best->latency_us - 1;
}
-static bool msm_lpm_irqs_detectable(struct msm_rpmrs_limits *limits,
- bool irqs_detectable, bool gpio_detectable)
+
+static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+ unsigned long action, void *hcpu)
{
- if (!limits->irqs_detectable)
- return irqs_detectable;
-
- if (!limits->gpio_detectable)
- return gpio_detectable;
-
- return true;
-
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ allowed_l2_mode = default_l2_mode;
+ msm_lpm_level_update();
+ break;
+ case CPU_DEAD_FROZEN:
+ case CPU_DEAD:
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ if (num_online_cpus() == 1)
+ allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ msm_lpm_level_update();
+ break;
+ }
+ return NOTIFY_OK;
}
static void *msm_lpm_lowest_limits(bool from_idle,
@@ -244,24 +338,15 @@
{
unsigned int cpu = smp_processor_id();
struct msm_rpmrs_level *best_level = NULL;
+ uint32_t best_level_pwr = 0;
uint32_t pwr;
int i;
- int best_level_iter = msm_lpm_level_count + 1;
- bool irqs_detect = false;
- bool gpio_detect = false;
bool modify_event_timer;
uint32_t next_wakeup_us = time_param->sleep_us;
if (!msm_lpm_levels)
return NULL;
- msm_lpm_level_update();
-
- if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
- irqs_detect = msm_mpm_irqs_detectable(from_idle);
- gpio_detect = msm_mpm_gpio_irqs_detectable(from_idle);
- }
-
for (i = 0; i < msm_lpm_level_count; i++) {
struct msm_rpmrs_level *level = &msm_lpm_levels[i];
@@ -293,11 +378,6 @@
if (next_wakeup_us <= level->time_overhead_us)
continue;
- if ((sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) &&
- !msm_lpm_irqs_detectable(&level->rs_limits,
- irqs_detect, gpio_detect))
- continue;
-
if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
if (!cpu && msm_rpm_waiting_for_ack())
@@ -318,12 +398,10 @@
pwr += level->energy_overhead / next_wakeup_us;
}
- if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
+ if (!best_level || (best_level_pwr >= pwr)) {
- level->rs_limits.latency_us[cpu] = level->latency_us;
- level->rs_limits.power[cpu] = pwr;
best_level = level;
- best_level_iter = i;
+ best_level_pwr = pwr;
if (power)
*power = pwr;
if (modify_event_timer &&
@@ -336,32 +414,78 @@
time_param->modified_time_us = 0;
}
}
- if (best_level && !lpm_level_permitted(best_level_iter))
- best_level = NULL;
- else
- per_cpu(msm_lpm_sleep_time, cpu) =
- time_param->modified_time_us ?
- time_param->modified_time_us : time_param->sleep_us;
- return best_level ? &best_level->rs_limits : NULL;
+ return best_level ? &best_level->l2_cache : NULL;
}
-static struct lpm_test_platform_data lpm_test_pdata;
-
-static struct platform_device msm_lpm_test_device = {
- .name = "lpm_test",
- .id = -1,
- .dev = {
- .platform_data = &lpm_test_pdata,
- },
-};
-
static struct msm_pm_sleep_ops msm_lpm_ops = {
.lowest_limits = msm_lpm_lowest_limits,
.enter_sleep = msm_lpm_enter_sleep,
.exit_sleep = msm_lpm_exit_sleep,
};
+static int msm_lpm_get_l2_cache_value(struct device_node *node,
+ char *key, uint32_t *l2_val)
+{
+ int i;
+ struct lpm_lookup_table l2_mode_lookup[] = {
+ {MSM_SPM_L2_MODE_POWER_COLLAPSE, "l2_cache_pc"},
+ {MSM_SPM_L2_MODE_GDHS, "l2_cache_gdhs"},
+ {MSM_SPM_L2_MODE_RETENTION, "l2_cache_retention"},
+ {MSM_SPM_L2_MODE_DISABLED, "l2_cache_active"}
+ };
+ const char *l2_str;
+ int ret;
+
+ ret = of_property_read_string(node, key, &l2_str);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
+ if (!strcmp(l2_str, l2_mode_lookup[i].mode_name)) {
+ *l2_val = l2_mode_lookup[i].modes;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static int __devinit msm_lpm_levels_sysfs_add(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *low_power_kobj = NULL;
+ int rc = 0;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module %s\n",
+ __func__, KBUILD_MODNAME);
+ rc = -ENOENT;
+ goto resource_sysfs_add_exit;
+ }
+
+ low_power_kobj = kobject_create_and_add(
+ "enable_low_power", module_kobj);
+ if (!low_power_kobj) {
+ pr_err("%s: cannot create kobject\n", __func__);
+ rc = -ENOMEM;
+ goto resource_sysfs_add_exit;
+ }
+
+ rc = sysfs_create_group(low_power_kobj, &lpm_levels_attr_grp);
+resource_sysfs_add_exit:
+ if (rc) {
+ if (low_power_kobj) {
+ sysfs_remove_group(low_power_kobj,
+ &lpm_levels_attr_grp);
+ kobject_del(low_power_kobj);
+ }
+ }
+
+ return rc;
+}
+
static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
{
struct msm_rpmrs_level *levels = NULL;
@@ -372,7 +496,6 @@
int ret = 0;
uint32_t num_levels = 0;
int idx = 0;
- unsigned int m_cpu = 0;
for_each_child_of_node(pdev->dev.of_node, node)
num_levels++;
@@ -392,49 +515,11 @@
goto fail;
level->sleep_mode = val;
- key = "qcom,xo";
- ret = msm_lpm_get_xo_value(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.pxo = val;
-
key = "qcom,l2";
ret = msm_lpm_get_l2_cache_value(node, key, &val);
if (ret)
goto fail;
- level->rs_limits.l2_cache = val;
-
- key = "qcom,vdd-dig-upper-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_dig_upper_bound = val;
-
- key = "qcom,vdd-dig-lower-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_dig_lower_bound = val;
-
- key = "qcom,vdd-mem-upper-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_mem_upper_bound = val;
-
- key = "qcom,vdd-mem-lower-bound";
- ret = of_property_read_u32(node, key, &val);
- if (ret)
- goto fail;
- level->rs_limits.vdd_mem_lower_bound = val;
-
- key = "qcom,gpio-detectable";
- level->rs_limits.gpio_detectable =
- of_property_read_bool(node, key);
-
- key = "qcom,irqs-detectable";
- level->rs_limits.irqs_detectable =
- of_property_read_bool(node, key);
+ level->l2_cache = val;
key = "qcom,latency-us";
ret = of_property_read_u32(node, key, &val);
@@ -463,22 +548,33 @@
level->available = true;
}
+ node = pdev->dev.of_node;
+ key = "qcom,no-l2-saw";
+ no_l2_saw = of_property_read_bool(node, key);
+
msm_lpm_levels = levels;
msm_lpm_level_count = idx;
- lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
- lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
- key = "qcom,use-qtimer";
- lpm_test_pdata.use_qtimer =
- of_property_read_bool(pdev->dev.of_node, key);
+ if (num_online_cpus() == 1)
+ allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- for_each_possible_cpu(m_cpu)
- per_cpu(lpm_permitted_level, m_cpu) =
- msm_lpm_level_count + 1;
+ /* Do the following two steps only if L2 SAW is present */
+ if (!no_l2_saw) {
+ key = "qcom,default-l2-state";
+ if (msm_lpm_get_l2_cache_value(node, key, &default_l2_mode))
+ goto fail;
- platform_device_register(&msm_lpm_test_device);
+ if (msm_lpm_levels_sysfs_add())
+ goto fail;
+ register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+ msm_pm_set_l2_flush_flag(0);
+ } else {
+ msm_pm_set_l2_flush_flag(1);
+ default_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+ }
+
+ msm_lpm_level_update();
msm_pm_set_sleep_ops(&msm_lpm_ops);
-
return 0;
fail:
pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
deleted file mode 100644
index 1d9c539..0000000
--- a/arch/arm/mach-msm/lpm_resources.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/* Copyright (c) 2012-2013, 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/slab.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <mach/mpm.h>
-#include <mach/rpm-smd.h>
-#include <mach/trace_msm_low_power.h>
-#include "spm.h"
-#include "lpm_resources.h"
-#include "rpm-notifier.h"
-#include "idle.h"
-
-
-/*Debug Definitions*/
-enum {
- MSM_LPMRS_DEBUG_RPM = BIT(0),
- MSM_LPMRS_DEBUG_PXO = BIT(1),
- MSM_LPMRS_DEBUG_VDD_DIG = BIT(2),
- MSM_LPMRS_DEBUG_VDD_MEM = BIT(3),
- MSM_LPMRS_DEBUG_L2 = BIT(4),
- MSM_LPMRS_DEBUG_LVLS = BIT(5),
-};
-
-static int msm_lpm_debug_mask;
-module_param_named(
- debug_mask, msm_lpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-static bool msm_lpm_get_rpm_notif = true;
-
-/*Macros*/
-#define MAX_RS_NAME (16)
-#define MAX_RS_SIZE (4)
-#define IS_RPM_CTL(rs) \
- (!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
-#define MAX_STR_LEN 30
-
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_dig(int notify_rpm);
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
- char *key, uint32_t *default_value);
-
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_vdd_mem(int notify_rpm);
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
- char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_pxo(int notify_rpm);
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
- *rpm_notifier_cb);
-static int msm_lpm_init_value_pxo(struct device_node *node,
- char *key, uint32_t *default_value);
-
-
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
-static void msm_lpm_flush_l2(int notify_rpm);
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
-static int msm_lpm_init_value_l2(struct device_node *node,
- char *key, uint32_t *default_value);
-
-static void msm_lpm_flush_rpm_ctl(int notify_rpm);
-
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
- unsigned long action, void *rpm_notif);
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
- unsigned long action, void *hcpu);
-
-static ssize_t msm_lpm_resource_attr_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf);
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count);
-
-
-#define RPMRS_ATTR(_name) \
- __ATTR(_name, S_IRUGO|S_IWUSR, \
- msm_lpm_resource_attr_show, msm_lpm_resource_attr_store)
-
-/*Data structures*/
-struct msm_lpm_rs_data {
- uint32_t type;
- uint32_t id;
- uint32_t key;
- uint32_t value;
- uint32_t default_value;
- struct msm_rpm_request *handle;
-};
-
-enum {
- MSM_LPM_RPM_RS_TYPE = 0,
- MSM_LPM_LOCAL_RS_TYPE = 1,
-};
-
-enum {
- MSM_SCM_L2_ON = 0,
- MSM_SCM_L2_OFF = 1,
- MSM_SCM_L2_GDHS = 3,
-};
-
-struct msm_lpm_resource {
- struct msm_lpm_rs_data rs_data;
- uint32_t sleep_value;
- char name[MAX_RS_NAME];
-
- uint32_t enable_low_power;
- bool valid;
-
- bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
- void (*aggregate)(struct msm_rpmrs_limits *limits);
- void (*flush)(int notify_rpm);
- void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
- struct kobj_attribute ko_attr;
- int (*init_value)(struct device_node *node,
- char *key, uint32_t *default_value);
-};
-
-struct lpm_lookup_table {
- uint32_t modes;
- const char *mode_name;
-};
-
-static struct msm_lpm_resource msm_lpm_l2 = {
- .name = "l2",
- .beyond_limits = msm_lpm_beyond_limits_l2,
- .aggregate = msm_lpm_aggregate_l2,
- .flush = msm_lpm_flush_l2,
- .notify = NULL,
- .valid = false,
- .ko_attr = RPMRS_ATTR(l2),
- .init_value = msm_lpm_init_value_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_dig = {
- .name = "vdd-dig",
- .beyond_limits = msm_lpm_beyond_limits_vdd_dig,
- .aggregate = msm_lpm_aggregate_vdd_dig,
- .flush = msm_lpm_flush_vdd_dig,
- .notify = msm_lpm_notify_vdd_dig,
- .valid = false,
- .ko_attr = RPMRS_ATTR(vdd_dig),
- .init_value = msm_lpm_init_value_vdd_dig,
-};
-
-static struct msm_lpm_resource msm_lpm_vdd_mem = {
- .name = "vdd-mem",
- .beyond_limits = msm_lpm_beyond_limits_vdd_mem,
- .aggregate = msm_lpm_aggregate_vdd_mem,
- .flush = msm_lpm_flush_vdd_mem,
- .notify = msm_lpm_notify_vdd_mem,
- .valid = false,
- .ko_attr = RPMRS_ATTR(vdd_mem),
- .init_value = msm_lpm_init_value_vdd_mem,
-};
-
-static struct msm_lpm_resource msm_lpm_pxo = {
- .name = "pxo",
- .beyond_limits = msm_lpm_beyond_limits_pxo,
- .aggregate = msm_lpm_aggregate_pxo,
- .flush = msm_lpm_flush_pxo,
- .notify = msm_lpm_notify_pxo,
- .valid = false,
- .ko_attr = RPMRS_ATTR(pxo),
- .init_value = msm_lpm_init_value_pxo,
-};
-
-static struct msm_lpm_resource *msm_lpm_resources[] = {
- &msm_lpm_vdd_dig,
- &msm_lpm_vdd_mem,
- &msm_lpm_pxo,
- &msm_lpm_l2,
-};
-
-static struct msm_lpm_resource msm_lpm_rpm_ctl = {
- .name = "rpm_ctl",
- .beyond_limits = NULL,
- .aggregate = NULL,
- .flush = msm_lpm_flush_rpm_ctl,
- .valid = true,
- .ko_attr = RPMRS_ATTR(rpm_ctl),
-};
-
-static struct notifier_block msm_lpm_rpm_nblk = {
- .notifier_call = msm_lpm_rpm_callback,
-};
-
-static struct notifier_block __refdata msm_lpm_cpu_nblk = {
- .notifier_call = msm_lpm_cpu_callback,
-};
-
-static DEFINE_SPINLOCK(msm_lpm_sysfs_lock);
-
-/* Attribute Definitions */
-static struct attribute *msm_lpm_attributes[] = {
- &msm_lpm_vdd_dig.ko_attr.attr,
- &msm_lpm_vdd_mem.ko_attr.attr,
- &msm_lpm_pxo.ko_attr.attr,
- &msm_lpm_l2.ko_attr.attr,
- NULL,
-};
-
-static struct attribute_group msm_lpm_attribute_group = {
- .attrs = msm_lpm_attributes,
-};
-
-static struct attribute *msm_lpm_rpm_ctl_attribute[] = {
- &msm_lpm_rpm_ctl.ko_attr.attr,
- NULL,
-};
-
-static struct attribute_group msm_lpm_rpm_ctl_attr_group = {
- .attrs = msm_lpm_rpm_ctl_attribute,
-};
-
-#define GET_RS_FROM_ATTR(attr) \
- (container_of(attr, struct msm_lpm_resource, ko_attr))
-
-/* RPM */
-static struct msm_rpm_request *msm_lpm_create_rpm_request
- (uint32_t rsc_type, uint32_t rsc_id)
-{
- struct msm_rpm_request *handle = NULL;
-
- handle = msm_rpm_create_request(MSM_RPM_CTX_SLEEP_SET,
- rsc_type,
- rsc_id, 1);
- return handle;
-}
-
-static int msm_lpm_send_sleep_data(struct msm_rpm_request *handle,
- uint32_t key, uint8_t *value)
-{
- int ret = 0;
- int msg_id;
-
- if (!handle)
- return ret;
-
- ret = msm_rpm_add_kvp_data_noirq(handle, key, value, MAX_RS_SIZE);
-
- if (ret < 0) {
- pr_err("%s: Error adding kvp data key %u, size %d\n",
- __func__, key, MAX_RS_SIZE);
- return ret;
- }
-
- msg_id = msm_rpm_send_request_noirq(handle);
- if (!msg_id) {
- pr_err("%s: Error sending RPM request key %u, handle 0x%x\n",
- __func__, key, (unsigned int)handle);
- ret = -EIO;
- return ret;
- }
-
- ret = msm_rpm_wait_for_ack_noirq(msg_id);
- if (ret < 0) {
- pr_err("%s: Couldn't get ACK from RPM for Msg %d Error %d",
- __func__, msg_id, ret);
- return ret;
- }
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
- pr_info("Rs key %u, value %u, size %d\n", key,
- *(unsigned int *)value, MAX_RS_SIZE);
- return ret;
-}
-
-/* RPM Notifier */
-static int msm_lpm_rpm_callback(struct notifier_block *rpm_nb,
- unsigned long action,
- void *rpm_notif)
-{
- int i;
- struct msm_lpm_resource *rs = NULL;
- struct msm_rpm_notifier_data *rpm_notifier_cb =
- (struct msm_rpm_notifier_data *)rpm_notif;
-
- if (!msm_lpm_get_rpm_notif)
- return NOTIFY_DONE;
-
- if (!(rpm_nb && rpm_notif))
- return NOTIFY_BAD;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs && rs->valid && rs->notify)
- rs->notify(rpm_notifier_cb);
- }
-
- return NOTIFY_OK;
-}
-
-/* SYSFS */
-static ssize_t msm_lpm_resource_attr_show(
- struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-{
- struct kernel_param kp;
- unsigned long flags;
- unsigned int temp;
- int rc;
-
- spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
- temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
- spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
- kp.arg = &temp;
- rc = param_get_uint(buf, &kp);
-
- if (rc > 0) {
- strlcat(buf, "\n", PAGE_SIZE);
- rc++;
- }
-
- return rc;
-}
-
-static ssize_t msm_lpm_resource_attr_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count)
-{
- struct kernel_param kp;
- unsigned long flags;
- unsigned int temp;
- int rc;
-
- kp.arg = &temp;
- rc = param_set_uint(buf, &kp);
- if (rc)
- return rc;
-
- spin_lock_irqsave(&msm_lpm_sysfs_lock, flags);
- GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
-
- if (IS_RPM_CTL(GET_RS_FROM_ATTR(attr))) {
- struct msm_lpm_resource *rs = GET_RS_FROM_ATTR(attr);
- rs->flush(false);
- }
-
- spin_unlock_irqrestore(&msm_lpm_sysfs_lock, flags);
-
- return count;
-}
-
-/* lpm resource handling functions */
-/* Common */
-static void msm_lpm_notify_common(struct msm_rpm_notifier_data *cb,
- struct msm_lpm_resource *rs)
-{
- if ((cb->rsc_type == rs->rs_data.type) &&
- (cb->rsc_id == rs->rs_data.id) &&
- (cb->key == rs->rs_data.key)) {
-
- BUG_ON(cb->size > MAX_RS_SIZE);
-
- if (rs->valid) {
- if (cb->value) {
- memcpy(&rs->rs_data.value, cb->value, cb->size);
- msm_rpm_add_kvp_data_noirq(rs->rs_data.handle,
- cb->key, cb->value, cb->size);
- }
- else
- rs->rs_data.value = rs->rs_data.default_value;
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_RPM)
- pr_info("Notification received Rs %s value %u\n",
- rs->name, rs->rs_data.value);
- }
- }
-}
-
-/* L2 */
-static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits)
-{
- uint32_t l2;
- bool ret = false;
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- if (rs->valid) {
- uint32_t l2_buf = rs->rs_data.value;
-
- if (rs->enable_low_power == 1)
- l2 = MSM_LPM_L2_CACHE_GDHS;
- else if (rs->enable_low_power == 2)
- l2 = MSM_LPM_L2_CACHE_HSFS_OPEN;
- else
- l2 = MSM_LPM_L2_CACHE_ACTIVE ;
-
- if (l2_buf > l2)
- l2 = l2_buf;
- ret = (l2 > limits->l2_cache);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
- pr_info("%s: l2 buf %u, l2 %u, limits %u\n",
- __func__, l2_buf, l2, limits->l2_cache);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- if (rs->valid)
- rs->sleep_value = limits->l2_cache;
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_set_l2_mode(int sleep_mode)
-{
- int lpm, rc;
-
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
-
- switch (sleep_mode) {
- case MSM_LPM_L2_CACHE_HSFS_OPEN:
- lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
- break;
- case MSM_LPM_L2_CACHE_GDHS:
- lpm = MSM_SPM_L2_MODE_GDHS;
- msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
- break;
- case MSM_LPM_L2_CACHE_RETENTION:
- lpm = MSM_SPM_L2_MODE_RETENTION;
- break;
- default:
- case MSM_LPM_L2_CACHE_ACTIVE:
- lpm = MSM_SPM_L2_MODE_DISABLED;
- break;
- }
-
- rc = msm_spm_l2_set_low_power_mode(lpm, true);
-
- if (rc < 0)
- pr_err("%s: Failed to set L2 low power mode %d",
- __func__, lpm);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_L2)
- pr_info("%s: Requesting low power mode %d\n",
- __func__, lpm);
-}
-
-static int msm_lpm_init_value_l2(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return msm_lpm_get_l2_cache_value(node, key, default_value);
-}
-
-static void msm_lpm_flush_l2(int notify_rpm)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
-
- msm_lpm_set_l2_mode(rs->sleep_value);
-}
-
-int msm_lpm_get_l2_cache_value(struct device_node *node,
- char *key, uint32_t *l2_val)
-{
- int i;
- struct lpm_lookup_table l2_mode_lookup[] = {
- {MSM_LPM_L2_CACHE_HSFS_OPEN, "l2_cache_pc"},
- {MSM_LPM_L2_CACHE_GDHS, "l2_cache_gdhs"},
- {MSM_LPM_L2_CACHE_RETENTION, "l2_cache_retention"},
- {MSM_LPM_L2_CACHE_ACTIVE, "l2_cache_active"}
- };
- const char *l2_str;
- int ret;
-
- ret = of_property_read_string(node, key, &l2_str);
- if (!ret) {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
- if (!strncmp(l2_str, l2_mode_lookup[i].mode_name,
- MAX_STR_LEN)) {
- *l2_val = l2_mode_lookup[i].modes;
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-/* RPM CTL */
-static void msm_lpm_flush_rpm_ctl(int notify_rpm)
-{
- struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
-}
-
-/*VDD Dig*/
-static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- uint32_t vdd_dig = rs->enable_low_power ? rs->enable_low_power :
- rs->rs_data.default_value;
-
- if (vdd_buf > vdd_dig)
- vdd_dig = vdd_buf;
-
- ret = (vdd_dig > limits->vdd_dig_upper_bound);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_DIG)
- pr_info("%s:buf %d vdd dig %d limits%d\n",
- __func__, vdd_buf, vdd_dig,
- limits->vdd_dig_upper_bound);
- }
- return ret;
-}
-
-static int msm_lpm_init_value_vdd_dig(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return of_property_read_u32(node, key, default_value);
-}
-
-static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- if (limits->vdd_dig_lower_bound > vdd_buf)
- rs->sleep_value = limits->vdd_dig_lower_bound;
- else
- rs->sleep_value = vdd_buf;
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_dig(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-/*VDD Mem*/
-static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- uint32_t vdd_mem = rs->enable_low_power ? rs->enable_low_power :
- rs->rs_data.default_value;
-
- if (vdd_buf > vdd_mem)
- vdd_mem = vdd_buf;
-
- ret = (vdd_mem > limits->vdd_mem_upper_bound);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_VDD_MEM)
- pr_info("%s:buf %d vdd mem %d limits%d\n",
- __func__, vdd_buf, vdd_mem,
- limits->vdd_mem_upper_bound);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
-
- if (rs->valid) {
- uint32_t vdd_buf = rs->rs_data.value;
- if (limits->vdd_mem_lower_bound > vdd_buf)
- rs->sleep_value = limits->vdd_mem_lower_bound;
- else
- rs->sleep_value = vdd_buf;
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_vdd_mem(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_vdd_mem;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_vdd_mem(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return of_property_read_u32(node, key, default_value);
-}
-
-/*PXO*/
-static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
-{
- bool ret = true;
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
- if (rs->valid) {
- uint32_t pxo_buf = rs->rs_data.value;
- uint32_t pxo = rs->enable_low_power ? MSM_LPM_PXO_OFF :
- rs->rs_data.default_value;
-
- if (pxo_buf > pxo)
- pxo = pxo_buf;
-
- ret = (pxo > limits->pxo);
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
- pr_info("%s:pxo buf %d pxo %d limits pxo %d\n",
- __func__, pxo_buf, pxo, limits->pxo);
- }
- return ret;
-}
-
-static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits)
-{
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
-
- if (rs->valid) {
- uint32_t pxo_buf = rs->rs_data.value;
- if (limits->pxo > pxo_buf)
- rs->sleep_value = limits->pxo;
- else
- rs->sleep_value = pxo_buf;
-
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_PXO)
- pr_info("%s: pxo buf %d sleep value %d\n",
- __func__, pxo_buf, rs->sleep_value);
- }
- trace_lpm_resources(rs->sleep_value, rs->name);
-}
-
-static void msm_lpm_flush_pxo(int notify_rpm)
-{
- if (notify_rpm) {
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
- msm_lpm_send_sleep_data(rs->rs_data.handle,
- rs->rs_data.key,
- (uint8_t *)&rs->sleep_value);
- }
-}
-
-static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
- *rpm_notifier_cb)
-{
- struct msm_lpm_resource *rs = &msm_lpm_pxo;
- msm_lpm_notify_common(rpm_notifier_cb, rs);
-}
-
-static int msm_lpm_init_value_pxo(struct device_node *node,
- char *key, uint32_t *default_value)
-{
- return msm_lpm_get_xo_value(node, key, default_value);
-}
-
-static inline bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
-{
- return (limits->pxo == MSM_LPM_PXO_OFF);
-}
-
-int msm_lpm_get_xo_value(struct device_node *node,
- char *key, uint32_t *xo_val)
-{
- int i;
- struct lpm_lookup_table pxo_mode_lookup[] = {
- {MSM_LPM_PXO_OFF, "xo_off"},
- {MSM_LPM_PXO_ON, "xo_on"}
- };
- const char *xo_str;
- int ret;
-
- ret = of_property_read_string(node, key, &xo_str);
- if (!ret) {
- ret = -EINVAL;
- for (i = 0; i < ARRAY_SIZE(pxo_mode_lookup); i++) {
- if (!strncmp(xo_str, pxo_mode_lookup[i].mode_name,
- MAX_STR_LEN)) {
- *xo_val = pxo_mode_lookup[i].modes;
- ret = 0;
- break;
- }
- }
- }
- return ret;
-}
-
-/* LPM levels interface */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
- int i;
- struct msm_lpm_resource *rs;
- bool beyond_limit = false;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->beyond_limits && rs->beyond_limits(limits)) {
- beyond_limit = true;
- if (msm_lpm_debug_mask & MSM_LPMRS_DEBUG_LVLS)
- pr_info("%s: %s beyond limit", __func__,
- rs->name);
- break;
- }
- }
-
- return beyond_limit;
-}
-
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm)
-{
- int ret = 0;
- int i;
- struct msm_lpm_resource *rs = NULL;
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->aggregate)
- rs->aggregate(limits);
- }
-
- msm_lpm_get_rpm_notif = false;
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- rs = msm_lpm_resources[i];
- if (rs->valid && rs->flush)
- rs->flush(notify_rpm);
- }
- msm_lpm_get_rpm_notif = true;
-
- if (notify_rpm)
- msm_mpm_enter_sleep(sclk_count, from_idle);
-
- return ret;
-}
-
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed)
-{
- if (msm_lpm_use_mpm(limits))
- msm_mpm_exit_sleep(from_idle);
-
- if (msm_lpm_l2.valid)
- msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
-}
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
- unsigned long action, void *hcpu)
-{
- struct msm_lpm_resource *rs = &msm_lpm_l2;
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- rs->rs_data.value = rs->rs_data.default_value;
- break;
- case CPU_ONLINE_FROZEN:
- case CPU_ONLINE:
- if (num_online_cpus() > 1)
- rs->rs_data.value = rs->rs_data.default_value;
- break;
- case CPU_DEAD_FROZEN:
- case CPU_DEAD:
- if (num_online_cpus() == 1)
- rs->rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- break;
- }
- return NOTIFY_OK;
-}
-
-/* RPM CTL */
-static int __devinit msm_lpm_init_rpm_ctl(void)
-{
- struct msm_lpm_resource *rs = &msm_lpm_rpm_ctl;
-
- rs->rs_data.handle = msm_rpm_create_request(
- MSM_RPM_CTX_ACTIVE_SET,
- rs->rs_data.type,
- rs->rs_data.id, 1);
- if (!rs->rs_data.handle)
- return -EIO;
-
- rs->valid = true;
- return 0;
-}
-
-static int __devinit msm_lpm_resource_sysfs_add(void)
-{
- struct kobject *module_kobj = NULL;
- struct kobject *low_power_kobj = NULL;
- struct kobject *mode_kobj = NULL;
- int rc = 0;
-
- module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
- if (!module_kobj) {
- pr_err("%s: cannot find kobject for module %s\n",
- __func__, KBUILD_MODNAME);
- rc = -ENOENT;
- goto resource_sysfs_add_exit;
- }
-
- low_power_kobj = kobject_create_and_add(
- "enable_low_power", module_kobj);
- if (!low_power_kobj) {
- pr_err("%s: cannot create kobject\n", __func__);
- rc = -ENOMEM;
- goto resource_sysfs_add_exit;
- }
-
- mode_kobj = kobject_create_and_add(
- "mode", module_kobj);
- if (!mode_kobj) {
- pr_err("%s: cannot create kobject\n", __func__);
- rc = -ENOMEM;
- goto resource_sysfs_add_exit;
- }
-
- rc = sysfs_create_group(low_power_kobj, &msm_lpm_attribute_group);
- if (rc) {
- pr_err("%s: cannot create kobject attribute group\n", __func__);
- goto resource_sysfs_add_exit;
- }
-
- rc = sysfs_create_group(mode_kobj, &msm_lpm_rpm_ctl_attr_group);
- if (rc) {
- pr_err("%s: cannot create kobject attribute group\n", __func__);
- goto resource_sysfs_add_exit;
- }
-
-resource_sysfs_add_exit:
- if (rc) {
- if (low_power_kobj)
- sysfs_remove_group(low_power_kobj,
- &msm_lpm_attribute_group);
- kobject_del(low_power_kobj);
- kobject_del(mode_kobj);
- }
-
- return rc;
-}
-
-late_initcall(msm_lpm_resource_sysfs_add);
-
-static int __devinit msm_lpmrs_probe(struct platform_device *pdev)
-{
- struct device_node *node = NULL;
- char *key = NULL;
- int ret = 0;
-
- for_each_child_of_node(pdev->dev.of_node, node) {
- struct msm_lpm_resource *rs = NULL;
- const char *val;
- int i;
- bool local_resource;
-
- key = "qcom,name";
- ret = of_property_read_string(node, key, &val);
- if (ret) {
- pr_err("Cannot read string\n");
- goto fail;
- }
-
- for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
- char *lpmrs_name = msm_lpm_resources[i]->name;
- if (!msm_lpm_resources[i]->valid &&
- !strncmp(val, lpmrs_name, strnlen(lpmrs_name,
- MAX_RS_NAME))) {
- rs = msm_lpm_resources[i];
- break;
- }
- }
-
- if (!rs) {
- pr_err("LPM resource not found\n");
- continue;
- }
-
- key = "qcom,init-value";
- ret = rs->init_value(node, key, &rs->rs_data.default_value);
- if (ret) {
- pr_err("%s():Failed to read %s\n", __func__, key);
- goto fail;
- }
-
- rs->rs_data.value = rs->rs_data.default_value;
-
- key = "qcom,local-resource-type";
- local_resource = of_property_read_bool(node, key);
-
- if (!local_resource) {
- key = "qcom,type";
- ret = of_property_read_u32(node, key,
- &rs->rs_data.type);
- if (ret) {
- pr_err("Failed to read type\n");
- goto fail;
- }
-
- key = "qcom,id";
- ret = of_property_read_u32(node, key, &rs->rs_data.id);
- if (ret) {
- pr_err("Failed to read id\n");
- goto fail;
- }
-
- key = "qcom,key";
- ret = of_property_read_u32(node, key, &rs->rs_data.key);
- if (ret) {
- pr_err("Failed to read key\n");
- goto fail;
- }
-
- rs->rs_data.handle = msm_lpm_create_rpm_request(
- rs->rs_data.type,
- rs->rs_data.id);
-
- if (!rs->rs_data.handle) {
- pr_err("%s: Failed to allocate handle for %s\n",
- __func__, rs->name);
- ret = -1;
- goto fail;
- }
- /* fall through */
- }
-
- rs->valid = true;
- }
- msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
- msm_lpm_init_rpm_ctl();
-
- if (msm_lpm_l2.valid) {
- register_hotcpu_notifier(&msm_lpm_cpu_nblk);
- /* For UP mode, set the default to HSFS OPEN*/
- if (num_possible_cpus() == 1) {
- msm_lpm_l2.rs_data.default_value =
- MSM_LPM_L2_CACHE_HSFS_OPEN;
- msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- }
- msm_pm_set_l2_flush_flag(0);
- } else
- msm_pm_set_l2_flush_flag(1);
-
-fail:
- return ret;
-}
-
-static struct of_device_id msm_lpmrs_match_table[] = {
- {.compatible = "qcom,lpm-resources"},
- {},
-};
-
-static struct platform_driver msm_lpmrs_driver = {
- .probe = msm_lpmrs_probe,
- .driver = {
- .name = "lpm-resources",
- .owner = THIS_MODULE,
- .of_match_table = msm_lpmrs_match_table,
- },
-};
-
-int __init msm_lpmrs_module_init(void)
-{
- return platform_driver_register(&msm_lpmrs_driver);
-}
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
deleted file mode 100644
index 105cfe6..0000000
--- a/arch/arm/mach-msm/lpm_resources.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* Copyright (c) 2012-2013, 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_LPM_RESOURCES_H
-#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
-
-#include "pm.h"
-#include "test-lpm.h"
-
-enum {
- MSM_LPM_PXO_OFF,
- MSM_LPM_PXO_ON
-};
-
-enum {
- MSM_LPM_L2_CACHE_HSFS_OPEN,
- MSM_LPM_L2_CACHE_GDHS,
- MSM_LPM_L2_CACHE_RETENTION,
- MSM_LPM_L2_CACHE_ACTIVE,
-};
-
-struct msm_rpmrs_limits {
- uint32_t pxo;
- uint32_t l2_cache;
- uint32_t vdd_mem_upper_bound;
- uint32_t vdd_mem_lower_bound;
- uint32_t vdd_dig_upper_bound;
- uint32_t vdd_dig_lower_bound;
- bool irqs_detectable;
- bool gpio_detectable;
-
- uint32_t latency_us[NR_CPUS];
- uint32_t power[NR_CPUS];
-};
-
-struct msm_rpmrs_level {
- enum msm_pm_sleep_mode sleep_mode;
- struct msm_rpmrs_limits rs_limits;
- bool available;
- uint32_t latency_us;
- uint32_t steady_state_power;
- uint32_t energy_overhead;
- uint32_t time_overhead_us;
-};
-
-enum {
- MSM_LPM_STATE_ENTER = 0,
- MSM_LPM_STATE_EXIT = 1,
-};
-
-#define MSM_PM(field) MSM_LPM_##field
-
-/**
- * msm_pm_get_pxo() - get the limits for pxo
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource pxo on
- * 8974
- */
-
-uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_l2_cache() - get the limits for l2 cache
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource l2 cache
- * on 8974
- */
-
-uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_mem() - get the limits for pxo
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource vdd mem
- * on 8974
- */
-
-uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_pm_get_vdd_dig() - get the limits for vdd dig
- * @limits: pointer to the msm_rpmrs_limits structure
- *
- * This function gets the limits to the resource on 8974
- */
-
-uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpm_get_xo_value() - get the enum value for xo
- * @node pointer to the device node
- * @key pxo property key
- * @xo_val xo enum value
- */
-int msm_lpm_get_xo_value(struct device_node *node,
- char *key, uint32_t *xo_val);
-
-/**
- * msm_lpm_get_l2_cache_value() - get the enum value for l2 cache
- * @node pointer to the device node
- * @key l2 cache property key
- * @l2_val l2 mode enum value
- */
-int msm_lpm_get_l2_cache_value(struct device_node *node,
- char *key, uint32_t *l2_val);
-
-/**
- * struct msm_lpm_sleep_data - abstraction to get sleep data
- * @limits: pointer to the msm_rpmrs_limits structure
- * @kernel_sleep: kernel sleep time as decided by the power calculation
- * algorithm
- *
- * This structure is an abstraction to get the limits and kernel sleep time
- * during enter sleep.
- */
-
-struct msm_lpm_sleep_data {
- struct msm_rpmrs_limits *limits;
- uint32_t kernel_sleep;
-};
-
-/**
- * msm_lpm_register_notifier() - register for notifications
- * @cpu: cpu to debug
- * @level_iter: low power level index to debug
- * @nb: notifier block to callback on notifications
- * @is_latency_measure: is it latency measure
- *
- * This function sets the permitted level to the index of the
- * level under test and registers notifier for callback.
- */
-
-int msm_lpm_register_notifier(int cpu, int level_iter,
- struct notifier_block *nb, bool is_latency_measure);
-
-/**
- * msm_lpm_unregister_notifier() - unregister from notifications
- * @cpu: cpu to debug
- * @nb: notifier block to callback on notifications
- *
- * This function sets the permitted level to a value one more than
- * available levels count which indicates that all levels are
- * permitted and it also unregisters notifier for callback.
- */
-
-int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
-
-#ifdef CONFIG_MSM_RPM_SMD
-
-/**
- * msm_lpm_level_beyond_limit() - Check if the resources in a low power level
- * is beyond the limits of the driver votes received for those resources.This
- * function is used by lpm_levels to eliminate any low power level that cannot
- * be entered.
- *
- * @limits: pointer to the resource limits of a low power level.
- *
- * returns true if the resource limits are beyond driver resource votes.
- * false otherwise.
- */
-bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits);
-
-/**
- * msm_lpmrs_enter_sleep() - Enter sleep flushes the sleep votes of low power
- * resources to the RPM driver, also configure the MPM if needed depending
- * on the low power mode being entered. L2 low power mode is also set in
- * this function.
-
- * @sclk_count: wakeup counter for RPM.
- * @limits: pointer to the resource limits of the low power mode being entered.
- * @from_idle: bool to determine if this call being made as a part of
- * idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- *
- * returns 0 on success.
- */
-int msm_lpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm);
-
-/**
- * msm_lpmrs_exit_sleep() - Exit sleep, reset the MPM and L2 mode.
- * @ limits: pointer to resource limits of the most recent low power mode.
- * @from_idle: bool to determine if this call being made as a part of
- * idle power collapse.
- * @notify_rpm: bool that informs if this is an RPM notified power collapse.
- * @collapsed: bool that informs if the Krait was power collapsed.
- */
-void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed);
-/**
- * msm_lpmrs_module_init() - Init function that parses the device tree to
- * get the low power resource attributes and registers with RPM driver for
- * callback notification.
- *
- * returns 0 on success.
- */
-int __init msm_lpmrs_module_init(void);
-
-#else
-static inline bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
-{
- return true;
-}
-
-static inline int msm_lpmrs_enter_sleep(uint32_t sclk_count,
- struct msm_rpmrs_limits *limits, bool from_idle, bool notify_rpm)
-{
- return 0;
-}
-
-static inline void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
- bool from_idle, bool notify_rpm, bool collapsed)
-{
- return;
-}
-
-static inline int __init msm_lpmrs_module_init(void)
-{
- return 0;
-}
-#endif /* CONFIG_MSM_RPM_SMD */
-
-#endif
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index dbd5d67..a0746f9 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -27,10 +27,17 @@
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
#include <asm/hardware/gic.h>
#include <asm/arch_timer.h>
#include <mach/gpio.h>
#include <mach/mpm.h>
+#include <mach/clk.h>
+#include <mach/rpm-regulator-smd.h>
enum {
MSM_MPM_GIC_IRQ_DOMAIN,
@@ -75,6 +82,12 @@
#define ARCH_TIMER_HZ (19200000)
static struct msm_mpm_device_data msm_mpm_dev_data;
+static struct clk *xo_clk;
+static bool xo_enabled;
+static struct workqueue_struct *msm_mpm_wq;
+static struct work_struct msm_mpm_work;
+static struct completion wake_wq;
+
enum mpm_reg_offsets {
MSM_MPM_REG_WAKEUP,
MSM_MPM_REG_ENABLE,
@@ -257,6 +270,8 @@
else
__clear_bit(d->hwirq, irq_apps);
+ if (!wakeset && (msm_mpm_initialized & MSM_MPM_DEVICE_PROBED))
+ complete(&wake_wq);
}
return 0;
@@ -543,6 +558,54 @@
}
}
}
+static void msm_mpm_sys_low_power_modes(bool allow)
+{
+ if (allow) {
+ if (xo_enabled) {
+ clk_disable_unprepare(xo_clk);
+ xo_enabled = false;
+ }
+ } else {
+ if (!xo_enabled) {
+ /* If we cannot enable XO clock then we want to flag it,
+ * than having to deal with not being able to wakeup
+ * from a non-monitorable interrupt
+ */
+ BUG_ON(clk_prepare_enable(xo_clk));
+ xo_enabled = true;
+ }
+ }
+}
+
+void msm_mpm_suspend_prepare(void)
+{
+ bool allow = msm_mpm_irqs_detectable(false) &&
+ msm_mpm_gpio_irqs_detectable(false);
+ msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_prepare);
+
+void msm_mpm_suspend_wake(void)
+{
+ bool allow = msm_mpm_irqs_detectable(true) &&
+ msm_mpm_gpio_irqs_detectable(true);
+ msm_mpm_sys_low_power_modes(allow);
+}
+EXPORT_SYMBOL(msm_mpm_suspend_wake);
+
+static void msm_mpm_work_fn(struct work_struct *work)
+{
+ unsigned long flags;
+ while (1) {
+ bool allow;
+ wait_for_completion(&wake_wq);
+ spin_lock_irqsave(&msm_mpm_lock, flags);
+ allow = msm_mpm_irqs_detectable(true) &&
+ msm_mpm_gpio_irqs_detectable(true);
+ spin_unlock_irqrestore(&msm_mpm_lock, flags);
+ msm_mpm_sys_low_power_modes(allow);
+ }
+}
static int __devinit msm_mpm_dev_probe(struct platform_device *pdev)
{
@@ -555,6 +618,13 @@
return 0;
}
+ xo_clk = devm_clk_get(&pdev->dev, "xo");
+
+ if (IS_ERR(xo_clk)) {
+ pr_err("%s(): Cannot get clk resource for XO\n", __func__);
+ return PTR_ERR(xo_clk);
+ }
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vmpm");
if (!res) {
pr_err("%s(): Missing RPM memory resource\n", __func__);
@@ -610,10 +680,27 @@
return ret;
}
+
+ init_completion(&wake_wq);
+
+ INIT_WORK(&msm_mpm_work, msm_mpm_work_fn);
+ msm_mpm_wq = create_singlethread_workqueue("mpm");
+
+ if (msm_mpm_wq)
+ queue_work(msm_mpm_wq, &msm_mpm_work);
+ else {
+ pr_warn("%s(): Failed to create wq. So voting against XO off",
+ __func__);
+ /* Throw a BUG. Otherwise, its possible that system allows
+ * XO shutdown when there are non-monitored interrupts are
+ * pending and cause errors at a later point in time.
+ */
+ BUG_ON(clk_prepare_enable(xo_clk));
+ xo_enabled = true;
+ }
+
msm_mpm_initialized |= MSM_MPM_DEVICE_PROBED;
-
return 0;
-
}
static inline int __init mpm_irq_domain_linear_size(struct irq_domain *d)
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 8bceb42..da5e67a 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -40,6 +40,7 @@
#include <mach/trace_msm_low_power.h>
#include <mach/msm-krait-l2-accessors.h>
#include <mach/msm_bus.h>
+#include <mach/mpm.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -1132,9 +1133,22 @@
pm_sleep_ops = *ops;
}
+static int msm_suspend_prepare(void)
+{
+ msm_mpm_suspend_prepare();
+ return 0;
+}
+
+static void msm_suspend_wake(void)
+{
+ msm_mpm_suspend_wake();
+}
+
static const struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
+ .prepare_late = msm_suspend_prepare,
+ .wake = msm_suspend_wake,
};
static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index e62af21..1d12b07 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -21,6 +21,7 @@
#include <linux/uaccess.h>
#include <linux/user.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/cp15.h>
#include <asm/cputype.h>
@@ -656,23 +657,23 @@
}
#ifdef CONFIG_PROC_FS
-static int proc_read_status(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int vfp_bounce_show(struct seq_file *m, void *v)
{
- char *p = page;
- int len;
-
- p += snprintf(p, PAGE_SIZE, "%llu\n", atomic64_read(&vfp_bounce_count));
-
- len = (p - page) - off;
- if (len < 0)
- len = 0;
-
- *eof = (len <= count) ? 1 : 0;
- *start = page + off;
-
- return len;
+ seq_printf(m, "%llu\n", atomic64_read(&vfp_bounce_count));
+ return 0;
}
+
+static int vfp_bounce_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vfp_bounce_show, NULL);
+}
+
+static const struct file_operations vfp_bounce_fops = {
+ .open = vfp_bounce_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
/*
@@ -755,11 +756,9 @@
}
#ifdef CONFIG_PROC_FS
- procfs_entry = create_proc_entry("cpu/vfp_bounce", S_IRUGO, NULL);
-
- if (procfs_entry)
- procfs_entry->read_proc = proc_read_status;
- else
+ procfs_entry = proc_create("cpu/vfp_bounce", S_IRUGO, NULL,
+ &vfp_bounce_fops);
+ if (!procfs_entry)
pr_err("Failed to create procfs node for VFP bounce reporting\n");
#endif
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 132df90..6efab5b 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -65,6 +65,7 @@
#define CSR_QDSSPWRREQIGNORE (0x060)
#define CSR_QDSSSPARE (0x064)
#define CSR_IPCAT (0x068)
+#define CSR_BYTECNTVAL (0x06C)
#define BLKSIZE_256 0
#define BLKSIZE_512 1
@@ -159,6 +160,19 @@
}
EXPORT_SYMBOL(coresight_csr_hwctrl_set);
+void coresight_csr_set_byte_cntr(uint32_t count)
+{
+ struct csr_drvdata *drvdata = csrdrvdata;
+
+ CSR_UNLOCK(drvdata);
+
+ csr_writel(drvdata, count, CSR_BYTECNTVAL);
+ mb();
+
+ CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
+
static int __devinit csr_probe(struct platform_device *pdev)
{
int ret;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index b570252..3ad1f34 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -48,12 +48,14 @@
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
+extern void coresight_csr_set_byte_cntr(uint32_t);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
uint32_t val) { return -ENOSYS; }
+static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
#endif
#ifdef CONFIG_CORESIGHT_ETM
extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 4186abe..c501700 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -30,6 +30,10 @@
#include <linux/of_coresight.h>
#include <linux/coresight.h>
#include <linux/coresight-cti.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
#include <linux/usb/usb_qdss.h>
#include <mach/memory.h>
#include <mach/sps.h>
@@ -135,6 +139,8 @@
struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
+ struct cdev byte_cntr_dev;
+ struct class *byte_cntr_class;
struct clk *clk;
spinlock_t spinlock;
bool reset_flush_race;
@@ -157,6 +163,19 @@
bool enable;
enum tmc_config_type config_type;
uint32_t trigger_cntr;
+ int byte_cntr_irq;
+ atomic_t byte_cntr_irq_cnt;
+ uint32_t byte_cntr_value;
+ struct mutex byte_cntr_read_lock;
+ struct mutex byte_cntr_lock;
+ uint32_t byte_cntr_block_size;
+ bool byte_cntr_overflow;
+ bool byte_cntr_present;
+ bool byte_cntr_enable;
+ uint32_t byte_cntr_overflow_cnt;
+ bool byte_cntr_read_active;
+ wait_queue_head_t wq;
+ char *byte_cntr_node;
};
static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -368,6 +387,52 @@
mutex_unlock(&drvdata->usb_lock);
}
+static uint32_t tmc_etr_get_write_ptr(struct tmc_drvdata *drvdata)
+{
+ uint32_t rwp = 0;
+
+ TMC_UNLOCK(drvdata);
+
+ rwp = tmc_readl(drvdata, TMC_RWP);
+
+ TMC_LOCK(drvdata);
+
+ return rwp;
+}
+
+static void tmc_etr_byte_cntr_start(struct tmc_drvdata *drvdata)
+{
+ if (!drvdata->byte_cntr_present)
+ return;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
+ drvdata->byte_cntr_overflow = false;
+ drvdata->byte_cntr_read_active = false;
+ drvdata->byte_cntr_enable = true;
+ if (drvdata->byte_cntr_value != 0)
+ drvdata->byte_cntr_overflow_cnt = drvdata->size /
+ (drvdata->byte_cntr_value * 8);
+ else
+ drvdata->byte_cntr_overflow_cnt = 0;
+ coresight_csr_set_byte_cntr(drvdata->byte_cntr_value);
+ mutex_unlock(&drvdata->byte_cntr_lock);
+}
+
+static void tmc_etr_byte_cntr_stop(struct tmc_drvdata *drvdata)
+{
+ if (!drvdata->byte_cntr_present)
+ return;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ coresight_csr_set_byte_cntr(0);
+ drvdata->byte_cntr_value = 0;
+ drvdata->byte_cntr_enable = false;
+ mutex_unlock(&drvdata->byte_cntr_lock);
+
+ wake_up(&drvdata->wq);
+}
+
static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
{
/* Zero out the memory to help with debug */
@@ -438,10 +503,14 @@
coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
- !drvdata->reset_flush_race) {
- coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
- coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+ tmc_etr_byte_cntr_start(drvdata);
+ if (!drvdata->reset_flush_race) {
+ coresight_cti_map_trigout(drvdata->cti_flush,
+ 3, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset,
+ 2, 0);
+ }
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
@@ -674,10 +743,14 @@
coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
- !drvdata->reset_flush_race) {
- coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
- coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+ tmc_etr_byte_cntr_stop(drvdata);
+ if (!drvdata->reset_flush_race) {
+ coresight_cti_unmap_trigin(drvdata->cti_reset,
+ 2, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush,
+ 3, 0);
+ }
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
tmc_etr_bam_disable(drvdata);
usb_qdss_close(drvdata->usbch);
@@ -929,6 +1002,161 @@
.llseek = no_llseek,
};
+static int tmc_etr_byte_cntr_open(struct inode *inode, struct file *file)
+{
+ struct tmc_drvdata *drvdata = container_of(inode->i_cdev,
+ struct tmc_drvdata,
+ byte_cntr_dev);
+
+ if (drvdata->out_mode != TMC_ETR_OUT_MODE_MEM ||
+ !drvdata->byte_cntr_enable)
+ return -EPERM;
+
+ if (!mutex_trylock(&drvdata->byte_cntr_read_lock))
+ return -EPERM;
+
+ file->private_data = drvdata;
+ nonseekable_open(inode, file);
+ drvdata->byte_cntr_block_size = drvdata->byte_cntr_value * 8;
+ drvdata->byte_cntr_read_active = true;
+ dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+ return 0;
+}
+
+static void tmc_etr_read_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+ size_t bytes, size_t *len)
+{
+ if (*len >= bytes) {
+ atomic_dec(&drvdata->byte_cntr_irq_cnt);
+ *len = bytes;
+ } else {
+ if (((uint32_t)*ppos % bytes) + *len > bytes)
+ *len = bytes - ((uint32_t)*ppos % bytes);
+ if ((*len + (uint32_t)*ppos) % bytes == 0)
+ atomic_dec(&drvdata->byte_cntr_irq_cnt);
+ }
+}
+
+static size_t tmc_etr_flush_bytes(struct tmc_drvdata *drvdata, loff_t *ppos,
+ size_t bytes)
+{
+ uint32_t rwp = 0;
+ size_t len = bytes;
+
+ rwp = tmc_etr_get_write_ptr(drvdata);
+ if (rwp >= (drvdata->paddr + *ppos)) {
+ if (len > (rwp - drvdata->paddr - *ppos))
+ len = rwp - drvdata->paddr - *ppos;
+ }
+ return len;
+}
+
+static ssize_t tmc_etr_byte_cntr_read(struct file *file, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ struct tmc_drvdata *drvdata = file->private_data;
+ char *bufp = drvdata->vaddr + *ppos;
+ size_t bytes = drvdata->byte_cntr_block_size;
+ int ret = 0;
+
+ if (!data)
+ return -EINVAL;
+ if (drvdata->byte_cntr_overflow)
+ return -EIO;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ /* In case the byte counter is enabled and disabled multiple times
+ * prevent unexpected data from being given to the user
+ */
+ if (!drvdata->byte_cntr_read_active)
+ goto read_err0;
+
+ if (!drvdata->byte_cntr_enable) {
+ if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ /* Read the last 'block' of data which might be needed
+ * to be read partially. If already read, return 0
+ */
+ len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+ if (!len)
+ goto read_err0;
+ } else {
+ /* Keep reading until you reach the last block of data
+ */
+ tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+ }
+ } else {
+ if (!atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ if (wait_event_interruptible(drvdata->wq,
+ (atomic_read(&drvdata->byte_cntr_irq_cnt) > 0) ||
+ !drvdata->byte_cntr_enable)) {
+ ret = -ERESTARTSYS;
+ goto read_err1;
+ }
+ mutex_lock(&drvdata->byte_cntr_lock);
+ if (!drvdata->byte_cntr_read_active) {
+ ret = 0;
+ goto read_err0;
+ }
+ }
+ if (drvdata->byte_cntr_overflow) {
+ ret = -EIO;
+ goto read_err0;
+ }
+ if (!drvdata->byte_cntr_enable &&
+ !atomic_read(&drvdata->byte_cntr_irq_cnt)) {
+ len = tmc_etr_flush_bytes(drvdata, ppos, bytes);
+ if (!len) {
+ ret = 0;
+ goto read_err0;
+ }
+ } else {
+ tmc_etr_read_bytes(drvdata, ppos, bytes, &len);
+ }
+ }
+ if (copy_to_user(data, bufp, len)) {
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+ ret = -EFAULT;
+ goto read_err1;
+ }
+ mutex_unlock(&drvdata->byte_cntr_lock);
+
+ if (*ppos + len >= drvdata->size)
+ *ppos = 0;
+ else
+ *ppos += len;
+
+ dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+ __func__, len, (int) (drvdata->size - *ppos));
+ return len;
+
+read_err0:
+ mutex_unlock(&drvdata->byte_cntr_lock);
+read_err1:
+ return ret;
+}
+
+static int tmc_etr_byte_cntr_release(struct inode *inode, struct file *file)
+{
+ struct tmc_drvdata *drvdata = file->private_data;
+
+ mutex_lock(&drvdata->byte_cntr_lock);
+ drvdata->byte_cntr_read_active = false;
+ mutex_unlock(&drvdata->byte_cntr_lock);
+ mutex_unlock(&drvdata->byte_cntr_read_lock);
+ dev_dbg(drvdata->dev, "%s: released\n", __func__);
+ return 0;
+}
+
+static const struct file_operations byte_cntr_fops = {
+ .owner = THIS_MODULE,
+ .open = tmc_etr_byte_cntr_open,
+ .read = tmc_etr_byte_cntr_read,
+ .release = tmc_etr_byte_cntr_release,
+ .llseek = no_llseek,
+};
+
static ssize_t tmc_show_trigger_cntr(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1044,6 +1272,41 @@
static DEVICE_ATTR(out_mode, S_IRUGO | S_IWUSR, tmc_etr_show_out_mode,
tmc_etr_store_out_mode);
+static ssize_t tmc_etr_show_byte_cntr_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->byte_cntr_value;
+
+ if (!drvdata->byte_cntr_present)
+ return -EPERM;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_byte_cntr_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (!drvdata->byte_cntr_present || drvdata->byte_cntr_enable)
+ return -EPERM;
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+ if ((drvdata->size / 8) < val)
+ return -EINVAL;
+ if (drvdata->size % (val * 8) != 0)
+ return -EINVAL;
+
+ drvdata->byte_cntr_value = val;
+ return size;
+}
+static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
+ tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
+
static struct attribute *tmc_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
@@ -1055,6 +1318,7 @@
static struct attribute *tmc_etr_attrs[] = {
&dev_attr_out_mode.attr,
+ &dev_attr_byte_cntr_value.attr,
NULL,
};
@@ -1118,6 +1382,113 @@
sps_deregister_bam_device(bamdata->handle);
}
+static irqreturn_t tmc_etr_byte_cntr_irq(int irq, void *data)
+{
+ struct tmc_drvdata *drvdata = data;
+
+ atomic_inc(&drvdata->byte_cntr_irq_cnt);
+ if (atomic_read(&drvdata->byte_cntr_irq_cnt) >
+ drvdata->byte_cntr_overflow_cnt) {
+ dev_err(drvdata->dev, "Byte counter overflow\n");
+ drvdata->byte_cntr_overflow = true;
+ }
+ wake_up(&drvdata->wq);
+ return IRQ_HANDLED;
+}
+
+static int tmc_etr_byte_cntr_dev_register(struct tmc_drvdata *drvdata)
+{
+ int ret;
+ struct device *device;
+ dev_t dev;
+
+ ret = alloc_chrdev_region(&dev, 0, 1, drvdata->byte_cntr_node);
+ if (ret)
+ goto dev_err0;
+ cdev_init(&drvdata->byte_cntr_dev, &byte_cntr_fops);
+ drvdata->byte_cntr_dev.owner = THIS_MODULE;
+ drvdata->byte_cntr_dev.ops = &byte_cntr_fops;
+ ret = cdev_add(&drvdata->byte_cntr_dev, dev, 1);
+ if (ret)
+ goto dev_err1;
+ drvdata->byte_cntr_class = class_create(THIS_MODULE,
+ drvdata->byte_cntr_node);
+ if (!drvdata->byte_cntr_class)
+ goto dev_err2;
+ device = device_create(drvdata->byte_cntr_class, NULL,
+ drvdata->byte_cntr_dev.dev, drvdata,
+ drvdata->byte_cntr_node);
+ if (IS_ERR(device)) {
+ ret = PTR_ERR(device);
+ goto dev_err3;
+ }
+ return 0;
+dev_err3:
+ class_destroy(drvdata->byte_cntr_class);
+dev_err2:
+ cdev_del(&drvdata->byte_cntr_dev);
+dev_err1:
+ unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+dev_err0:
+ return ret;
+}
+
+static void tmc_etr_byte_cntr_dev_deregister(struct tmc_drvdata *drvdata)
+{
+ device_destroy(drvdata->byte_cntr_class, drvdata->byte_cntr_dev.dev);
+ class_destroy(drvdata->byte_cntr_class);
+ cdev_del(&drvdata->byte_cntr_dev);
+ unregister_chrdev_region(drvdata->byte_cntr_dev.dev, 1);
+}
+
+static int tmc_etr_byte_cntr_init(struct platform_device *pdev,
+ struct tmc_drvdata *drvdata)
+{
+ int ret = 0;
+ size_t node_size = strlen("-stream") + 1;
+ char *node_name = (char *)((struct coresight_platform_data *)
+ (pdev->dev.platform_data))->name;
+
+ if (!drvdata->byte_cntr_present) {
+ dev_info(&pdev->dev, "Byte Counter feature absent\n");
+ return 0;
+ }
+
+ drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
+ "byte-cntr-irq");
+ if (drvdata->byte_cntr_irq < 0) {
+ dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
+ return 0;
+ }
+ ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
+ tmc_etr_byte_cntr_irq,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ node_name, drvdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Request irq failed\n");
+ return ret;
+ }
+ init_waitqueue_head(&drvdata->wq);
+ node_size += strlen(node_name);
+ drvdata->byte_cntr_node = devm_kzalloc(&pdev->dev,
+ node_size, GFP_KERNEL);
+ strlcpy(drvdata->byte_cntr_node, node_name, node_size);
+ strlcat(drvdata->byte_cntr_node, "-stream", node_size);
+ ret = tmc_etr_byte_cntr_dev_register(drvdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Byte cntr node not registered\n");
+ return ret;
+ }
+ dev_info(&pdev->dev, "Byte Counter feature enabled\n");
+ return 0;
+}
+
+static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
+{
+ if (drvdata->byte_cntr_present)
+ tmc_etr_byte_cntr_dev_deregister(drvdata);
+}
+
static int __devinit tmc_probe(struct platform_device *pdev)
{
int ret;
@@ -1162,6 +1533,9 @@
spin_lock_init(&drvdata->spinlock);
mutex_init(&drvdata->read_lock);
mutex_init(&drvdata->usb_lock);
+ mutex_init(&drvdata->byte_cntr_lock);
+ mutex_init(&drvdata->byte_cntr_read_lock);
+ atomic_set(&drvdata->byte_cntr_irq_cnt, 0);
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
@@ -1207,10 +1581,16 @@
memset(drvdata->vaddr, 0, drvdata->size);
drvdata->buf = drvdata->vaddr;
drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
-
- ret = tmc_etr_bam_init(pdev, drvdata);
+ if (pdev->dev.of_node)
+ drvdata->byte_cntr_present = !of_property_read_bool
+ (pdev->dev.of_node,
+ "qcom,byte-cntr-absent");
+ ret = tmc_etr_byte_cntr_init(pdev, drvdata);
if (ret)
goto err0;
+ ret = tmc_etr_bam_init(pdev, drvdata);
+ if (ret)
+ goto err1;
} else {
baddr = devm_kzalloc(dev, PAGE_SIZE + drvdata->size,
GFP_KERNEL);
@@ -1277,7 +1657,7 @@
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
- goto err1;
+ goto err2;
}
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1290,7 +1670,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -1303,7 +1683,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
} else {
desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
@@ -1317,7 +1697,7 @@
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
- goto err1;
+ goto err2;
}
}
@@ -1327,14 +1707,16 @@
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
if (ret)
- goto err2;
+ goto err3;
dev_info(dev, "TMC initialized\n");
return 0;
-err2:
+err3:
coresight_unregister(drvdata->csdev);
-err1:
+err2:
tmc_etr_bam_exit(drvdata);
+err1:
+ tmc_etr_byte_cntr_exit(drvdata);
err0:
free_contiguous_memory_by_paddr(drvdata->paddr);
return ret;
@@ -1344,6 +1726,7 @@
{
struct tmc_drvdata *drvdata = platform_get_drvdata(pdev);
+ tmc_etr_byte_cntr_exit(drvdata);
misc_deregister(&drvdata->miscdev);
coresight_unregister(drvdata->csdev);
tmc_etr_bam_exit(drvdata);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 76c6350..4c05978 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -188,12 +188,7 @@
min_rev = (rev & CRYPTO_CORE_MINOR_REV_MASK) >> CRYPTO_CORE_MINOR_REV;
step_rev = (rev & CRYPTO_CORE_STEP_REV_MASK) >> CRYPTO_CORE_STEP_REV;
- if ((maj_rev != 0x05) || (min_rev > 0x02) || (step_rev > 0x02)) {
- pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
- pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
- return -EIO;
- };
- if ((min_rev > 0) && (step_rev != 0)) {
+ if (maj_rev != 0x05) {
pr_err("Unknown Qualcomm crypto device at 0x%x, rev %d.%d.%d\n",
pce_dev->phy_iobase, maj_rev, min_rev, step_rev);
return -EIO;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5415f4e..b725200 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1996,7 +1996,7 @@
if (atomic_read(&data->st_enabled) == 0)
break;
- pm_runtime_put(&data->client->adapter->dev);
+ pm_runtime_put(data->client->adapter->dev.parent);
atomic_set(&data->st_enabled, 0);
complete(&data->st_completion);
mxt_interrupt(data->client->irq, data);
@@ -2015,8 +2015,9 @@
}
INIT_COMPLETION(data->st_completion);
INIT_COMPLETION(data->st_powerdown);
- atomic_set(&data->st_pending_irqs, 0);
atomic_set(&data->st_enabled, 1);
+ synchronize_irq(data->client->irq);
+ atomic_set(&data->st_pending_irqs, 0);
break;
default:
dev_err(&data->client->dev, "unsupported value: %lu\n", value);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ba0be2b..908d0d7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1056,6 +1056,8 @@
rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
"synaptics,i2c-pull-up");
+ rmi4_pdata->power_down_enable = of_property_read_bool(np,
+ "synaptics,power-down");
rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
@@ -2003,7 +2005,7 @@
error_reg_en_vcc_i2c:
if (rmi4_data->board->i2c_pull_up)
- reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+ reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
error_reg_opt_i2c:
regulator_disable(rmi4_data->vdd);
error_reg_en_vdd:
@@ -2592,29 +2594,53 @@
bool on)
{
int retval;
+ int load_ua;
if (on == false)
goto regulator_hpm;
- retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+ load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+ retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_ana set_opt failed rc=%d\n",
+ "Regulator vdd_ana set_opt failed rc=%d\n",
retval);
goto fail_regulator_lpm;
}
- if (rmi4_data->board->i2c_pull_up) {
- retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
- RMI4_I2C_LPM_LOAD_UA);
- if (retval < 0) {
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_disable(rmi4_data->vdd);
+ if (retval) {
dev_err(&rmi4_data->i2c_client->dev,
- "Regulator vcc_i2c set_opt failed rc=%d\n",
+ "Regulator vdd disable failed rc=%d\n",
retval);
goto fail_regulator_lpm;
}
}
+ if (rmi4_data->board->i2c_pull_up) {
+ load_ua = rmi4_data->board->power_down_enable ?
+ 0 : RMI4_I2C_LPM_LOAD_UA;
+ retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+ load_ua);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c set_opt failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_lpm;
+ }
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_disable(rmi4_data->vcc_i2c);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c disable failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_lpm;
+ }
+ }
+ }
+
return 0;
regulator_hpm:
@@ -2628,6 +2654,16 @@
goto fail_regulator_hpm;
}
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_enable(rmi4_data->vdd);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vdd enable failed rc=%d\n",
+ retval);
+ goto fail_regulator_hpm;
+ }
+ }
+
if (rmi4_data->board->i2c_pull_up) {
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
RMI4_I2C_LOAD_UA);
@@ -2637,6 +2673,26 @@
retval);
goto fail_regulator_hpm;
}
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = regulator_enable(rmi4_data->vcc_i2c);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Regulator vcc_i2c enable failed " \
+ "rc=%d\n", retval);
+ goto fail_regulator_hpm;
+ }
+ }
+ }
+
+ if (rmi4_data->board->power_down_enable) {
+ retval = synaptics_rmi4_reset_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to issue reset command, rc = %d\n",
+ __func__, retval);
+ return retval;
+ }
}
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8b0f6f1..a4eb274 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1036,7 +1036,7 @@
}
#endif
-void msm_cpp_do_timeout_work(struct work_struct *work)
+static void msm_cpp_do_timeout_work(struct work_struct *work)
{
int ret;
uint32_t i = 0;
@@ -1046,6 +1046,11 @@
pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
del_timer_idx, jiffies);
+ if (!work || !this_frame) {
+ pr_err("Invalid work:%p, this_frame:%p, del_idx:%d\n",
+ work, this_frame, del_timer_idx);
+ return;
+ }
pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
this_frame->identity, this_frame->frame_id);
cpp_timers[del_timer_idx].used = 0;
@@ -1304,7 +1309,8 @@
(cpp_frame_msg[12] & 0x3FF);
fw_version_1_2_x = 0;
- if (cpp_dev->hw_info.cpp_hw_version == 0x10010000)
+ if ((cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_0) ||
+ (cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1))
fw_version_1_2_x = 2;
for (i = 0; i < num_stripes; i++) {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 0a70d37..796bede 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -21,6 +21,14 @@
#include <media/v4l2-subdev.h>
#include "msm_sd.h"
+/* hw version info:
+ 31:28 Major version
+ 27:16 Minor version
+ 15:0 Revision bits
+**/
+#define CPP_HW_VERSION_1_1_0 0x10010000
+#define CPP_HW_VERSION_1_1_1 0x10010001
+
#define MAX_ACTIVE_CPP_INSTANCE 8
#define MAX_CPP_PROCESSING_FRAME 2
#define MAX_CPP_V4l2_EVENTS 30
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 44105ad..a63ee61 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1230,7 +1230,7 @@
hfi_msg_sys_session_abort_done_packet*) msg_hdr);
break;
default:
- dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+ dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1c43f1e..b6d031a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -477,14 +477,14 @@
if (rc) {
dprintk(VIDC_ERR,
"Failed to initialize vb2 queue on capture port\n");
- goto fail_init;
+ goto fail_bufq_capture;
}
rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
session_type);
if (rc) {
dprintk(VIDC_ERR,
"Failed to initialize vb2 queue on capture port\n");
- goto fail_init;
+ goto fail_bufq_output;
}
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
if (rc) {
@@ -502,6 +502,14 @@
mutex_unlock(&core->lock);
return inst;
fail_init:
+ vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+fail_bufq_output:
+ vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+ if (session_type == MSM_VIDC_DECODER)
+ msm_vdec_ctrl_deinit(inst);
+ else if (session_type == MSM_VIDC_ENCODER)
+ msm_venc_ctrl_deinit(inst);
msm_smem_delete_client(inst->mem_client);
fail_mem_client:
kfree(inst);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 8121471..9cd199b 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -296,24 +296,13 @@
static long set_default_properties(struct venc_inst *inst)
{
struct v4l2_control ctrl = {0};
- int rc;
/* Set the IDR period as 1. The venus core doesn't give
* the sps/pps for I-frames, only IDR. */
ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
ctrl.value = 1;
- rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
- if (rc)
- WFD_MSG_WARN("Failed to set IDR period\n");
- /* Set the default rc mode to VBR/VFR, client can change later */
- ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
- ctrl.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
- rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
- if (rc)
- WFD_MSG_WARN("Failed to set rc mode\n");
-
- return 0;
+ return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
static int subscribe_events(struct venc_inst *inst)
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 28f9e80..7934234 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2420,9 +2420,11 @@
FMDERR("AF list size received more than available size");
return;
}
- memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET], ev.af_size);
+ memcpy(&ev.af_list[0], &skb->data[AF_LIST_OFFSET],
+ ev.af_size * sizeof(int));
iris_q_event(radio, IRIS_EVT_NEW_AF_LIST);
- iris_q_evt_data(radio, (char *)&ev, sizeof(ev), IRIS_BUF_AF_LIST);
+ iris_q_evt_data(radio, (char *)&ev, (7 + ev.af_size * sizeof(int)),
+ IRIS_BUF_AF_LIST);
}
static void hci_ev_rds_lock_status(struct radio_hci_dev *hdev,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9527249..654dbcb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1496,9 +1496,11 @@
int vdd_bit = -1;
u8 ctrl;
+ mutex_lock(&host->ios_mutex);
if (host->flags & SDHCI_DEVICE_DEAD) {
if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+ mutex_unlock(&host->ios_mutex);
return;
}
@@ -1508,6 +1510,7 @@
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->ios_mutex);
return;
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -1664,6 +1667,7 @@
sdhci_set_clock(host, ios->clock);
mmiowb();
+ mutex_unlock(&host->ios_mutex);
}
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -2900,6 +2904,7 @@
host->mmc = mmc;
spin_lock_init(&host->lock);
+ mutex_init(&host->ios_mutex);
return host;
}
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 9e9a4ea..e832716 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -27,7 +27,6 @@
#include <linux/regulator/consumer.h>
#include "nfc-nci.h"
-
struct qca199x_platform_data {
unsigned int irq_gpio;
unsigned int dis_gpio;
@@ -62,6 +61,7 @@
bool irq_enabled;
spinlock_t irq_enabled_lock;
unsigned int count_irq;
+ enum nfcc_state state;
};
/*
@@ -69,6 +69,12 @@
* IOCTL NFC_KERNEL_LOGGING_MODE.
*/
static int logging_level;
+/*
+ * FTM-RAW-I2C RD/WR MODE
+ */
+static struct devicemode device_mode;
+static int ftm_raw_write_mode;
+static int ftm_werr_code;
static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
{
@@ -104,7 +110,6 @@
struct qca199x_dev *qca199x_dev = dev_id;
unsigned long flags;
-
spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
qca199x_dev->count_irq++;
spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
@@ -119,7 +124,6 @@
unsigned int mask = 0;
unsigned long flags;
-
poll_wait(filp, &qca199x_dev->read_wq, wait);
spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
@@ -129,17 +133,33 @@
}
spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
-
return mask;
}
+/*
+ * ONLY for FTM-RAW-I2C Mode
+ * Required to instigate a read, which comes from DT layer. This means we need
+ * to spoof an interrupt and send a wake up event.
+ */
+void ftm_raw_trigger_read(struct qca199x_dev *qca199x_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
+ qca199x_dev->count_irq++;
+ spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
+ wake_up(&qca199x_dev->read_wq);
+}
+
static ssize_t nfc_read(struct file *filp, char __user *buf,
size_t count, loff_t *offset)
{
struct qca199x_dev *qca199x_dev = filp->private_data;
- unsigned char tmp[MAX_BUFFER_SIZE];
+ unsigned char tmp[MAX_BUFFER_SIZE], rd_byte;
unsigned char len[PAYLOAD_HEADER_LENGTH];
int total, length, ret;
+ int ftm_rerr_code;
+ enum ehandler_mode dmode;
total = 0;
length = 0;
@@ -147,6 +167,36 @@
count = MAX_BUFFER_SIZE;
mutex_lock(&qca199x_dev->read_mutex);
+ dmode = device_mode.handle_flavour;
+ /* FTM-RAW-I2C RD/WR MODE - Special Case */
+ if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+ (dmode == SOLICITED_FTM_RAW_MODE)) {
+ /* READ */
+ if ((ftm_raw_write_mode == 0) && (ftm_werr_code == 0)) {
+ ftm_rerr_code = i2c_master_recv(qca199x_dev->client,
+ &rd_byte, 1);
+ if (ftm_rerr_code == 0x1)
+ ftm_rerr_code = 0;
+ tmp[0] = (unsigned char)ftm_rerr_code;
+ tmp[1] = rd_byte;
+ total = 2;
+ ret = copy_to_user(buf, tmp, total);
+ }
+ /* WRITE */
+ else if ((ftm_raw_write_mode == 1) || (ftm_werr_code != 0)) {
+ tmp[0] = (unsigned char)ftm_werr_code;
+ total = 1;
+ ret = copy_to_user(buf, tmp, total);
+ } else {
+ /* Invalid case */
+ total = 0;
+ ret = copy_to_user(buf, tmp, total);
+ }
+ mutex_unlock(&qca199x_dev->read_mutex);
+ goto done;
+ }
+
+ /* NORMAL NCI Behaviour */
/* Read the header */
ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
if (ret != PAYLOAD_HEADER_LENGTH)
@@ -174,7 +224,7 @@
err:
if (ret < 0)
mutex_unlock(&qca199x_dev->read_mutex);
-
+done:
return total;
}
@@ -183,7 +233,8 @@
{
struct qca199x_dev *qca199x_dev = filp->private_data;
char tmp[MAX_BUFFER_SIZE];
- int ret;
+ int ret = 0;
+ enum ehandler_mode dmode;
if (count > MAX_BUFFER_SIZE) {
dev_err(&qca199x_dev->client->dev, "out of memory\n");
@@ -195,10 +246,39 @@
return -EFAULT;
}
mutex_lock(&qca199x_dev->read_mutex);
- ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ dmode = device_mode.handle_flavour;
+ /* FTM-DIRECT-I2C RD/WR MODE */
+ /* This is a special FTM-i2c mode case,where tester is not using NCI */
+ if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
+ (dmode == SOLICITED_FTM_RAW_MODE)) {
+ /* Read From Register */
+ if (count == 1) {
+ ftm_raw_write_mode = 0;
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ if (ret == 1)
+ ftm_werr_code = 0;
+ else
+ ftm_werr_code = ret;
+ ftm_raw_trigger_read(qca199x_dev);
+ }
+ /* Write to Register */
+ if (count == 2) {
+ ftm_raw_write_mode = 1;
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ if (ret == 2)
+ ftm_werr_code = 0;
+ else
+ ftm_werr_code = ret;
+ ftm_raw_trigger_read(qca199x_dev);
+ }
+ } else {
+ /* NORMAL NCI behaviour - NB :
+ We can be in FTM mode here also */
+ ret = i2c_master_send(qca199x_dev->client, tmp, count);
+ }
if (ret != count) {
dev_err(&qca199x_dev->client->dev,
- "NFC: failed to write %d\n", ret);
+ "NFC: failed to write %d\n", ret);
ret = -EIO;
}
mutex_unlock(&qca199x_dev->read_mutex);
@@ -225,7 +305,7 @@
/*
* Wake/Sleep Mode
*/
-int nfcc_wake(int level, struct nfc_info *info)
+int nfcc_wake(int level, struct file *filp)
{
int r = 0;
unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
@@ -233,32 +313,32 @@
unsigned char raw_nci_wake[] = {0x10, 0x0F};
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
+ struct qca199x_dev *qca199x_dev = filp->private_data;
- struct i2c_client *client = info->i2c_dev;
-
- dev_dbg(&client->dev, "nfcc_wake: %s: info: %p\n", __func__, info);
+ dev_dbg(&qca199x_dev->client->dev, "nfcc_wake: %s: info: %p\n",
+ __func__, qca199x_dev);
if (level == NFCC_SLEEP) {
- r = nfc_i2c_write(client, &raw_nci_sleep[0],
+ r = i2c_master_send(qca199x_dev->client, &raw_nci_sleep[0],
sizeof(raw_nci_sleep));
+ r = sizeof(raw_nci_sleep);
if (r != sizeof(raw_nci_sleep))
return -EMSGSIZE;
- info->state = NFCC_STATE_NORMAL_SLEEP;
+ qca199x_dev->state = NFCC_STATE_NORMAL_SLEEP;
} else {
- curr_addr = client->addr;
- client->addr = slave_addr;
- r = nfc_i2c_write(client, &raw_nci_wake[0],
+ curr_addr = qca199x_dev->client->addr;
+ qca199x_dev->client->addr = slave_addr;
+ r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
sizeof(raw_nci_wake));
/* Restore original NFCC slave I2C address */
- client->addr = curr_addr;
-
- if (r != sizeof(raw_nci_sleep))
+ qca199x_dev->client->addr = curr_addr;
+ r = sizeof(raw_nci_wake);
+ if (r != sizeof(raw_nci_wake))
return -EMSGSIZE;
-
- info->state = NFCC_STATE_NORMAL_WAKE;
+ qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
}
- msleep(20);
+
return r;
}
@@ -284,41 +364,35 @@
{
int r = 0;
struct qca199x_dev *qca199x_dev = filp->private_data;
- struct nfc_info *info = container_of(filp->private_data,
- struct nfc_info, miscdev);
-
- struct i2c_client *client = info->i2c_dev;
-
- r = gpio_request(qca199x_dev->dis_gpio, "nfc_reset_gpio");
- if (r) {
- dev_err(&client->dev, "unable to request gpio [%d]\n",
- qca199x_dev->dis_gpio);
- goto err_req;
- }
- gpio_set_value(qca199x_dev->dis_gpio, 0);
- r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
- if (r) {
- dev_err(&client->dev, "unable to set direction for gpio [%d]\n",
- qca199x_dev->irq_gpio);
- goto err_req;
- }
if (arg == 0) {
gpio_set_value(qca199x_dev->dis_gpio, 0);
- msleep(20);
+ r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+ if (r) {
+ dev_err(&qca199x_dev->client->dev,
+ "unable to set direction for gpio [%d]\n",
+ qca199x_dev->dis_gpio);
+ goto err_req;
+ }
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
} else if (arg == 1) {
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
+ r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
+ if (r) {
+ dev_err(&qca199x_dev->client->dev,
+ "unable to set direction for gpio [%d]\n",
+ qca199x_dev->dis_gpio);
+ goto err_req;
+ }
gpio_set_value(qca199x_dev->dis_gpio, 1);
- msleep(20);
} else if (arg == 2) {
msleep(20);
} else if (arg == 3) {
msleep(20);
} else if (arg == 4) {
- nfcc_wake(NFCC_WAKE, info);
- msleep(20);
+ nfcc_wake(NFCC_WAKE, filp);
} else if (arg == 5) {
- nfcc_wake(NFCC_SLEEP, info);
- msleep(20);
+ nfcc_wake(NFCC_SLEEP, filp);
} else {
r = -ENOIOCTLCMD;
}
@@ -327,6 +401,63 @@
return r;
}
+
+/*
+ * Inside nfc_ioctl_nfcc_mode
+ *
+ * @brief nfc_ioctl_nfcc_mode
+ *
+ * (arg = 0) ; NORMAL_MODE - Standard mode, unsolicited read behaviour
+ * (arg = 1) ; SOLICITED_MODE - As above but reads are solicited from User Land
+ * (arg = 2) ; UNSOLICITED_FTM_RAW MODE - NORMAL_MODE but messages from FTM and
+ * not NCI Host.
+ * (arg = 2) ; SOLICITED_FTM_RAW_MODE - As SOLICITED_MODE but messages from FTM
+ * and not NCI Host.
+ *
+ *
+ *
+ */
+int nfc_ioctl_nfcc_mode(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ static unsigned short nci_addr;
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ struct qca199x_platform_data *platform_data;
+
+ platform_data = qca199x_dev->client->dev.platform_data;
+
+ if (arg == 0) {
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ qca199x_dev->client->addr = NCI_I2C_SLAVE;
+ /* enable interrupts again */
+ qca199x_enable_irq(qca199x_dev);
+ } else if (arg == 1) {
+ device_mode.handle_flavour = SOLICITED_MODE;
+ qca199x_dev->client->addr = qca199x_dev->client->addr;
+ /* enable interrupts again */
+ qca199x_enable_irq(qca199x_dev);
+ } else if (arg == 2) {
+ device_mode.handle_flavour = UNSOLICITED_FTM_RAW_MODE;
+ nci_addr = qca199x_dev->client->addr;
+ /* replace with new client slave address*/
+ qca199x_dev->client->addr = 0xE;
+ /* We also need to disable interrupts */
+ qca199x_disable_irq(qca199x_dev);
+ } else if (arg == 3) {
+ device_mode.handle_flavour = SOLICITED_FTM_RAW_MODE;
+ nci_addr = qca199x_dev->client->addr;
+ /* replace with new client slave address*/
+ qca199x_dev->client->addr = 0xE;
+ /* We also need to disable interrupts */
+ qca199x_disable_irq(qca199x_dev);
+ } else {
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ qca199x_dev->client->addr = NCI_I2C_SLAVE;
+ }
+ return retval;
+}
+
/*
* Inside nfc_ioctl_kernel_logging
*
@@ -371,6 +502,7 @@
nfc_ioctl_power_states(pfile, cmd, arg);
break;
case NFCC_MODE:
+ nfc_ioctl_nfcc_mode(pfile, cmd, arg);
break;
case NFC_KERNEL_LOGGING_MODE:
nfc_ioctl_kernel_logging(arg, pfile);
@@ -447,66 +579,75 @@
unsigned char raw_s73[] = {0x73, 0x02};
unsigned char raw_slave1_rd = {0x0};
unsigned char raw_1P8_PAD_CFG_CLK_REQ[] = {0xA5, 0x1};
- unsigned char buf[4];
+ unsigned char raw_1P8_PAD_CFG_PWR_REQ[] = {0xA7, 0x1};
+ unsigned char buf = 0;
- /* Set I2C address to enable configuration of QCA1990 */
client->addr = curr_addr;
- RAW(s73, 0x02);
+ r = i2c_master_send(client, &buf, 1);
+ buf = 0;
+ r = i2c_master_recv(client, &buf, 1);
+ if (0x10 != (0x10 & buf)) {
+ RAW(s73, 0x02);
- r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
- usleep(1000);
- RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+ r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+ usleep(1000);
+ RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
- r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+ r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
sizeof(raw_1p8_CONTROL_011));
- usleep(1000);
- RAW(1P8_CONTROL_010, (0x8));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
-
- usleep(10000); /* 10ms wait */
- RAW(1P8_CONTROL_010, (0xC));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- usleep(100); /* 100uS wait */
- RAW(1P8_X0_0B0, (FREQ_SEL_19));
- r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0));
- usleep(1000);
-
- /* PWR_EN = 1 */
- RAW(1P8_CONTROL_010, (0xd));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ usleep(1000);
+ RAW(1P8_CONTROL_010, (0x8));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
sizeof(raw_1P8_CONTROL_010));
- usleep(20000); /* 20ms wait */
- /* LS_EN = 1 */
- RAW(1P8_CONTROL_010, 0xF);
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- usleep(20000); /* 20ms wait */
- /* Enable the PMIC clock */
- RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+ usleep(10000); /* 10ms wait */
+ RAW(1P8_CONTROL_010, (0xC));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(100); /* 100uS wait */
+ RAW(1P8_X0_0B0, (FREQ_SEL_19));
+ r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+ sizeof(raw_1P8_X0_0B0));
+ usleep(1000);
+
+ /* PWR_EN = 1 */
+ RAW(1P8_CONTROL_010, (0xd));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+ /* LS_EN = 1 */
+ RAW(1P8_CONTROL_010, 0xF);
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ usleep(20000); /* 20ms wait */
+
+ /* Enable the PMIC clock */
+ RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
sizeof(raw_1P8_PAD_CFG_CLK_REQ));
- usleep(1000);
+ usleep(1000);
- RAW(slave2, 0x10);
- r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
- usleep(1000);
- {
- r = i2c_master_send(client, buf, 1);
- memset(buf, 0xAA, sizeof(buf));
- r = i2c_master_recv(client, buf, 1);
+ RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+ usleep(1000);
+
+ RAW(slave2, 0x10);
+ r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+ usleep(1000);
+
+ RAW(slave1, NCI_I2C_SLAVE);
+ r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+ usleep(1000);
+
+ /* QCA199x NFCC CPU should now boot... */
+ r = i2c_master_recv(client, &raw_slave1_rd, 1);
+ /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+ client->addr = NCI_I2C_SLAVE;
+ r = 0;
+ } else {
+ r = 1;
}
- RAW(slave1, NCI_I2C_SLAVE);
- r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
- usleep(1000);
-
- /* QCA199x NFCC CPU should now boot... */
- r = i2c_master_recv(client, &raw_slave1_rd, 1);
- /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
- client->addr = NCI_I2C_SLAVE;
-
return r;
}
@@ -623,6 +764,9 @@
dev_err(&client->dev, "dis gpio not provided\n");
goto err_irq;
}
+ gpio_set_value(qca199x_dev->dis_gpio, 1);
+ msleep(20);
+ gpio_set_value(qca199x_dev->dis_gpio, 0);
nfc_clk = clk_get(&client->dev, "ref_clk");
@@ -640,7 +784,7 @@
r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
if (r) {
dev_err(&client->dev, "unable to request gpio [%d]\n",
- platform_data->irq_gpio);
+ platform_data->ven_gpio);
goto err_ven_gpio;
}
r = gpio_direction_input(platform_data->ven_gpio);
@@ -648,7 +792,7 @@
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
- platform_data->irq_gpio);
+ platform_data->ven_gpio);
goto err_ven_gpio;
}
@@ -681,7 +825,12 @@
/* request irq. The irq is set whenever the chip has data available
* for reading. It is cleared when all data has been read.
*/
- nfcc_initialise(client, platform_data->reg);
+ device_mode.handle_flavour = UNSOLICITED_MODE;
+ r = nfcc_initialise(client, platform_data->reg);
+ if (r) {
+ dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n");
+ goto err_nfcc_init_failed;
+ }
qca199x_dev->irq_enabled = true;
r = request_irq(client->irq, qca199x_dev_irq_handler,
@@ -697,6 +846,7 @@
__func__);
return 0;
+err_nfcc_init_failed:
err_request_irq_failed:
misc_deregister(&qca199x_dev->qca199x_device);
err_misc_register:
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 4398df7..c3cabc2 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -30,8 +30,10 @@
};
enum ehandler_mode {
- UNSOLICITED_READ_MODE = 0,
- SOLICITED_READ_MODE
+ UNSOLICITED_MODE = 0,
+ SOLICITED_MODE,
+ UNSOLICITED_FTM_RAW_MODE,
+ SOLICITED_FTM_RAW_MODE
};
enum ekernel_logging_mode {
@@ -43,9 +45,9 @@
LEVEL_5
};
-struct DeviceMode {
+struct devicemode {
enum ehandler_mode handle_flavour;
-} tDeviceMode;
+} tdevicemode;
#define NFC_DRIVER_NAME "nfc-nci"
#define NFC_I2C_DRIVER_NAME "NCI NFC I2C Interface",
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index c8e5163..e36806f 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1186,6 +1186,7 @@
int ret;
struct smux_lch_t *ch;
int enable_powerdown = 0;
+ int tx_ready = 0;
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1203,7 +1204,7 @@
if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
schedule_notify(lcid, SMUX_CONNECTED, NULL);
if (!(list_empty(&ch->tx_queue)))
- list_channel(ch);
+ tx_ready = 1;
}
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
@@ -1226,6 +1227,9 @@
spin_unlock(&smux.tx_lock_lha2);
}
+ if (tx_ready)
+ list_channel(ch);
+
return ret;
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 96f0f8c..f2de17d 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -857,6 +857,26 @@
return ret;
}
+static int msm_dsi_cont_on(struct mdss_panel_data *pdata)
+{
+ struct mdss_panel_info *pinfo;
+ int ret = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ pinfo = &pdata->panel_info;
+ ret = msm_dsi_regulator_enable();
+ if (ret) {
+ pr_err("%s: DSI power on failed\n", __func__);
+ return ret;
+ }
+
+ msm_dsi_ahb_ctrl(1);
+ msm_dsi_prepare_clocks();
+ msm_dsi_clk_enable();
+ return 0;
+}
+
static int __devinit msm_dsi_probe(struct platform_device *pdev)
{
struct dsi_interface intf;
@@ -925,6 +945,7 @@
dsi_host_private->dis_dev = pdev->dev;
intf.on = msm_dsi_on;
intf.off = msm_dsi_off;
+ intf.cont_on = msm_dsi_cont_on;
intf.op_mode_config = msm_dsi_op_mode_config;
intf.tx = msm_dsi_cmds_tx;
intf.rx = msm_dsi_cmds_rx;
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 5c164e4..022d911 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -163,7 +163,20 @@
pr_debug("%s: enable = %d\n", __func__, enable);
- if (enable) {
+ if (enable == 2) {
+ dsi_panel_power(1);
+ gpio_request(panel_private->rst_gpio, "panel_reset");
+ if (gpio_is_valid(panel_private->disp_en_gpio)) {
+ gpio_request(panel_private->disp_en_gpio,
+ "panel_enable");
+ }
+ if (gpio_is_valid(panel_private->video_mode_gpio)) {
+ gpio_request(panel_private->video_mode_gpio,
+ "panel_video_mdoe");
+ }
+ if (gpio_is_valid(panel_private->te_gpio))
+ gpio_request(panel_private->te_gpio, "panel_te");
+ } else if (enable == 1) {
dsi_panel_power(1);
gpio_request(panel_private->rst_gpio, "panel_reset");
gpio_set_value(panel_private->rst_gpio, 1);
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 1a9059c..686ec01 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -82,6 +82,25 @@
return rc;
}
+static int dsi_splash_on(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+
+ pr_debug("%s:\n", __func__);
+
+ if (panel_common_data->reset)
+ panel_common_data->reset(pdata, 2);
+
+ if (dsi_intf.cont_on)
+ rc = dsi_intf.cont_on(pdata);
+
+ if (rc) {
+ pr_err("mdss_dsi_on DSI failed %d\n", rc);
+ return rc;
+ }
+ return rc;
+}
+
static int dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -105,6 +124,9 @@
case MDSS_EVENT_PANEL_OFF:
rc = dsi_panel_handler(pdata, 0);
break;
+ case MDSS_EVENT_CONT_SPLASH_BEGIN:
+ rc = dsi_splash_on(pdata);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 54b772b..96dd390 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -198,6 +198,7 @@
struct dsi_interface {
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
+ int (*cont_on)(struct mdss_panel_data *pdata);
void (*op_mode_config)(int mode, struct mdss_panel_data *pdata);
int (*tx)(struct mdss_panel_data *pdata,
struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 66418db..f6f722e 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -959,6 +959,21 @@
return rc;
}
+int mdp3_iommu_is_attached(int client)
+{
+ struct mdp3_iommu_ctx_map *context_map;
+ int context = MDP3_IOMMU_CTX_DMA_0;
+
+ if (!mdp3_res->iommu_contexts)
+ return 0;
+
+ if (client == MDP3_CLIENT_PPP)
+ context = MDP3_IOMMU_CTX_PPP_0;
+
+ context_map = mdp3_res->iommu_contexts + context;
+ return context_map->attached;
+}
+
static int mdp3_init(struct msm_fb_data_type *mfd)
{
int rc;
@@ -982,6 +997,66 @@
return xres * bpp;
}
+void mdp3_fbmem_clear(void)
+{
+ if (mdp3_res->ion_handle && mdp3_res->virt) {
+ pr_debug("mdp3_fbmem_clear\n");
+ memset(mdp3_res->virt, 0, mdp3_res->size);
+ }
+}
+
+static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
+{
+ int ret = 0;
+
+ if (mdp3_res->ion_handle) {
+ pr_debug("memory already alloc\n");
+ *virt = mdp3_res->virt;
+ *phys = mdp3_res->phys;
+ return 0;
+ }
+
+ mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
+ SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
+ *virt = ion_map_kernel(mdp3_res->ion_client,
+ mdp3_res->ion_handle);
+ if (IS_ERR(*virt)) {
+ pr_err("map kernel error\n");
+ goto ion_map_kernel_err;
+ }
+
+ ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
+ phys, &size);
+ if (ret) {
+ pr_err("%s ion_phys error\n", __func__);
+ goto ion_map_phys_err;
+ }
+
+ mdp3_res->virt = *virt;
+ mdp3_res->phys = *phys;
+ mdp3_res->size = size;
+ } else {
+ pr_err("%s ion alloc fail\n", __func__);
+ mdp3_res->ion_handle = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+
+ion_map_phys_err:
+ ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
+ion_map_kernel_err:
+ ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
+ mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
+ return -ENOMEM;
+}
+
static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
{
int ret = -ENOMEM, dom;
@@ -999,28 +1074,10 @@
return 0;
}
- mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
- SZ_1M,
- ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-
- if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
- virt = ion_map_kernel(mdp3_res->ion_client,
- mdp3_res->ion_handle);
- if (IS_ERR(virt)) {
- pr_err("%s map kernel error\n", __func__);
- goto ion_map_kernel_err;
- }
-
- ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
- &phys, &size);
- if (ret) {
- pr_err("%s ion_phys error\n", __func__);
- goto ion_map_phys_err;
- }
- } else {
- pr_err("%s ion alloc fail\n", __func__);
- mdp3_res->ion_handle = NULL;
- return -ENOMEM;
+ ret = mdp3_alloc(size, &virt, &phys);
+ if (ret) {
+ pr_err("fail to allocate fb memory\n");
+ return ret;
}
dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
@@ -1031,10 +1088,10 @@
if (ret) {
pr_err("%s map IOMMU error\n", __func__);
- goto ion_map_phys_err;
+ goto ion_map_iommu_err;
}
- pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
mfd->fbi->screen_base = virt;
@@ -1042,17 +1099,19 @@
mfd->fbi->fix.smem_len = size;
return 0;
-ion_map_phys_err:
+ion_map_iommu_err:
ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-ion_map_kernel_err:
ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
return -ENOMEM;
}
void mdp3_fbmem_free(struct msm_fb_data_type *mfd)
{
- pr_info("mdp3_fbmem_free\n");
+ pr_debug("mdp3_fbmem_free\n");
if (mdp3_res->ion_handle) {
int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
@@ -1061,6 +1120,9 @@
dom, 0);
ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
mdp3_res->ion_handle = NULL;
+ mdp3_res->virt = NULL;
+ mdp3_res->phys = 0;
+ mdp3_res->size = 0;
mfd->fbi->screen_base = 0;
mfd->fbi->fix.smem_start = 0;
mfd->fbi->fix.smem_len = 0;
@@ -1103,6 +1165,130 @@
return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
}
+int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
+{
+ unsigned long splash_phys, phys;
+ void *splash_virt, *virt;
+ u32 height, width, rgb_size, stride;
+ size_t size;
+ int rc;
+
+ rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
+ stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
+ stride = stride & 0x3FFF;
+ splash_phys = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * stride * 2);
+ pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
+ height, width, size);
+
+ rc = mdp3_alloc(size, &virt, &phys);
+ if (rc) {
+ pr_err("fail to allocate memory for continuous splash image\n");
+ return rc;
+ }
+
+ splash_virt = ioremap(splash_phys, stride * height);
+ memcpy(virt, splash_virt, stride * height);
+ iounmap(splash_virt);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, phys);
+
+ return 0;
+}
+
+static int mdp3_is_display_on(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+ u32 status;
+
+ mdp3_clk_update(MDP3_CLK_AHB, 1);
+ mdp3_clk_update(MDP3_CLK_CORE, 1);
+
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
+ rc = status & 0x1;
+ } else {
+ status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
+ rc = status & 01;
+ }
+
+ mdp3_clk_update(MDP3_CLK_AHB, 0);
+ mdp3_clk_update(MDP3_CLK_CORE, 0);
+ return rc;
+}
+
+static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
+{
+ struct mdss_panel_info *panel_info = &pdata->panel_info;
+ int ab, ib, rc;
+
+ pr_debug("mdp3__continuous_splash_on\n");
+
+ rc = mdp3_clk_enable(1);
+ if (rc) {
+ pr_err("fail to enable clk\n");
+ return rc;
+ }
+
+ ab = panel_info->xres * panel_info->yres * 4;
+ ab *= panel_info->mipi.frame_rate;
+ ib = (ab * 3) / 2;
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
+ if (rc) {
+ pr_err("fail to request bus bandwidth\n");
+ goto splash_on_err;
+ }
+
+ rc = mdp3_ppp_init();
+ if (rc) {
+ pr_err("ppp init failed\n");
+ goto splash_on_err;
+ }
+
+ rc = mdp3_continuous_splash_copy(pdata);
+ if (rc) {
+ pr_err("fail to copy continuous splash image\n");
+ goto splash_on_err;
+ }
+
+ mdp3_irq_register();
+
+ if (pdata->event_handler) {
+ rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
+ NULL);
+ if (rc) {
+ pr_err("MDSS_EVENT_CONT_SPLASH_BEGIN event fail\n");
+ goto splash_on_err;
+ }
+ }
+
+ if (panel_info->type == MIPI_VIDEO_PANEL)
+ mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
+ else
+ mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+ return 0;
+
+splash_on_err:
+ mdp3_clk_enable(0);
+ return rc;
+}
+
+static int mdp3_panel_register_done(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+
+ if (pdata->panel_info.cont_splash_enabled) {
+ if (!mdp3_is_display_on(pdata)) {
+ pr_err("continuous splash, but bootloader is not\n");
+ return 0;
+ }
+ rc = mdp3_continuous_splash_on(pdata);
+ }
+ return rc;
+}
+
static int mdp3_probe(struct platform_device *pdev)
{
int rc;
@@ -1110,6 +1296,7 @@
.init_fnc = mdp3_init,
.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
.fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+ .panel_register_done = mdp3_panel_register_done,
.fb_stride = mdp3_fb_stride,
};
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index d29e5b6..03416c7 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -111,6 +111,9 @@
struct mdp3_iommu_domain_map *domains;
struct mdp3_iommu_ctx_map *iommu_contexts;
struct ion_handle *ion_handle;
+ void *virt;
+ unsigned long phys;
+ size_t size;
struct mdp3_dma dma[MDP3_DMA_MAX];
struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
@@ -151,7 +154,10 @@
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
int mdp3_iommu_enable(int client);
int mdp3_iommu_disable(int client);
+int mdp3_iommu_is_attached(int client);
void mdp3_fbmem_free(struct msm_fb_data_type *mfd);
+void mdp3_fbmem_clear(void);
+
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 7edf3d2..f77a2b3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -351,7 +351,11 @@
cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0;
} else
return -EINVAL;
- rc = mdp3_intf_init(intf, &cfg);
+
+ if (intf->config)
+ rc = intf->config(intf, &cfg);
+ else
+ rc = -EINVAL;
return rc;
}
@@ -390,7 +394,10 @@
(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
MDP3_DMA_OUTPUT_COMP_BITS_8;
- rc = mdp3_dma_init(dma, &sourceConfig, &outputConfig);
+ if (dma->dma_config)
+ rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
+ else
+ rc = -EINVAL;
return rc;
}
@@ -413,6 +420,11 @@
goto on_error;
}
+ if (mdp3_session->intf->active) {
+ pr_debug("continuous splash screen, initialized already\n");
+ goto on_error;
+ }
+
rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
if (rc) {
pr_err("fail to attach MDP DMA SMMU\n");
@@ -461,6 +473,8 @@
goto on_error;
}
+ mdp3_fbmem_clear();
+
if (panel->set_backlight)
panel->set_backlight(panel, panel->panel_info.bl_max);
@@ -671,6 +685,12 @@
return -EPERM;
}
+ if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ pr_debug("continuous splash screen, IOMMU not attached\n");
+ mdp3_ctrl_off(mfd);
+ mdp3_ctrl_on(mfd);
+ }
+
mutex_lock(&mdp3_session->lock);
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
@@ -715,6 +735,12 @@
return;
}
+ if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ pr_debug("continuous splash screen, IOMMU not attached\n");
+ mdp3_ctrl_off(mfd);
+ mdp3_ctrl_on(mfd);
+ }
+
mutex_lock(&mdp3_session->lock);
fbi = mfd->fbi;
@@ -1217,12 +1243,23 @@
goto init_done;
}
+ rc = mdp3_dma_init(mdp3_session->dma);
+ if (rc) {
+ pr_err("fail to init dma\n");
+ goto init_done;
+ }
+
intf_type = mdp3_ctrl_get_intf_type(mfd);
mdp3_session->intf = mdp3_get_display_intf(intf_type);
if (!mdp3_session->intf) {
rc = -ENODEV;
goto init_done;
}
+ rc = mdp3_intf_init(mdp3_session->intf);
+ if (rc) {
+ pr_err("fail to init interface\n");
+ goto init_done;
+ }
mdp3_session->mfd = mfd;
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 2e9c787..88eedb9 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -829,19 +829,14 @@
return ret;
}
-int mdp3_dma_init(struct mdp3_dma *dma,
- struct mdp3_dma_source *source_config,
- struct mdp3_dma_output_config *output_config)
+int mdp3_dma_init(struct mdp3_dma *dma)
{
int ret = 0;
pr_debug("mdp3_dma_init\n");
switch (dma->dma_sel) {
case MDP3_DMA_P:
- ret = mdp3_dmap_config(dma, source_config, output_config);
- if (ret < 0)
- return ret;
-
+ dma->dma_config = mdp3_dmap_config;
dma->config_cursor = mdp3_dmap_cursor_config;
dma->config_ccs = mdp3_dmap_ccs_config;
dma->config_histo = mdp3_dmap_histo_config;
@@ -855,10 +850,7 @@
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_S:
- ret = mdp3_dmas_config(dma, source_config, output_config);
- if (ret < 0)
- return ret;
-
+ dma->dma_config = mdp3_dmas_config;
dma->config_cursor = NULL;
dma->config_ccs = NULL;
dma->config_histo = NULL;
@@ -1029,10 +1021,9 @@
return 0;
}
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+int mdp3_intf_init(struct mdp3_intf *intf)
{
- int ret = 0;
- switch (cfg->type) {
+ switch (intf->cfg.type) {
case MDP3_DMA_OUTPUT_SEL_LCDC:
intf->config = lcdc_config;
intf->start = lcdc_start;
@@ -1052,16 +1043,5 @@
default:
return -EINVAL;
}
-
- intf->active = false;
- if (intf->config)
- ret = intf->config(intf, cfg);
-
- if (ret) {
- pr_err("MDP interface initialization failed\n");
- return ret;
- }
-
- intf->cfg = *cfg;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index c652818..e4a28dc 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -250,6 +250,10 @@
int histo_state;
struct mdp3_dma_histogram_data histo_data;
+ int (*dma_config)(struct mdp3_dma *dma,
+ struct mdp3_dma_source *source_config,
+ struct mdp3_dma_output_config *output_config);
+
int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -323,11 +327,9 @@
int (*stop)(struct mdp3_intf *intf);
};
-int mdp3_dma_init(struct mdp3_dma *dma,
- struct mdp3_dma_source *source_config,
- struct mdp3_dma_output_config *output_config);
+int mdp3_dma_init(struct mdp3_dma *dma);
-int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg);
+int mdp3_intf_init(struct mdp3_intf *intf);
void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e682e69..5f5084d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -44,6 +44,14 @@
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ if (ctrl->shared_pdata.broadcast_enable)
+ if (ctrl->panel_data.panel_info.pdest
+ == DISPLAY_1) {
+ pr_debug("%s: Broadcast mode enabled.\n",
+ __func__);
+ left_ctrl_pdata = ctrl;
+ }
+
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
ctrl->dsi_hw = &mdss_dsi0_hw;
@@ -861,13 +869,6 @@
else
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x14000000);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if (pdata->panel_info.pdest == DISPLAY_1) {
- pr_debug("%s: Broadcast mode enabled.\n",
- __func__);
- left_ctrl_pdata = ctrl_pdata;
- }
-
data = 0;
if (pinfo->te_sel)
data |= BIT(31);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ce6b805..ac87cbd 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -111,7 +111,7 @@
return ret;
}
- if (notify > NOTIFY_UPDATE_STOP)
+ if (notify > NOTIFY_UPDATE_POWER_OFF)
return -EINVAL;
if (notify == NOTIFY_UPDATE_START) {
@@ -119,12 +119,19 @@
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
to_user = mfd->update.value;
- } else {
+ } else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
to_user = mfd->no_update.value;
+ } else {
+ if (mfd->panel_power_on) {
+ INIT_COMPLETION(mfd->power_off_comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->power_off_comp, 1 * HZ);
+ }
}
+
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
@@ -649,6 +656,9 @@
if (!op_enable)
return -EPERM;
+ if (mfd->dcm_state == DCM_ENTER)
+ return -EPERM;
+
switch (blank_mode) {
case FB_BLANK_UNBLANK:
if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
@@ -690,6 +700,7 @@
else
mdss_fb_release_fences(mfd);
mfd->op_enable = true;
+ complete(&mfd->power_off_comp);
}
break;
}
@@ -1019,6 +1030,7 @@
mfd->ref_cnt = 0;
mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_UNINIT;
mdss_fb_parse_dt_split(mfd);
@@ -1037,6 +1049,7 @@
mfd->no_update.timer.data = (unsigned long)mfd;
init_completion(&mfd->update.comp);
init_completion(&mfd->no_update.comp);
+ init_completion(&mfd->power_off_comp);
init_completion(&mfd->commit_comp);
init_completion(&mfd->power_set_comp);
INIT_WORK(&mfd->commit_work, mdss_fb_commit_wq_handler);
@@ -1522,6 +1535,58 @@
return 0;
}
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
+{
+ int ret = -EINVAL;
+
+ if (req_state == mfd->dcm_state) {
+ pr_warn("Already in correct DCM state");
+ ret = 0;
+ }
+
+ switch (req_state) {
+ case DCM_UNBLANK:
+ if (mfd->dcm_state == DCM_UNINIT &&
+ !mfd->panel_power_on && mfd->mdp.on_fnc) {
+ ret = mfd->mdp.on_fnc(mfd);
+ if (ret == 0) {
+ mfd->panel_power_on = true;
+ mfd->dcm_state = DCM_UNBLANK;
+ }
+ }
+ break;
+ case DCM_ENTER:
+ if (mfd->dcm_state == DCM_UNBLANK) {
+ /* Keep unblank path available for only
+ DCM operation */
+ mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_ENTER;
+ ret = 0;
+ }
+ break;
+ case DCM_EXIT:
+ if (mfd->dcm_state == DCM_ENTER) {
+ /* Release the unblank path for exit */
+ mfd->panel_power_on = true;
+ mfd->dcm_state = DCM_EXIT;
+ ret = 0;
+ }
+ break;
+ case DCM_BLANK:
+ if ((mfd->dcm_state == DCM_EXIT ||
+ mfd->dcm_state == DCM_UNBLANK) &&
+ mfd->panel_power_on && mfd->mdp.off_fnc) {
+ ret = mfd->mdp.off_fnc(mfd);
+ if (ret == 0) {
+ mfd->panel_power_on = false;
+ mfd->dcm_state = DCM_UNINIT;
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
static int mdss_fb_cursor(struct fb_info *info, void __user *p)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 12f3d68..030fd67 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -124,6 +124,7 @@
struct disp_info_notify update;
struct disp_info_notify no_update;
+ struct completion power_off_comp;
struct msm_mdp_interface mdp;
@@ -145,6 +146,8 @@
void *msm_fb_backup;
struct completion power_set_comp;
u32 is_power_setting;
+
+ u32 dcm_state;
};
struct msm_fb_backup_type {
@@ -177,4 +180,5 @@
void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd);
void mdss_fb_signal_timeline(struct msm_fb_data_type *mfd);
int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
+int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c4f274f..4032b91 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1601,6 +1601,13 @@
if (ret)
return ret;
+ /* Supprt only MDP register read/write and
+ exit_dcm in DCM state*/
+ if (mfd->dcm_state == DCM_ENTER &&
+ (mdp_pp.op != mdp_op_calib_buffer &&
+ mdp_pp.op != mdp_op_calib_dcm_state))
+ return -EPERM;
+
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
ret = mdss_mdp_pa_config(mdp5_data->ctl,
@@ -1681,6 +1688,9 @@
(struct mdp_calib_config_buffer *)
&mdp_pp.data.calib_buffer, ©back);
break;
+ case mdp_op_calib_dcm_state:
+ ret = mdss_fb_dcm(mfd, mdp_pp.data.calib_dcm.dcm_state);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
mdp_pp.op);
@@ -1986,7 +1996,8 @@
if (!mfd->panel_info->cont_splash_enabled) {
rc = mdss_mdp_overlay_start(mfd);
- if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL))
+ if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL) &&
+ (mfd->panel_info->type != WRITEBACK_PANEL))
rc = mdss_mdp_overlay_kickoff(mfd);
} else {
rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 624046d..3f75053 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -162,6 +162,9 @@
int i;
int rc = 0, rot_mode = 0;
u32 nlines;
+ u16 width;
+
+ width = pipe->src.w >> pipe->horz_deci;
if (pipe->bwc_mode) {
rc = mdss_mdp_get_rau_strides(pipe->src.w, pipe->src.h,
@@ -172,11 +175,11 @@
ps.ystride[0], ps.ystride[1]);
} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
ps.num_planes = 2;
- ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
+ ps.ystride[0] = width;
ps.ystride[1] = ps.ystride[0];
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
- pipe->src.w, pipe->src.h, &ps, 0);
+ width, pipe->src.h, &ps, 0);
if (rc)
return rc;
@@ -184,7 +187,7 @@
rot_mode = 1;
else if (ps.num_planes == 1)
ps.ystride[0] = MAX_BPP *
- max(pipe->mixer->width, pipe->src.w);
+ max(pipe->mixer->width, width);
}
nlines = pipe->bwc_mode ? 1 : 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 9ae41df..0c74137 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -601,6 +601,12 @@
case MDP_ARGB_8888:
dst_format = WB_FORMAT_ARGB_8888;
break;
+ case MDP_BGRA_8888:
+ dst_format = WB_FORMAT_BGRA_8888;
+ break;
+ case MDP_BGRX_8888:
+ dst_format = WB_FORMAT_BGRX_8888;
+ break;
case MDP_Y_CBCR_H2V2_VENUS:
dst_format = WB_FORMAT_NV12;
break;
@@ -633,6 +639,12 @@
case WB_FORMAT_ARGB_8888:
ctl->dst_format = MDP_ARGB_8888;
break;
+ case WB_FORMAT_BGRA_8888:
+ ctl->dst_format = MDP_BGRA_8888;
+ break;
+ case WB_FORMAT_BGRX_8888:
+ ctl->dst_format = MDP_BGRX_8888;
+ break;
case WB_FORMAT_NV12:
ctl->dst_format = MDP_Y_CBCR_H2V2_VENUS;
break;
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 72961c3..cd141a4 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -96,4 +96,10 @@
}
#endif /* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif /* CONFIG_PANIC_ON_DATA_CORRUPTION */
#endif /* _LINUX_BUG_H */
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 73016d6..d121695 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,8 +35,11 @@
* struct synaptics_rmi4_platform_data - rmi4 platform data
* @x_flip: x flip flag
* @y_flip: y flip flag
+ * @i2c_pull_up: pull up i2c bus with regulator
+ * @power_down_enable: enable complete regulator shutdown in suspend
* @irq_gpio: attention interrupt gpio
* @irq_flags: flags used by the irq
+ * @reset_flags: flags used by reset line
* @reset_gpio: reset gpio
* @panel_x: panel maximum values on the x
* @panel_y: panel maximum values on the y
@@ -47,6 +50,7 @@
bool x_flip;
bool y_flip;
bool i2c_pull_up;
+ bool power_down_enable;
unsigned irq_gpio;
u32 irq_flags;
u32 reset_flags;
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 72e31b2..94d8245 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -241,6 +241,7 @@
struct sdhci_next next_data;
ktime_t data_start_time;
+ struct mutex ios_mutex;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index c3ff9de..2455212 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -87,6 +87,7 @@
enum {
NOTIFY_UPDATE_START,
NOTIFY_UPDATE_STOP,
+ NOTIFY_UPDATE_POWER_OFF,
};
enum {
@@ -612,6 +613,19 @@
uint32_t *buffer;
};
+struct mdp_calib_dcm_state {
+ uint32_t ops;
+ uint32_t dcm_state;
+};
+
+enum {
+ DCM_UNINIT,
+ DCM_UNBLANK,
+ DCM_ENTER,
+ DCM_EXIT,
+ DCM_BLANK,
+};
+
#define MDSS_MAX_BL_BRIGHTNESS 255
#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
@@ -704,6 +718,7 @@
mdp_op_ad_input,
mdp_op_calib_mode,
mdp_op_calib_buffer,
+ mdp_op_calib_dcm_state,
mdp_op_max,
};
@@ -713,6 +728,8 @@
WB_FORMAT_RGB_888,
WB_FORMAT_xRGB_8888,
WB_FORMAT_ARGB_8888,
+ WB_FORMAT_BGRA_8888,
+ WB_FORMAT_BGRX_8888,
WB_FORMAT_ARGB_8888_INPUT_ALPHA /* Need to support */
};
@@ -732,6 +749,7 @@
struct mdss_calib_cfg mdss_calib_cfg;
struct mdss_ad_input ad_input;
struct mdp_calib_config_buffer calib_buffer;
+ struct mdp_calib_dcm_state calib_dcm;
} data;
};
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index f1a6e9e..90fd57d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,6 +41,7 @@
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
+#include <linux/bug.h>
#include "workqueue_sched.h"
@@ -1878,6 +1879,7 @@
printk(KERN_ERR " last function: ");
print_symbol("%s\n", (unsigned long)f);
debug_show_held_locks(current);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 097d70f..b9060a1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1290,6 +1290,13 @@
If unsure, say N.
+config PANIC_ON_DATA_CORRUPTION
+ bool "Cause a Kernel Panic When Data Corruption is detected"
+ help
+ Select this option to upgrade warnings for potentially
+ recoverable data corruption scenarios to system-halting panics,
+ for easier detection and debug.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 982b850..6a039a6 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -10,6 +10,7 @@
#include <linux/list.h>
#include <linux/bug.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
/*
* Insert a new entry between two known consecutive entries.
@@ -30,6 +31,10 @@
"list_add corruption. prev->next should be "
"next (%p), but was %p. (prev=%p).\n",
next, prev->next, prev);
+
+ BUG_ON(((prev->next != next) || (next->prev != prev)) &&
+ PANIC_CORRUPTION);
+
next->prev = new;
new->next = next;
new->prev = prev;
@@ -55,8 +60,10 @@
"but was %p\n", entry, prev->next) ||
WARN(next->prev != entry,
"list_del corruption. next->prev should be %p, "
- "but was %p\n", entry, next->prev))
+ "but was %p\n", entry, next->prev)) {
+ BUG_ON(PANIC_CORRUPTION);
return;
+ }
__list_del(prev, next);
}
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index f2aa5de..ac516f4 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -12,6 +12,7 @@
#include <linux/debug_locks.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/bug.h>
void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
struct lock_class_key *key)
@@ -64,6 +65,7 @@
owner ? owner->comm : "<none>",
owner ? task_pid_nr(owner) : -1,
lock->owner_cpu);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index d02713a..b2dca68 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -627,6 +627,8 @@
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOICE2)
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_QCHAT)
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -1914,6 +1916,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1932,6 +1937,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
@@ -1950,6 +1958,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1971,6 +1982,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1992,6 +2006,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -2013,6 +2030,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -2034,6 +2054,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -2055,6 +2078,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -2073,6 +2099,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -2094,6 +2123,9 @@
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -2243,6 +2275,33 @@
msm_routing_put_voice_stub_mixer),
};
+static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_QCHAT", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_QCHAT",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_QCHAT", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_QCHAT", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_QCHAT", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -2831,6 +2890,8 @@
/* LSM */
SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
*/
@@ -3065,6 +3126,9 @@
SND_SOC_DAPM_MIXER("PRI_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
primary_mi2s_rx_port_mixer_controls,
ARRAY_SIZE(primary_mi2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
+ ARRAY_SIZE(tx_qchat_mixer_controls)),
/* Virtual Pins to force backends ON atm */
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_INPUT("BE_IN"),
@@ -3266,6 +3330,7 @@
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3273,6 +3338,7 @@
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3280,6 +3346,7 @@
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3287,6 +3354,7 @@
{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3295,6 +3363,7 @@
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIM_0_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3302,6 +3371,7 @@
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3309,6 +3379,7 @@
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3317,6 +3388,7 @@
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3324,6 +3396,7 @@
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3331,6 +3404,7 @@
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
{"HDMI", NULL, "HDMI_DL_HL"},
@@ -3339,6 +3413,7 @@
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
@@ -3398,6 +3473,16 @@
{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM_UL_HL", NULL, "LSM1 MUX"},
+ {"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
+ {"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
+ {"QCHAT_Tx Mixer", "INTERNAL_BT_SCO_TX_QCHAT", "INT_BT_SCO_TX"},
+ {"QCHAT_Tx Mixer", "AFE_PCM_TX_QCHAT", "PCM_TX"},
+ {"QCHAT_Tx Mixer", "AUX_PCM_TX_QCHAT", "AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "SEC_AUX_PCM_TX_QCHAT", "SEC_AUX_PCM_TX"},
+ {"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"},
+ {"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"},
+ {"QCHAT_UL", NULL, "QCHAT_Tx Mixer"},
+
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4ce0db5..10be150 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -81,6 +81,7 @@
MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_LSM1,
MSM_FRONTEND_DAI_VOICE2,
+ MSM_FRONTEND_DAI_QCHAT,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 053375e..7aea1a5 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -51,7 +51,7 @@
.fifo_size = 0,
};
-static int is_volte(struct msm_voice *pvolte)
+static bool is_volte(struct msm_voice *pvolte)
{
if (pvolte == &voice_info[VOLTE_SESSION_INDEX])
return true;
@@ -59,7 +59,7 @@
return false;
}
-static int is_voice2(struct msm_voice *pvoice2)
+static bool is_voice2(struct msm_voice *pvoice2)
{
if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
return true;
@@ -67,6 +67,14 @@
return false;
}
+static bool is_qchat(struct msm_voice *pqchat)
+{
+ if (pqchat == &voice_info[QCHAT_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
static uint32_t get_session_id(struct msm_voice *pvoc)
{
uint32_t session_id = 0;
@@ -75,6 +83,8 @@
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
else if (is_voice2(pvoc))
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
+ else if (is_qchat(pvoc))
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
@@ -120,6 +130,10 @@
voice = &voice_info[VOICE2_SESSION_INDEX];
pr_debug("%s: Open Voice2 Substream Id=%s\n",
__func__, substream->pcm->id);
+ } else if (!strncmp("QCHAT", substream->pcm->id, 5)) {
+ voice = &voice_info[QCHAT_SESSION_INDEX];
+ pr_debug("%s: Open QCHAT Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index 5425c46..f199be6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -17,6 +17,7 @@
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
VOICE2_SESSION_INDEX,
+ QCHAT_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 147530c..a21bff0 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -208,6 +208,9 @@
} else if (session_id ==
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
session_name = VOLTE_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
+ session_name = QCHAT_SESSION_NAME;
} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
session_name = VOIP_SESSION_NAME;
}
@@ -227,6 +230,9 @@
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+ else if (!strncmp(name, "QCHAT session", 13))
+ session_id =
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
else
session_id = common.voice[VOC_PATH_FULL].session_id;
@@ -258,6 +264,10 @@
v = &common.voice[VOC_PATH_FULL];
break;
+ case QCHAT_SESSION_VSID:
+ v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
+ break;
+
case ALL_SESSION_VSID:
break;
@@ -294,6 +304,10 @@
idx = VOC_PATH_FULL;
break;
+ case QCHAT_SESSION_VSID:
+ idx = VOC_PATH_QCHAT_PASSIVE;
+ break;
+
case ALL_SESSION_VSID:
idx = MAX_VOC_SESSIONS - 1;
break;
@@ -313,11 +327,6 @@
NULL : &common.voice[idx]);
}
-static bool is_voice_session(u32 session_id)
-{
- return (session_id == common.voice[VOC_PATH_PASSIVE].session_id);
-}
-
static bool is_voip_session(u32 session_id)
{
return (session_id == common.voice[VOC_PATH_FULL].session_id);
@@ -333,6 +342,11 @@
return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
+static bool is_qchat_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
+}
+
static bool is_voc_state_active(int voc_state)
{
if ((voc_state == VOC_RUN) ||
@@ -369,6 +383,7 @@
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id = VOLTE_SESSION_VSID;
common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
+ common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
}
static int voice_apr_register(void)
@@ -493,10 +508,8 @@
pr_err("%s: apr_mvm is NULL.\n", __func__);
return -EINVAL;
}
- pr_debug("%s: VoLTE command to MVM\n", __func__);
- if (is_volte_session(v->session_id) ||
- is_voice_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ pr_debug("%s: Send Dual Control command to MVM\n", __func__);
+ if (!is_voip_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -570,9 +583,7 @@
/* send cmd to create mvm session and wait for response */
if (!mvm_handle) {
- if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ if (!is_voip_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -597,6 +608,10 @@
strlcpy(mvm_session_cmd.mvm_session.name,
VOICE2_SESSION_VSID_STR,
sizeof(mvm_session_cmd.mvm_session.name));
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ QCHAT_SESSION_VSID_STR,
+ sizeof(mvm_session_cmd.mvm_session.name));
} else {
strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
@@ -659,9 +674,7 @@
}
/* send cmd to create cvs session */
if (!cvs_handle) {
- if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id) ||
- is_voice2_session(v->session_id)) {
+ if (!is_voip_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -687,6 +700,10 @@
strlcpy(cvs_session_cmd.cvs_session.name,
VOICE2_SESSION_VSID_STR,
sizeof(cvs_session_cmd.cvs_session.name));
+ } else if (is_qchat_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ QCHAT_SESSION_VSID_STR,
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
@@ -875,7 +892,9 @@
}
}
- if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+ if (is_voip_session(v->session_id) ||
+ is_qchat_session(v->session_id) ||
+ v->voc_state == VOC_ERROR) {
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -4536,6 +4555,11 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4679,6 +4703,11 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
@@ -4951,6 +4980,11 @@
v = voice_get_session(session_id);
if (v != NULL)
v->voc_state = VOC_ERROR;
+
+ session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ v = voice_get_session(session_id);
+ if (v != NULL)
+ v->voc_state = VOC_ERROR;
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index b3a98e2..9e2cfd7 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1309,7 +1309,7 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 4
+#define MAX_VOC_SESSIONS 5
struct common_data {
/* these default values are for all devices */
@@ -1372,18 +1372,22 @@
#define VOC_PATH_FULL 1
#define VOC_PATH_VOLTE_PASSIVE 2
#define VOC_PATH_VOICE2_PASSIVE 3
+#define VOC_PATH_QCHAT_PASSIVE 4
#define MAX_SESSION_NAME_LEN 32
#define VOICE_SESSION_NAME "Voice session"
#define VOIP_SESSION_NAME "VoIP session"
#define VOLTE_SESSION_NAME "VoLTE session"
#define VOICE2_SESSION_NAME "Voice2 session"
+#define QCHAT_SESSION_NAME "QCHAT session"
#define VOICE2_SESSION_VSID_STR "10DC1000"
+#define QCHAT_SESSION_VSID_STR "10803000"
#define VOICE_SESSION_VSID 0x10C01000
#define VOICE2_SESSION_VSID 0x10DC1000
#define VOLTE_SESSION_VSID 0x10C02000
#define VOIP_SESSION_VSID 0x10004000
+#define QCHAT_SESSION_VSID 0x10803000
#define ALL_SESSION_VSID 0xFFFFFFFF
#define VSID_MAX ALL_SESSION_VSID