Merge "defconfig: remove support for /dev/mem and /dev/kmem on perf builds"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 3947f75..15b94ca 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -43,6 +43,29 @@
- qcpm,cpu-sensors: List of type names in thermal zone device struct which maps
to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
cpus there are.
+- qcom,freq-mitigation-temp: Threshold temperature to mitigate
+ the CPU max frequency in degC. This will be
+ used when polling based frequency control is disabled.
+ The difference between freq-mitigation-temp
+ and limit-temp is that limit-temp is used during
+ early boot prior to thermal_sys being available for registering
+ temperature thresholds. Also, this emergency frequency
+ mitigation is a single step frequency mitigation to a predefined value
+ as opposed to the step by step frequency mitigation during boot-up.
+- qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the
+ cpu max frequency.
+- qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal
+ should mitigate the CPU, when the freq-mitigation-temp
+ threshold is reached.
+- qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be
+ used to determine if KTM should do emergency frequency
+ mitigation for a core or not. A mask of 0x00 indicates the
+ mitigation is disabled for all the cores and a mask of 0x05
+ indicates this mitigation is enabled for cpu-0 and cpu-2.
+ Note: For KTM's frequency mitigation to work, the data for all the
+ above four properties (qcom,freq-mitigation-temp; qcom,
+ freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and
+ qcom,freq-mitigation-control-mask) should be populated.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
enable vdd restriction which will set higher voltage on
key voltage rails, in degC.
@@ -67,6 +90,20 @@
phandle_of_regulator is defined by reuglator device tree.
Optional child nodes
+- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
+ dual phase) for rails with PMIC, in degC. If this property exists,
+ then the properties, qti,pmic-opt-curr-temp-hysteresis and
+ qti,pmic-opt-curr-regs should also be defined to enable this
+ feature.
+- qti,pmic-opt-curr-temp-hysteresis: Degree below the threshold to disable the optimum
+ current request for a rail, in degC. If this property exists,
+ then the properties, qti,pmic-opt-curr-temp and
+ qti,pmic-opt-curr-regs should also be defined to enable
+ this feature.
+- qti,pmic-opt-curr-regs: Name of the rails for which the optimum current should be
+ requested. If this property exists, then the properties,
+ qti,pmic-opt-curr-temp and qti,pmic-opt-curr-temp-hysteresis
+ should also be defined to enable this feature.
- qcom,<vdd restriction child node name>: Define the name of the child node.
If this property exisits, qcom,vdd-rstr-reg, qcom,levels
need to exist. qcom,min-level is optional if qcom,freq-req
@@ -97,11 +134,18 @@
qcom,hotplug-temp-hysteresis = <20>;
qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
"tsens_tz_sensor7", "tsens_tz_sensor8";
+ qcom,freq-mitigation-temp = <110>;
+ qcom,freq-mitigation-temp-hysteresis = <20>;
+ qcom,freq-mitigation-value = <960000>;
+ qcom,freq-mitigation-control-mask = <0x01>;
qcom,pmic-sw-mode-temp = <90>;
qcom,pmic-sw-mode-temp-hysteresis = <80>;
qcom,pmic-sw-mode-regs = "vdd-dig";
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-temp = <85>;
+ qti,pmic-opt-curr-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-regs = "vdd-dig";
vdd-dig-supply=<&pm8841_s2_floor_corner>
qcom,vdd-dig-rstr{
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 56bdc59..a77b5ff 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -102,6 +102,12 @@
- compatible : "qcom,msm-lsm-client"
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qti,msm-pcm-loopback"
+
* msm-dai-q6
[First Level Nodes]
diff --git a/Makefile b/Makefile
index be32c2f..0c11d69 100644
--- a/Makefile
+++ b/Makefile
@@ -864,6 +864,7 @@
# Generate .S file with all kernel symbols
quiet_cmd_kallsyms = KSYM $@
cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+ --page-offset=$(CONFIG_PAGE_OFFSET) \
$(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 8c79bb9..25e5072 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -17,7 +17,7 @@
*---------------------------------------------------------------------------*/
&mdss_mdp {
dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
- qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+ qcom,mdss-dsi-panel-name = "hx8389b qhd video mode dsi panel";
qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
qcom,mdss-dsi-panel-type = "dsi_video_mode";
qcom,mdss-dsi-panel-destination = "display_1";
@@ -26,89 +26,35 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <540>;
qcom,mdss-dsi-panel-height = <960>;
- qcom,mdss-dsi-h-front-porch = <48>;
- qcom,mdss-dsi-h-back-porch = <96>;
- qcom,mdss-dsi-h-pulse-width = <96>;
+ qcom,mdss-dsi-h-front-porch = <60>;
+ qcom,mdss-dsi-h-back-porch = <39>;
+ qcom,mdss-dsi-h-pulse-width = <39>;
qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-v-front-porch = <9>;
qcom,mdss-dsi-v-pulse-width = <3>;
- qcom,mdss-dsi-v-back-porch = <13>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
qcom,mdss-dsi-v-bottom-border = <0>;
qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = <0>;
qcom,mdss-dsi-underflow-color = <0xff>;
qcom,mdss-dsi-border-color = <0>;
- qcom,mdss-dsi-on-command = [
- 39 01 00 00 00 00 04
- B9 FF 83 89
- 39 01 00 00 00 00 08
- BA 41 93 00
- 16 A4 10 18
- 23 01 00 00 00 00 02
- C6 08
- 39 01 00 00 00 00 03
- BC 02 00
- 23 01 00 00 00 00 02
- CC 02
- 39 01 00 00 00 00 14
- B1 00 00 07
- E8 50 10 11
- 98 f8 21 29
- 27 27 43 01
- 58 F0 00 E6
- 39 01 00 00 00 00 08
- B2 00 00 78
- 0C 07 3F 80
- 39 01 00 00 00 00 18
- b4 82 08 00
- 32 10 04 32
- 10 00 32 10
- 00 37 0a 40
- 08 37 0a 40
- 14 46 50 0a
- 39 01 00 00 00 00 39
- d5 00 00 00
- 00 01 00 00
- 00 60 00 99
- 88 AA BB 88
- 23 88 01 88
- 67 88 45 01
- 23 88 88 88
- 88 88 88 99
- BB AA 88 54
- 88 76 88 10
- 88 32 32 10
- 88 88 88 88
- 88 00 04 00
- 00 00 00 00
- 00
- 39 01 00 00 00 00 03
- CB 07 07
- 39 01 00 00 00 00 05
- BB 00 00 FF
- 80
- 39 01 00 00 00 00 04
- DE 05 58 10
- 39 01 00 00 00 00 05
- B6 00 8A 00
- 8A
- 39 01 00 00 00 00 23
- E0 01 08 0C
- 1F 25 36 12
- 35 05 09 0D
- 10 11 0F 0F
- 1C 1D 01 08
- 0C 1F 25 36
- 12 35 05 09
- 0D 10 11 0F
- 0F 1C 1D
- 05 01 00 00 96 00 02
- 11 00
- 05 01 00 00 96 00 02
- 29 00
- ];
+ qcom,mdss-dsi-on-command = [39 01 00 00 0A 00 04 B9 FF 83 89
+ 15 01 00 00 01 00 02 CC 02
+ 39 01 00 00 01 00 03 C0 43 17
+ 39 01 00 00 01 00 08 BA 41 93 00 16 A4 10 18
+ 39 01 00 00 01 00 14 B1 00 00 06 EB 59 10 11 EE EE 3A 42 3F 3F 43 01 5A F6 00 E6
+ 39 01 00 00 01 00 08 B2 00 00 78 0C 07 3F 80
+ 39 01 00 00 01 00 04 b7 00 00 50
+ 39 01 00 00 01 00 18 B4 80 08 00 32 10 04 32 10 00 32 10 00 37 0a 40 08 37 00 46 02 58 58 02
+ 39 01 00 00 01 00 39 D5 00 00 00 00 01 00 00 00 60 00 99 88 AA BB 88 23 88 01 88 67 88 45 01 23 88 88 88 88 88 88 99 BB AA 88 54 88 76 88 10 88 32 32 10 88 88 88 88 88 3C 04 00 00 00 00 00 00
+ 39 01 00 00 01 00 23 E0 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18
+ 39 01 00 00 05 00 80 C1 01 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0
+ 39 01 00 00 01 00 05 B6 00 88 00 88
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
@@ -120,7 +66,7 @@
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
- qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+ qcom,mdss-dsi-panel-timings = [87 1E 14 00 44 4B 19 21 22 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <26>;
@@ -129,6 +75,5 @@
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
-
};
};
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 38ca03b..a1a8480 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -160,7 +160,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index a0da9cc..2e9f6db 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -162,7 +162,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index d63c6e5..04eca14 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -143,7 +143,11 @@
"MIC BIAS External", "Handset Mic",
"MIC BIAS Internal2", "Headset Mic",
"AMIC1", "MIC BIAS External",
- "AMIC2", "MIC BIAS Internal2";
+ "AMIC2", "MIC BIAS Internal2",
+ "MIC BIAS External", "Digital Mic1",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC1", "MIC BIAS External",
+ "DMIC2", "MIC BIAS External";
qcom,headset-jack-type-NC;
};
};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index e5aa53c..ea37413 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -160,7 +160,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index c819c49..19fb185 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -162,7 +162,7 @@
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
- qcom,min-cpu-mode= "spc";
+ qcom,min-cpu-mode= "standalone_pc";
qcom,sync-cpus;
};
@@ -198,24 +198,40 @@
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<2 216>, /* tsens_upper_lower_int */
<41 63>, /* dino_gen_purpose_irq35 */
+ <0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */
+ <0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtmr_phy_irq[0] */
+ <0xff 47>, /* rbif_irq[0] */
<0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
+ <0xff 65>, /* o_gc_sys_irq[0] */
+ <0xff 74>, /* venus0_mmu_cirpt[1] */
+ <0xff 75>, /* venus0_mmu_cirpt[0] */
+ <0xff 78>, /* mdss_mmu_cirpt[0] */
+ <0xff 79>, /* mdss_mmu_cirpt[1] */
+ <0xff 97>, /* camss_vfe_mmu_cirpt[1] */
+ <0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 131>, /* blsp1_qup_5_irq */
+ <0xff 141>, /* blsp1_uart_3_irq */
+ <0xff 155>, /* sdc1_irq(0) */
+ <0xff 157>, /* sdc2_irq(0) */
+ <0xff 161>, /* lpass_irq_out_spare[4] */
+ <0xff 162>, /* lpass_irq_out_spare[5]*/
+ <0xff 170>, /* sdc1_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
<0xff 176>, /* o_wcss_apss_smsm_irq */
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
- <0xff 179>, /* o_wcss_apss_asic_intr
+ <0xff 179>, /* o_wcss_apss_asic_intr */
<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
- <0xff 161>, /* lpass_irq_out_spare[4] /
- <0xff 162>, /* lpass_irq_out_spare[5]*/
- <0xff 234>, /* lpass_irq_out_spare[6]*/
- <0xff 235>, /* lpass_irq_out_spare[7]*/
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -230,12 +246,16 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
+ <0xff 234>, /* lpass_irq_out_spare[6]*/
+ <0xff 235>, /* lpass_irq_out_spare[7]*/
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 253>, /* sdc2_pwr_cmd_irq */
<0xff 258>, /* rpm_ipc(28) */
<0xff 259>, /* rpm_ipc(29) */
- <0xff 275>, /* rpm_ipc(30) */
- <0xff 276>, /* rpm_ipc(31) */
<0xff 269>, /* rpm_wdog_expired_irq */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 270>, /* blsp1_bam_irq[0] */
+ <0xff 275>, /* rpm_ipc(30) */
+ <0xff 276>; /* rpm_ipc(31) */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 1>,
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 2ff92ed..b4a3e55 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1684,6 +1684,10 @@
compatible = "qcom,msm-lsm-client";
};
+ qti,msm-pcm-loopback {
+ compatible = "qti,msm-pcm-loopback";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -2179,6 +2183,10 @@
qcom,hotplug-temp-hysteresis = <20>;
qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
"tsens_tz_sensor7", "tsens_tz_sensor8";
+ qcom,freq-mitigation-temp = <110>;
+ qcom,freq-mitigation-temp-hysteresis = <20>;
+ qcom,freq-mitigation-value = <960000>;
+ qcom,freq-mitigation-control-mask = <0x01>;
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
qcom,pmic-sw-mode-temp = <85>;
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 366faef..938a2cc 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -214,6 +214,7 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 33>, /*l2_perf_mon*/
<0xff 34>, /* APCC_qgicL2ErrorIrptReq */
<0xff 35>, /* WDT_barkInt */
<0xff 40>, /* qtimer_phy_irq */
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index 2693642..71fbeae 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -152,6 +152,9 @@
qcom,msm-thermal {
vdd-dig-supply = <&pma8084_s2_floor_corner>;
vdd-gfx-supply = <&pma8084_s7_floor_corner>;
+ qti,pmic-opt-curr-temp = <85>;
+ qti,pmic-opt-curr-temp-hysteresis = <10>;
+ qti,pmic-opt-curr-regs = "vdd-dig";
/delete-property/ qcom,pmic-sw-mode-temp;
/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
/delete-property/ qcom,pmic-sw-mode-regs;
@@ -180,6 +183,10 @@
qcom,use-phase-switching;
};
+&mdss_mdp {
+ vdd-cx-supply = <&pma8084_s2_corner>;
+};
+
&tspp {
vdd_cx-supply = <&pma8084_s2_corner>;
};
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 14ddc4e..1e32cfa 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -457,7 +457,6 @@
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
CONFIG_MSM_RDBG=m
CONFIG_DEVMEM=n
CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index f672cc0..cedb6dc 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -511,5 +511,4 @@
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
-CONFIG_DEFAULT_ROW=y
CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index a779688..939dc82 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -320,6 +320,7 @@
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 0a48930..ff0c498 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -343,6 +343,7 @@
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_MDP3=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 97f5532..10f2919 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,6 +98,7 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c106913..0b9ba76 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -104,6 +104,7 @@
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 03f8837..affe6bd 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -631,6 +631,28 @@
},
};
+static struct gpiomux_setting gpio_cdc_dmic_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_cdc_dmic_configs[] __initdata = {
+ {
+ .gpio = 100, /* DMIC CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+ {
+ .gpio = 101, /* DMIC DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -668,4 +690,7 @@
msm_gpiomux_install(msm_non_qrd_configs,
ARRAY_SIZE(msm_non_qrd_configs));
}
+ if (of_board_is_cdp())
+ msm_gpiomux_install(msm_cdc_dmic_configs,
+ ARRAY_SIZE(msm_cdc_dmic_configs));
}
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index fac6575..a910cd26 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -63,9 +63,13 @@
if (!dev)
return -ENODEV;
+ /* Add check for user buf count greater than RD_BUF_SIZE */
+ if (count > RD_BUF_SIZE)
+ count = RD_BUF_SIZE;
+
if (copy_from_user(dev->buf, ubuf, count)) {
pr_err("error copying for writing");
- return 0;
+ return -EFAULT;
}
ret = hsic_sysmon_write(id, dev->buf, count, 1000);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 2e15cae..9a27fd2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -73,7 +73,8 @@
#define USF_TSC_PTR_EVENT_IND 1
#define USF_MOUSE_EVENT_IND 2
#define USF_KEYBOARD_EVENT_IND 3
-#define USF_MAX_EVENT_IND 4
+#define USF_TSC_EXT_EVENT_IND 4
+#define USF_MAX_EVENT_IND 5
/* Types of events, produced by the calculators */
#define USF_NO_EVENT 0
@@ -81,10 +82,12 @@
#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT (1 << USF_TSC_EXT_EVENT_IND)
#define USF_ALL_EVENTS (USF_TSC_EVENT |\
USF_TSC_PTR_EVENT |\
USF_MOUSE_EVENT |\
- USF_KEYBOARD_EVENT)
+ USF_KEYBOARD_EVENT |\
+ USF_TSC_EXT_EVENT)
/* min, max array dimension */
#define MIN_MAX_DIM 2
@@ -146,6 +149,8 @@
int tsc_y_tilt[MIN_MAX_DIM];
/* Touch screen pressure limits: min & max; for input module */
int tsc_pressure[MIN_MAX_DIM];
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
uint16_t event_types;
/* Input event source */
@@ -174,6 +179,8 @@
int inclinations[TILTS_DIM];
/* [0-1023] (10bits); 0 - pen up */
uint32_t pressure;
+/* Bitmap for side button state. 1 - down, 0 - up */
+ uint16_t side_buttons_state_bitmap;
};
/* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index b707df1..b9dcf88 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -291,7 +291,7 @@
system_level->num_cpu_votes != num_powered_cores)
continue;
- if (latency_us < pwr_param->latency_us)
+ if (latency_us < pwr_param->latency_us && from_idle)
continue;
if (sleep_us < pwr_param->time_overhead_us)
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index ac4ed25..c4e52be 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -36,72 +36,132 @@
struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
};
+static struct msm_pm_time_stats suspend_stats;
+
static DEFINE_SPINLOCK(msm_pm_stats_lock);
static DEFINE_PER_CPU_SHARED_ALIGNED(
struct msm_pm_cpu_time_stats, msm_pm_stats);
-
/*
- * Add the given time data to the statistics collection.
+ * Function to update stats
*/
-void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+static void update_stats(struct msm_pm_time_stats *stats, int64_t t)
{
- unsigned long flags;
- struct msm_pm_time_stats *stats;
int64_t bt;
int i;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats)
+ return;
- if (!stats[id].enabled)
- goto add_bail;
-
- stats[id].total_time += t;
- stats[id].count++;
+ stats->total_time += t;
+ stats->count++;
bt = t;
- do_div(bt, stats[id].first_bucket_time);
+ do_div(bt, stats->first_bucket_time);
if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
else
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
- stats[id].bucket[i]++;
+ stats->bucket[i]++;
- if (t < stats[id].min_time[i] || !stats[id].max_time[i])
- stats[id].min_time[i] = t;
- if (t > stats[id].max_time[i])
- stats[id].max_time[i] = t;
+ if (t < stats->min_time[i] || !stats->max_time[i])
+ stats->min_time[i] = t;
+ if (t > stats->max_time[i])
+ stats->max_time[i] = t;
+}
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ struct msm_pm_time_stats *stats;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ if (id == MSM_PM_STAT_SUSPEND) {
+ stats = &suspend_stats;
+ } else {
+ stats = __get_cpu_var(msm_pm_stats).stats;
+ if (!stats[id].enabled)
+ goto add_bail;
+ stats = &stats[id];
+ }
+ update_stats(stats, t);
add_bail:
spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-/*
- * Write out the power management statistics.
- */
-
-static int msm_pm_stats_show(struct seq_file *m, void *v)
+static void stats_show(struct seq_file *m,
+ struct msm_pm_time_stats *stats,
+ int cpu, int suspend)
{
- int cpu;
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+ int i;
int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- for_each_possible_cpu(cpu) {
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i, id;
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
+ if (!stats || !m)
+ return;
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ s = stats->total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ if (suspend)
+ seq_printf(m,
+ "%s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ stats->name,
+ stats->count,
+ s, ns);
+ else
+ seq_printf(m,
+ "[cpu %u] %s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ cpu, stats->name,
+ stats->count,
+ s, ns);
+
+ bucket_time = stats->first_bucket_time;
+ for (i = 0; i < bucket_count; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ seq_printf(m,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+ bucket_time <<= bucket_shift;
+ }
+
+ seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats->bucket[i],
+ stats->min_time[i],
+ stats->max_time[i]);
+}
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_stats_show(struct seq_file *m, void *v)
+{
+ int cpu;
+ int id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+
+ for_each_possible_cpu(cpu) {
+ struct msm_pm_time_stats *stats;
+
stats = per_cpu(msm_pm_stats, cpu).stats;
for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
@@ -109,38 +169,14 @@
if (!stats[id].enabled)
continue;
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
+ if (id == MSM_PM_STAT_SUSPEND)
+ continue;
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < bucket_count; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- seq_printf(m,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- bucket_time <<= bucket_shift;
- }
-
- seq_printf(m, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
+ stats_show(m, &stats[id], cpu, false);
}
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
}
-
+ stats_show(m, &suspend_stats, cpu, true);
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
return 0;
}
@@ -259,14 +295,6 @@
first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
- stats[MSM_PM_STAT_SUSPEND].name = "suspend";
- stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
- stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
@@ -275,6 +303,9 @@
stats[enable_stats[i]].enabled = true;
}
+ suspend_stats.name = "system_suspend";
+ suspend_stats.first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
d_entry = proc_create_data("msm_pm_stats", S_IRUGO | S_IWUSR | S_IWGRP,
NULL, &msm_pm_stats_fops, NULL);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index bf47366..7ab4ec3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -26,6 +26,8 @@
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
#define FORMAT_USPROX 0x00000002
+#define FORMAT_USGES_SYNC 0x00000003
+#define FORMAT_USRAW_SYNC 0x00000004
#define INVALID_FORMAT 0xffffffff
#define IN 0x000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..e6b1324 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.4.2"
-#define USF_VERSION_ID 0x0142
+#define DRV_VERSION "1.5.1"
+#define USF_VERSION_ID 0x0151
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -57,6 +57,8 @@
/* Place for US detection result, received from QDSP6 */
#define APR_US_DETECT_RESULT_IND 0
+#define BITS_IN_BYTE 8
+
/* The driver states */
enum usf_state_type {
USF_IDLE_STATE,
@@ -117,6 +119,8 @@
uint16_t conflicting_event_types;
/* Bitmap of types of events from devs, conflicting with USF */
uint16_t conflicting_event_filters;
+ /* The requested side buttons bitmap */
+ uint16_t req_side_buttons_bitmap;
};
struct usf_input_dev_type {
@@ -146,6 +150,12 @@
0, /* US_INPUT_SRC_UNDEF */
};
+/* Supported buttons container */
+static const int s_button_map[] = {
+ BTN_STYLUS,
+ BTN_STYLUS2
+};
+
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
@@ -176,14 +186,35 @@
struct us_input_info_type *input_info,
const char *name)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(input_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+ uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
struct input_dev *in_dev = allocate_dev(ind, name);
-
if (in_dev == NULL)
return -ENOMEM;
+ if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
+ pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+ __func__,
+ input_info->req_side_buttons_bitmap,
+ max_side_button_bitmap);
+ return -EINVAL;
+ }
+
usf_info->input_ifs[ind] = in_dev;
+ usf_info->req_side_buttons_bitmap =
+ input_info->req_side_buttons_bitmap;
in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+
+ for (i = 0; i < num_side_buttons; i++)
+ if (input_info->req_side_buttons_bitmap & (1 << i))
+ in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+ BIT_MASK(s_button_map[i]);
+
input_set_abs_params(in_dev, ABS_X,
input_info->tsc_x_dim[MIN_IND],
input_info->tsc_x_dim[MAX_IND],
@@ -260,6 +291,11 @@
struct usf_event_type *event)
{
+ int i = 0;
+ int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+ sizeof(usf_info->req_side_buttons_bitmap) *
+ BITS_IN_BYTE);
+
struct input_dev *input_if = usf_info->input_ifs[if_ind];
struct point_event_type *pe = &(event->event_data.point_event);
@@ -273,19 +309,27 @@
input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+ for (i = 0; i < num_side_buttons; i++) {
+ uint16_t mask = (1 << i),
+ btn_state = !!(pe->side_buttons_state_bitmap & mask);
+ if (usf_info->req_side_buttons_bitmap & mask)
+ input_report_key(input_if, s_button_map[i], btn_state);
+ }
+
if (usf_info->event_src)
input_report_key(input_if, usf_info->event_src, 1);
input_sync(input_if);
- pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
__func__,
pe->coordinates[X_IND],
pe->coordinates[Y_IND],
pe->coordinates[Z_IND],
pe->inclinations[X_IND],
pe->inclinations[Y_IND],
- pe->pressure);
+ pe->pressure,
+ pe->side_buttons_state_bitmap);
}
static void notify_mouse_event(struct usf_type *usf_info,
@@ -338,6 +382,8 @@
prepare_mouse_input_device, notify_mouse_event},
{USF_KEYBOARD_EVENT, "usf_kb",
prepare_keyboard_input_device, notify_key_event},
+ {USF_TSC_EXT_EVENT, "usf_tsc_ext",
+ prepare_tsc_input_device, notify_tsc_event},
};
static void usf_rx_cb(uint32_t opcode, uint32_t token,
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index fe7c8c2..51a51c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -628,6 +628,12 @@
case FORMAT_USPROX:
int_format = US_PROX_FORMAT_V2;
break;
+ case FORMAT_USGES_SYNC:
+ int_format = US_GES_SYNC_FORMAT;
+ break;
+ case FORMAT_USRAW_SYNC:
+ int_format = US_RAW_SYNC_FORMAT;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
break;
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index cb8ed19..1447854 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -54,7 +54,7 @@
u32 num_records;
u32 read_idx;
u32 len;
- char buf[256];
+ char buf[320];
struct msm_rpmstats_platform_data *platform_data;
};
@@ -64,7 +64,8 @@
u64 last_entered_at;
u64 last_exited_at;
u64 accumulated;
- u32 reserved[4];
+ u32 client_votes;
+ u32 reserved[3];
};
static inline u64 get_time_in_sec(u64 counter)
@@ -98,10 +99,12 @@
actual_last_sleep = get_time_in_msec(data->accumulated);
return snprintf(buf , buflength,
- "RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
- "time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
+ "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+ "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n"
+ "client votes: %#010x\n\n",
stat_type, data->count, time_in_last_mode,
- time_since_last_mode, actual_last_sleep);
+ time_since_last_mode, actual_last_sleep,
+ data->client_votes);
}
static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -147,6 +150,9 @@
data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
i, offsetof(struct msm_rpm_stats_data_v2,
accumulated));
+ data.client_votes = msm_rpmstats_read_long_register_v2(reg,
+ i, offsetof(struct msm_rpm_stats_data_v2,
+ client_votes));
length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
&data, sizeof(prvdata->buf) - length);
prvdata->read_idx++;
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index b6fbb3c2..cc8cf47 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -125,16 +125,38 @@
return n;
}
+struct fastrpc_buf {
+ struct ion_handle *handle;
+ void *virt;
+ ion_phys_addr_t phys;
+ int size;
+ int used;
+};
+
+struct smq_context_list;
+
struct smq_invoke_ctx {
+ struct hlist_node hn;
struct completion work;
int retval;
- atomic_t free;
+ int pid;
+ remote_arg_t *pra;
+ remote_arg_t *rpra;
+ struct fastrpc_buf obuf;
+ struct fastrpc_buf *abufs;
+ struct fastrpc_device *dev;
+ struct fastrpc_apps *apps;
+ int *fds;
+ struct ion_handle **handles;
+ int nbufs;
+ bool smmu;
+ uint32_t sc;
};
struct smq_context_list {
- struct smq_invoke_ctx *ls;
- int size;
- int last;
+ struct hlist_head pending;
+ struct hlist_head interrupted;
+ spinlock_t hlock;
};
struct fastrpc_smmu {
@@ -165,22 +187,16 @@
struct hlist_node hn;
struct ion_handle *handle;
void *virt;
+ ion_phys_addr_t phys;
uint32_t vaddrin;
uint32_t vaddrout;
int size;
};
-struct fastrpc_buf {
- struct ion_handle *handle;
- void *virt;
- ion_phys_addr_t phys;
- int size;
- int used;
-};
-
struct file_data {
spinlock_t hlock;
struct hlist_head hlst;
+ uint32_t mode;
};
struct fastrpc_device {
@@ -214,6 +230,11 @@
{
struct fastrpc_apps *me = &gfa;
if (!IS_ERR_OR_NULL(map->handle)) {
+ if (me->smmu.enabled && map->phys) {
+ ion_unmap_iommu(me->iclient, map->handle,
+ me->smmu.domain_id, 0);
+ map->phys = 0;
+ }
if (!IS_ERR_OR_NULL(map->virt)) {
ion_unmap_kernel(me->iclient, map->handle);
map->virt = 0;
@@ -263,65 +284,186 @@
return err;
}
-static int context_list_ctor(struct smq_context_list *me, int size)
+static int context_restore_interrupted(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
int err = 0;
- VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- me->size = size / sizeof(*me->ls);
- me->last = 0;
- bail:
+ struct smq_invoke_ctx *ctx = 0, *ictx = 0;
+ struct hlist_node *pos, *n;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
+ spin_lock(&me->clst.hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->clst.interrupted, hn) {
+ if (ictx->pid == current->pid) {
+ if (invoke->sc != ictx->sc)
+ err = -1;
+ else {
+ ctx = ictx;
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &me->clst.pending);
+ }
+ break;
+ }
+ }
+ spin_unlock(&me->clst.hlock);
+ if (ctx)
+ *po = ctx;
return err;
}
-static void context_list_dtor(struct smq_context_list *me)
+static int context_alloc(struct fastrpc_apps *me, uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd,
+ struct smq_invoke_ctx **po)
{
- kfree(me->ls);
-}
+ int err = 0, bufs, size = 0;
+ struct smq_invoke_ctx *ctx = 0;
+ struct smq_context_list *clst = &me->clst;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
-static void context_list_alloc_ctx(struct smq_context_list *me,
- struct smq_invoke_ctx **po)
-{
- int i = me->last;
- struct smq_invoke_ctx *ctx;
-
- for (;;) {
- i = i % me->size;
- ctx = &me->ls[i];
- if (atomic_read(&ctx->free) == 0)
- if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
- break;
- i++;
+ bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+ REMOTE_SCALARS_OUTBUFS(invoke->sc);
+ if (bufs) {
+ size = bufs * sizeof(*ctx->pra);
+ if (invokefd->fds)
+ size = size + bufs * sizeof(*ctx->fds) +
+ bufs * sizeof(*ctx->handles);
}
- me->last = i;
+
+ VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)));
+ if (err)
+ goto bail;
+
+ INIT_HLIST_NODE(&ctx->hn);
+ ctx->pra = (remote_arg_t *)(&ctx[1]);
+ ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]);
+ ctx->handles = invokefd->fds == 0 ? 0 :
+ (struct ion_handle **)(&ctx->fds[bufs]);
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra,
+ bufs * sizeof(*ctx->pra)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->pra, invoke->pra, bufs * sizeof(*ctx->pra));
+ }
+
+ if (invokefd->fds) {
+ if (!kernel) {
+ VERIFY(err, 0 == copy_from_user(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds)));
+ if (err)
+ goto bail;
+ } else {
+ memmove(ctx->fds, invokefd->fds,
+ bufs * sizeof(*ctx->fds));
+ }
+ }
+ ctx->sc = invoke->sc;
ctx->retval = -1;
+ ctx->pid = current->pid;
+ ctx->apps = me;
init_completion(&ctx->work);
+ spin_lock(&clst->hlock);
+ hlist_add_head(&ctx->hn, &clst->pending);
+ spin_unlock(&clst->hlock);
+
*po = ctx;
+bail:
+ if (ctx && err)
+ kfree(ctx);
+ return err;
}
-static void context_free(struct smq_invoke_ctx *me)
+static void context_save_interrupted(struct smq_invoke_ctx *ctx)
{
- if (me)
- atomic_set(&me->free, 0);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ hlist_add_head(&ctx->hn, &clst->interrupted);
+ spin_unlock(&clst->hlock);
}
-static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev);
+
+static void context_free(struct smq_invoke_ctx *ctx, bool lock)
{
- me->retval = retval;
- complete(&me->work);
+ struct smq_context_list *clst = &ctx->apps->clst;
+ struct fastrpc_apps *apps = ctx->apps;
+ struct ion_client *clnt = apps->iclient;
+ struct fastrpc_smmu *smmu = &apps->smmu;
+ struct fastrpc_buf *b;
+ int i, bufs;
+ if (ctx->smmu) {
+ bufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
+ REMOTE_SCALARS_OUTBUFS(ctx->sc);
+ if (ctx->fds) {
+ for (i = 0; i < bufs; i++)
+ if (!IS_ERR_OR_NULL(ctx->handles[i])) {
+ ion_unmap_iommu(clnt, ctx->handles[i],
+ smmu->domain_id, 0);
+ ion_free(clnt, ctx->handles[i]);
+ }
+ }
+ iommu_detach_group(smmu->domain, smmu->group);
+ }
+ for (i = 0, b = ctx->abufs; i < ctx->nbufs; ++i, ++b)
+ free_mem(b);
+
+ kfree(ctx->abufs);
+ if (ctx->dev) {
+ add_dev(apps, ctx->dev);
+ if (ctx->obuf.handle != ctx->dev->buf.handle)
+ free_mem(&ctx->obuf);
+ }
+ if (lock)
+ spin_lock(&clst->hlock);
+ hlist_del(&ctx->hn);
+ if (lock)
+ spin_unlock(&clst->hlock);
+ kfree(ctx);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *ctx, int retval)
+{
+ ctx->retval = retval;
+ complete(&ctx->work);
}
static void context_notify_all_users(struct smq_context_list *me)
{
- int i;
-
- if (!me->ls)
- return;
- for (i = 0; i < me->size; ++i) {
- if (atomic_read(&me->ls[i].free) != 0)
- complete(&me->ls[i].work);
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&me->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &me->pending, hn) {
+ complete(&ictx->work);
}
+ hlist_for_each_entry_safe(ictx, pos, n, &me->interrupted, hn) {
+ complete(&ictx->work);
+ }
+ spin_unlock(&me->hlock);
+
+}
+
+static void context_list_ctor(struct smq_context_list *me)
+{
+ INIT_HLIST_HEAD(&me->interrupted);
+ INIT_HLIST_HEAD(&me->pending);
+ spin_lock_init(&me->hlock);
+}
+
+static void context_list_dtor(struct fastrpc_apps *me,
+ struct smq_context_list *clst)
+{
+ struct smq_invoke_ctx *ictx = 0;
+ struct hlist_node *pos, *n;
+ spin_lock(&clst->hlock);
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->interrupted, hn) {
+ context_free(ictx, 0);
+ }
+ hlist_for_each_entry_safe(ictx, pos, n, &clst->pending, hn) {
+ context_free(ictx, 0);
+ }
+ spin_unlock(&clst->hlock);
}
static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
@@ -400,13 +542,12 @@
static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
remote_arg_t *rpra, remote_arg_t *upra,
struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
- int *nbufs, int *fds)
+ int *nbufs, int *fds, struct ion_handle **handles)
{
struct fastrpc_apps *me = &gfa;
struct smq_invoke_buf *list;
struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
struct smq_phy_page *pages;
- struct ion_handle **handles = NULL;
void *args;
int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -418,8 +559,6 @@
used = ALIGN(pbuf->used, BALIGN);
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
- if (fds)
- handles = (struct ion_handle **)(fds + inbufs + outbufs);
for (i = 0; i < inbufs + outbufs; ++i) {
rpra[i].buf.len = pra[i].buf.len;
@@ -614,7 +753,6 @@
struct fastrpc_apps *me = &gfa;
smd_close(me->chan);
- context_list_dtor(&me->clst);
ion_client_destroy(me->iclient);
me->iclient = 0;
me->chan = 0;
@@ -667,16 +805,14 @@
spin_lock_init(&me->wrlock);
init_completion(&me->work);
mutex_init(&me->smd_mutex);
+ context_list_ctor(&me->clst);
for (i = 0; i < RPC_HASH_SZ; ++i)
INIT_HLIST_HEAD(&me->htbl[i]);
- VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
- if (err)
- goto context_list_bail;
me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
DEVICE_NAME);
VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
if (err)
- goto ion_bail;
+ goto bail;
node = of_find_compatible_node(NULL, NULL,
"qcom,msm-audio-ion");
if (node)
@@ -697,9 +833,7 @@
return 0;
-ion_bail:
- context_list_dtor(&me->clst);
-context_list_bail:
+bail:
return err;
}
@@ -783,96 +917,88 @@
static int fastrpc_release_current_dsp_process(void);
-static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
- struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
- int *fds)
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
+ uint32_t kernel,
+ struct fastrpc_ioctl_invoke_fd *invokefd)
{
- remote_arg_t *rpra = 0;
- struct fastrpc_device *dev = 0;
struct smq_invoke_ctx *ctx = 0;
- struct fastrpc_buf obuf, *abufs = 0, *b;
- struct ion_handle **handles = NULL;
+ struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
int interrupted = 0;
- uint32_t sc;
- int i, bufs, nbufs = 0, err = 0;
+ int err = 0;
- sc = invoke->sc;
- obuf.handle = 0;
+ if (!kernel) {
+ VERIFY(err, 0 == context_restore_interrupted(me, invokefd,
+ &ctx));
+ if (err)
+ goto bail;
+ if (ctx)
+ goto wait;
+ }
+
+ VERIFY(err, 0 == context_alloc(me, kernel, invokefd, &ctx));
+ if (err)
+ goto bail;
+
if (me->smmu.enabled) {
VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
me->smmu.group));
if (err)
- return err;
+ goto bail;
+ ctx->smmu = 1;
}
- if (REMOTE_SCALARS_LENGTH(sc)) {
- VERIFY(err, 0 == get_dev(me, &dev));
+ if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+ VERIFY(err, 0 == get_dev(me, &ctx->dev));
if (err)
goto bail;
- VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
- &obuf));
+ VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
+ &ctx->dev->buf, &ctx->obuf));
if (err)
goto bail;
- rpra = (remote_arg_t *)obuf.virt;
- VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
- &obuf, &abufs, &nbufs, fds));
+ ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
+ VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra, &ctx->obuf, &ctx->abufs,
+ &ctx->nbufs, ctx->fds, ctx->handles));
if (err)
goto bail;
}
- context_list_alloc_ctx(&me->clst, &ctx);
- inv_args_pre(sc, rpra);
- VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
- ctx, &obuf));
+ inv_args_pre(ctx->sc, ctx->rpra);
+ if (FASTRPC_MODE_SERIAL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle,
+ ctx->sc, ctx, &ctx->obuf));
if (err)
goto bail;
- inv_args(sc, rpra, obuf.used);
- VERIFY(err, 0 == (interrupted =
- wait_for_completion_interruptible(&ctx->work)));
- if (err)
- goto bail;
+ if (FASTRPC_MODE_PARALLEL == mode)
+ inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ wait:
+ if (kernel)
+ wait_for_completion(&ctx->work);
+ else {
+ interrupted = wait_for_completion_interruptible(&ctx->work);
+ VERIFY(err, 0 == (err = interrupted));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == (err = ctx->retval));
if (err)
goto bail;
- VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+ VERIFY(err, 0 == put_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+ invoke->pra));
if (err)
goto bail;
bail:
- if (interrupted) {
- if (!kernel)
- (void)fastrpc_release_current_dsp_process();
- wait_for_completion(&ctx->work);
- }
- context_free(ctx);
-
- if (me->smmu.enabled) {
- bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
- if (fds) {
- handles = (struct ion_handle **)(fds + bufs);
- for (i = 0; i < bufs; i++)
- if (!IS_ERR_OR_NULL(handles[i])) {
- ion_unmap_iommu(me->iclient, handles[i],
- me->smmu.domain_id, 0);
- ion_free(me->iclient, handles[i]);
- }
- }
- iommu_detach_group(me->smmu.domain, me->smmu.group);
- }
- for (i = 0, b = abufs; i < nbufs; ++i, ++b)
- free_mem(b);
-
- kfree(abufs);
- if (dev) {
- add_dev(me, dev);
- if (obuf.handle != dev->buf.handle)
- free_mem(&obuf);
- }
+ if (ctx && interrupted == -ERESTARTSYS)
+ context_save_interrupted(ctx);
+ else if (ctx)
+ context_free(ctx, 1);
return err;
}
static int fastrpc_create_current_dsp_process(void)
{
int err = 0;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
struct fastrpc_apps *me = &gfa;
remote_arg_t ra[1];
int tgid = 0;
@@ -880,10 +1006,12 @@
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -891,17 +1019,19 @@
{
int err = 0;
struct fastrpc_apps *me = &gfa;
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int tgid = 0;
tgid = current->tgid;
ra[0].buf.pv = &tgid;
ra[0].buf.len = sizeof(tgid);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -910,7 +1040,7 @@
struct smq_phy_page *pages,
int num)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[3];
int err = 0;
struct {
@@ -936,10 +1066,12 @@
ra[2].buf.pv = &routargs;
ra[2].buf.len = sizeof(routargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
mmap->vaddrout = routargs.vaddrout;
if (err)
goto bail;
@@ -950,7 +1082,7 @@
static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
struct fastrpc_ioctl_munmap *munmap)
{
- struct fastrpc_ioctl_invoke ioctl;
+ struct fastrpc_ioctl_invoke_fd ioctl;
remote_arg_t ra[1];
int err = 0;
struct {
@@ -965,10 +1097,12 @@
ra[0].buf.pv = &inargs;
ra[0].buf.len = sizeof(inargs);
- ioctl.handle = 1;
- ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
- ioctl.pra = ra;
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+ ioctl.inv.handle = 1;
+ ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+ ioctl.inv.pra = ra;
+ ioctl.fds = 0;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+ FASTRPC_MODE_PARALLEL, 1, &ioctl)));
return err;
}
@@ -1010,7 +1144,7 @@
struct fastrpc_mmap *map = 0;
struct smq_phy_page *pages = 0;
void *buf;
- int len;
+ unsigned long len;
int num;
int err = 0;
@@ -1031,9 +1165,22 @@
VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
if (err)
goto bail;
- VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
- if (err)
- goto bail;
+
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 == ion_map_iommu(clnt, map->handle,
+ me->smmu.domain_id, 0,
+ SZ_4K, 0, &map->phys, &len, 0, 0));
+ if (err)
+ goto bail;
+ pages->addr = map->phys;
+ pages->size = len;
+ num = 1;
+ } else {
+ VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1,
+ pages, num)));
+ if (err)
+ goto bail;
+ }
VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
if (err)
@@ -1100,7 +1247,7 @@
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
if (fdata) {
- struct fastrpc_mmap *map;
+ struct fastrpc_mmap *map = 0;
struct hlist_node *n, *pos;
file->private_data = 0;
hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
@@ -1179,48 +1326,23 @@
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_ioctl_invoke_fd invokefd;
- struct fastrpc_ioctl_invoke *invoke = &invokefd.inv;
struct fastrpc_ioctl_mmap mmap;
struct fastrpc_ioctl_munmap munmap;
- remote_arg_t *pra = 0;
void *param = (char *)ioctl_param;
struct file_data *fdata = (struct file_data *)file->private_data;
- int *fds = 0;
- int bufs, size = 0, err = 0;
+ int size = 0, err = 0;
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE_FD:
case FASTRPC_IOCTL_INVOKE:
invokefd.fds = 0;
size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
- sizeof(*invoke) : sizeof(invokefd);
+ sizeof(invokefd.inv) : sizeof(invokefd);
VERIFY(err, 0 == copy_from_user(&invokefd, param, size));
if (err)
goto bail;
- bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
- REMOTE_SCALARS_OUTBUFS(invoke->sc);
- if (bufs) {
- size = bufs * sizeof(*pra);
- if (invokefd.fds)
- size = size + bufs * sizeof(*fds) +
- bufs * sizeof(struct ion_handle *);
- VERIFY(err, 0 != (pra = kzalloc(size, GFP_KERNEL)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
- bufs * sizeof(*pra)));
- if (err)
- goto bail;
- if (invokefd.fds) {
- fds = (int *)(pra + bufs);
- VERIFY(err, 0 == copy_from_user(fds, invokefd.fds,
- bufs * sizeof(*fds)));
- if (err)
- goto bail;
- }
- VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, invoke,
- pra, fds)));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
+ 0, &invokefd)));
if (err)
goto bail;
break;
@@ -1247,12 +1369,22 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_SETMODE:
+ switch ((uint32_t)ioctl_param) {
+ case FASTRPC_MODE_PARALLEL:
+ case FASTRPC_MODE_SERIAL:
+ fdata->mode = (uint32_t)ioctl_param;
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ break;
default:
err = -ENOTTY;
break;
}
bail:
- kfree(pra);
return err;
}
@@ -1307,7 +1439,9 @@
{
struct fastrpc_apps *me = &gfa;
+ context_list_dtor(me, &me->clst);
fastrpc_deinit();
+ cleanup_current_dev();
device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
class_destroy(me->class);
cdev_del(&me->cdev);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index da70eb5..f5d7450 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -20,9 +20,16 @@
#define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap)
#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap)
#define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd)
+#define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
+/* Driver should operate in parallel with the co-processor */
+#define FASTRPC_MODE_PARALLEL 0
+
+/* Driver should operate in serial mode with the co-processor */
+#define FASTRPC_MODE_SERIAL 1
+
/* Retrives number of input buffers from the scalars parameter */
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 03304dc..c9be39a 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,7 +24,7 @@
#define DISABLE_LOG_MASK 0
#define MAX_EVENT_SIZE 512
#define DCI_CLIENT_INDEX_INVALID -1
-#define DCI_PKT_REQ_MIN_LEN 8
+#define DCI_PKT_REQ_MIN_LEN 5
#define DCI_LOG_CON_MIN_LEN 14
#define DCI_EVENT_CON_MIN_LEN 16
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4f5893c..8f7d39c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -318,6 +318,7 @@
show_one(down_differential, down_differential);
show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
+show_one(down_differential_multi_core, down_differential_multi_core);
show_one(optimal_freq, optimal_freq);
show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
show_one(sync_freq, sync_freq);
@@ -437,6 +438,20 @@
return count;
}
+static ssize_t store_down_differential_multi_core(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ dbs_tuners_ins.down_differential_multi_core = input;
+ return count;
+}
+
+
static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -695,6 +710,7 @@
define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
define_one_global_rw(up_threshold_multi_core);
+define_one_global_rw(down_differential_multi_core);
define_one_global_rw(optimal_freq);
define_one_global_rw(up_threshold_any_cpu_load);
define_one_global_rw(sync_freq);
@@ -710,6 +726,7 @@
&powersave_bias.attr,
&io_is_busy.attr,
&up_threshold_multi_core.attr,
+ &down_differential_multi_core.attr,
&optimal_freq.attr,
&up_threshold_any_cpu_load.attr,
&sync_freq.attr,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0809308..514385c 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -36,6 +36,7 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
+#include <linux/idr.h>
#include <linux/msm_ion.h>
#include <trace/events/kmem.h>
@@ -70,6 +71,7 @@
* @node: node in the tree of all clients
* @dev: backpointer to ion device
* @handles: an rb tree of all the handles in this client
+ * @idr: an idr space for allocating handle ids
* @lock: lock protecting the tree of handles
* @name: used for debugging
* @task: used for debugging
@@ -82,6 +84,7 @@
struct rb_node node;
struct ion_device *dev;
struct rb_root handles;
+ struct idr idr;
struct mutex lock;
char *name;
struct task_struct *task;
@@ -96,7 +99,7 @@
* @buffer: pointer to the buffer
* @node: node in the client's handle rbtree
* @kmap_cnt: count of times this client has mapped to kernel
- * @dmap_cnt: count of times this client has mapped for dma
+ * @id: client-unique id allocated by client->idr
*
* Modifications to node, map_cnt or mapping should be protected by the
* lock in the client. Other fields are never changed after initialization.
@@ -107,6 +110,7 @@
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
+ int id;
};
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -343,6 +347,7 @@
ion_handle_kmap_put(handle);
mutex_unlock(&buffer->lock);
+ idr_remove(&client->idr, handle->id);
if (!RB_EMPTY_NODE(&handle->node))
rb_erase(&handle->node, &client->handles);
@@ -362,9 +367,16 @@
kref_get(&handle->ref);
}
-static int ion_handle_put(struct ion_handle *handle)
+int ion_handle_put(struct ion_handle *handle)
{
- return kref_put(&handle->ref, ion_handle_destroy);
+ struct ion_client *client = handle->client;
+ int ret;
+
+ mutex_lock(&client->lock);
+ ret = kref_put(&handle->ref, ion_handle_destroy);
+ mutex_unlock(&client->lock);
+
+ return ret;
}
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -374,36 +386,52 @@
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
+ node);
if (handle->buffer == buffer)
return handle;
}
return NULL;
}
-static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id)
{
- struct rb_node *n = client->handles.rb_node;
+ struct ion_handle *handle;
- while (n) {
- struct ion_handle *handle_node = rb_entry(n, struct ion_handle,
- node);
- if (handle < handle_node)
- n = n->rb_left;
- else if (handle > handle_node)
- n = n->rb_right;
- else
- return true;
- }
- return false;
+ mutex_lock(&client->lock);
+ handle = idr_find(&client->idr, id);
+ if (handle)
+ ion_handle_get(handle);
+ mutex_unlock(&client->lock);
+
+ return handle ? handle : ERR_PTR(-EINVAL);
}
-static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
{
+ WARN_ON(!mutex_is_locked(&client->lock));
+ return (idr_find(&client->idr, handle->id) == handle);
+}
+
+static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+{
+ int rc;
struct rb_node **p = &client->handles.rb_node;
struct rb_node *parent = NULL;
struct ion_handle *entry;
+ do {
+ int id;
+ rc = idr_pre_get(&client->idr, GFP_KERNEL);
+ if (!rc)
+ return -ENOMEM;
+ rc = idr_get_new_above(&client->idr, handle, 1, &id);
+ handle->id = id;
+ } while (rc == -EAGAIN);
+
+ if (rc < 0)
+ return rc;
+
while (*p) {
parent = *p;
entry = rb_entry(parent, struct ion_handle, node);
@@ -418,6 +446,8 @@
rb_link_node(&handle->node, parent, p);
rb_insert_color(&handle->node, &client->handles);
+
+ return 0;
}
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
@@ -428,6 +458,7 @@
struct ion_device *dev = client->dev;
struct ion_buffer *buffer = NULL;
struct ion_heap *heap;
+ int ret;
unsigned long secure_allocation = flags & ION_FLAG_SECURE;
const unsigned int MAX_DBG_STR_LEN = 64;
char dbg_str[MAX_DBG_STR_LEN];
@@ -518,12 +549,16 @@
*/
ion_buffer_put(buffer);
- if (!IS_ERR(handle)) {
- mutex_lock(&client->lock);
- ion_handle_add(client, handle);
- mutex_unlock(&client->lock);
- }
+ if (IS_ERR(handle))
+ return handle;
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
+ mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
return handle;
}
@@ -542,8 +577,8 @@
mutex_unlock(&client->lock);
return;
}
- ion_handle_put(handle);
mutex_unlock(&client->lock);
+ ion_handle_put(handle);
}
EXPORT_SYMBOL(ion_free);
@@ -775,6 +810,7 @@
client->dev = dev;
client->handles = RB_ROOT;
+ idr_init(&client->idr);
mutex_init(&client->lock);
client->name = kzalloc(name_len+1, GFP_KERNEL);
@@ -831,6 +867,10 @@
node);
ion_handle_destroy(&handle->ref);
}
+
+ idr_remove_all(&client->idr);
+ idr_destroy(&client->idr);
+
down_write(&dev->lock);
if (client->task)
put_task_struct(client->task);
@@ -1175,14 +1215,15 @@
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
- mutex_unlock(&client->lock);
if (!valid_handle) {
WARN(1, "%s: invalid handle passed to share.\n", __func__);
+ mutex_unlock(&client->lock);
return ERR_PTR(-EINVAL);
}
-
buffer = handle->buffer;
ion_buffer_get(buffer);
+ mutex_unlock(&client->lock);
+
dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
if (IS_ERR(dmabuf)) {
ion_buffer_put(buffer);
@@ -1215,6 +1256,7 @@
struct dma_buf *dmabuf;
struct ion_buffer *buffer;
struct ion_handle *handle;
+ int ret;
dmabuf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dmabuf))
@@ -1234,14 +1276,24 @@
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR_OR_NULL(handle)) {
ion_handle_get(handle);
+ mutex_unlock(&client->lock);
goto end;
}
+ mutex_unlock(&client->lock);
+
handle = ion_handle_create(client, buffer);
if (IS_ERR_OR_NULL(handle))
goto end;
- ion_handle_add(client, handle);
-end:
+
+ mutex_lock(&client->lock);
+ ret = ion_handle_add(client, handle);
mutex_unlock(&client->lock);
+ if (ret) {
+ ion_handle_put(handle);
+ handle = ERR_PTR(ret);
+ }
+
+end:
dma_buf_put(dmabuf);
return handle;
}
@@ -1279,17 +1331,20 @@
case ION_IOC_ALLOC:
{
struct ion_allocation_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.handle = ion_alloc(client, data.len, data.align,
+ handle = ion_alloc(client, data.len, data.align,
data.heap_mask, data.flags);
- if (IS_ERR(data.handle))
- return PTR_ERR(data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ data.handle = (ion_user_handle_t)handle->id;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
- ion_free(client, data.handle);
+ ion_free(client, handle);
return -EFAULT;
}
break;
@@ -1297,28 +1352,31 @@
case ION_IOC_FREE:
{
struct ion_handle_data data;
- bool valid;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_handle_data)))
return -EFAULT;
- mutex_lock(&client->lock);
- valid = ion_handle_validate(client, data.handle);
- mutex_unlock(&client->lock);
- if (!valid)
- return -EINVAL;
- ion_free(client, data.handle);
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ion_free(client, handle);
+ ion_handle_put(handle);
break;
}
case ION_IOC_SHARE:
case ION_IOC_MAP:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- data.fd = ion_share_dma_buf_fd(client, data.handle);
-
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ data.fd = ion_share_dma_buf_fd(client, handle);
+ ion_handle_put(handle);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
if (data.fd < 0)
@@ -1328,15 +1386,17 @@
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ struct ion_handle *handle;
int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
- data.handle = ion_import_dma_buf(client, data.fd);
- if (IS_ERR(data.handle)) {
- ret = PTR_ERR(data.handle);
- data.handle = NULL;
- }
+ handle = ion_import_dma_buf(client, data.fd);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle = (ion_user_handle_t)handle->id;
+
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index f5d0287..aa0a9e2 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -396,4 +396,9 @@
int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
int (*f)(struct ion_heap *heap, void *data));
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+ int id);
+
+int ion_handle_put(struct ion_handle *handle);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 213bcb1..cdd31e1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -973,11 +973,18 @@
sizeof(struct ion_flush_data)))
return -EFAULT;
- if (!data.handle) {
+ if (data.handle >= 0) {
+ handle = ion_handle_get_by_id(client, (int)data.handle);
+ if (IS_ERR(handle)) {
+ pr_info("%s: Could not find handle: %d\n",
+ __func__, (int)data.handle);
+ return PTR_ERR(handle);
+ }
+ } else {
handle = ion_import_dma_buf(client, data.fd);
if (IS_ERR(handle)) {
- pr_info("%s: Could not import handle: %d\n",
- __func__, (int)handle);
+ pr_info("%s: Could not import handle: %p\n",
+ __func__, handle);
return -EINVAL;
}
}
@@ -988,28 +995,20 @@
end = (unsigned long) data.vaddr + data.length;
if (start && check_vaddr_bounds(start, end)) {
- up_read(&mm->mmap_sem);
pr_err("%s: virtual address %p is out of bounds\n",
__func__, data.vaddr);
- if (!data.handle)
- ion_free(client, handle);
- return -EINVAL;
+ ret = -EINVAL;
+ } else {
+ ret = ion_do_cache_op(client, handle, data.vaddr,
+ data.offset, data.length, cmd);
}
-
- ret = ion_do_cache_op(client,
- data.handle ? data.handle : handle,
- data.vaddr, data.offset, data.length,
- cmd);
-
up_read(&mm->mmap_sem);
- if (!data.handle)
- ion_free(client, handle);
+ ion_free(client, handle);
if (ret < 0)
return ret;
break;
-
}
case ION_IOC_PREFETCH:
{
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index e5f5ad7..3d4c66a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4077,6 +4077,7 @@
static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
{
int ret;
+ struct kgsl_device *device = &adreno_dev->dev;
/* SP[3] counter is broken on a330 so disable it if a330 device */
if (adreno_is_a330(adreno_dev))
a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
@@ -4088,15 +4089,18 @@
ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
NULL, PERFCOUNTER_FLAG_KERNEL);
- /* VBIF waiting for RAM */
- ret |= adreno_perfcounter_get(adreno_dev,
+ if (device->pwrctrl.bus_control) {
+ /* VBIF waiting for RAM */
+ ret |= adreno_perfcounter_get(adreno_dev,
KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
NULL, PERFCOUNTER_FLAG_KERNEL);
- /* VBIF DDR cycles */
- ret |= adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+ /* VBIF DDR cycles */
+ ret |= adreno_perfcounter_get(adreno_dev,
+ KGSL_PERFCOUNTER_GROUP_VBIF,
VBIF_AXI_TOTAL_BEATS,
&adreno_dev->ram_cycles_lo,
PERFCOUNTER_FLAG_KERNEL);
+ }
/* Default performance counter profiling to false */
adreno_dev->profile.enabled = false;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe99a4b..9aefda6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2878,7 +2878,7 @@
bool full_flush = false;
if (param->id_list == NULL || param->count == 0
- || param->count > (UINT_MAX/sizeof(unsigned int)))
+ || param->count > (PAGE_SIZE / sizeof(unsigned int)))
return -EINVAL;
id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2be1f01..59b648d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -122,6 +122,8 @@
{
int i, rc = -1;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < v4l2_buf->length; i++) {
mapped_info = &buf_info->mapped_info[i];
mapped_info->handle =
@@ -144,6 +146,15 @@
mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
CDBG("%s: plane: %d addr:%lu\n",
__func__, i, mapped_info->paddr);
+
+ buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
+ if (!buf_pending) {
+ pr_err("No free memory for buf_pending\n");
+ return rc;
+ }
+
+ buf_pending->mapped_info = mapped_info;
+ list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
}
buf_info->num_planes = v4l2_buf->length;
return 0;
@@ -163,11 +174,26 @@
{
int i;
struct msm_isp_buffer_mapped_info *mapped_info;
+ struct buffer_cmd *buf_pending = NULL;
+
for (i = 0; i < buf_info->num_planes; i++) {
mapped_info = &buf_info->mapped_info[i];
- ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
- buf_mgr->iommu_domain_num, 0);
- ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+ if (!buf_pending)
+ break;
+
+ if (buf_pending->mapped_info == mapped_info) {
+ ion_unmap_iommu(buf_mgr->client,
+ mapped_info->handle,
+ buf_mgr->iommu_domain_num, 0);
+ ion_free(buf_mgr->client, mapped_info->handle);
+
+ list_del_init(&buf_pending->list);
+ kfree(buf_pending);
+ break;
+ }
+ }
}
return;
}
@@ -586,7 +612,7 @@
}
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
- if (BUF_SRC(bufq->stream_id)) {
+ if (bufq && BUF_SRC(bufq->stream_id)) {
rc = msm_isp_put_buf(buf_mgr,
info->handle, info->buf_idx);
if (rc < 0) {
@@ -691,6 +717,7 @@
if (!bufq->bufq_handle)
continue;
msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
+
kfree(bufq->bufs);
msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
}
@@ -739,9 +766,10 @@
pr_err("Invalid buffer queue number\n");
return rc;
}
-
CDBG("%s: E\n", __func__);
+
msm_isp_attach_ctx(buf_mgr);
+ INIT_LIST_HEAD(&buf_mgr->buffer_q);
buf_mgr->num_buf_q = num_buf_q;
buf_mgr->bufq =
kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 6d6ff9d..d8d3ba2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -44,6 +44,11 @@
struct ion_handle *handle;
};
+struct buffer_cmd {
+ struct list_head list;
+ struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
struct msm_isp_buffer {
/*Common Data structure*/
int num_planes;
@@ -138,6 +143,7 @@
int num_iommu_ctx;
struct device *iommu_ctx[2];
+ struct list_head buffer_q;
};
int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 2c5e136..80a0073 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -140,6 +140,7 @@
&vfe_vb2_ops, &vfe_layout);
if (rc < 0) {
pr_err("%s: Unable to create buffer manager\n", __func__);
+ msm_sd_unregister(&vfe_dev->subdev);
kfree(vfe_dev);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 87bffde..9dd0085 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -106,7 +106,7 @@
uint32_t reload_mask);
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
- void (*cfg_io_format) (struct vfe_device *vfe_dev,
+ int32_t (*cfg_io_format) (struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src,
uint32_t io_format);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index f5529cd..410fe8f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -74,6 +74,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
@@ -495,12 +497,17 @@
}
}
-static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
uint32_t io_format_reg;
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -512,6 +519,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -537,7 +547,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -558,9 +568,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+ return 0;
}
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 50a25bd..ad4b75f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -268,6 +268,8 @@
goto fs_failed;
}
}
+ else
+ goto fs_failed;
rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 1);
@@ -724,13 +726,18 @@
VFE40_WM_BASE(stream_info->wm[i]) + 0x1C);
}
-static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
{
int bpp, bpp_reg = 0, pack_reg = 0;
enum msm_isp_pack_fmt pack_fmt = 0;
uint32_t io_format_reg; /*io format register bit*/
bpp = msm_isp_get_bit_per_pixel(io_format);
+ if (bpp < 0) {
+ pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+ io_format, bpp);
+ return -EINVAL;
+ }
switch (bpp) {
case 8:
@@ -742,6 +749,9 @@
case 12:
bpp_reg = 1 << 1;
break;
+ default:
+ pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+ return -EINVAL;
}
if (stream_src == IDEAL_RAW) {
@@ -768,7 +778,7 @@
break;
default:
pr_err("%s: invalid pack fmt!\n", __func__);
- return;
+ return -EINVAL;
}
}
@@ -789,9 +799,10 @@
case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
- return;
+ return -EINVAL;
}
msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+ return 0;
}
static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 3202cdb..97b6347 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -68,9 +68,17 @@
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
int rc = -1, i;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t idx = 0;
+
+ if (NULL == stream_cfg_cmd || NULL == axi_data)
+ return rc;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return rc;
switch (stream_cfg_cmd->output_format) {
case V4L2_PIX_FMT_SBGGR8:
@@ -428,11 +436,22 @@
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- uint32_t framedrop_period = msm_isp_get_framedrop_period(
- stream_cfg_cmd->frame_skip_pattern);
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ uint32_t framedrop_period = 0;
+ uint8_t idx = 0;
+
+ if (NULL == axi_data || NULL == stream_cfg_cmd)
+ return;
+
+ idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+
+ if (idx < MAX_NUM_STREAM)
+ stream_info = &axi_data->stream_info[idx];
+ else
+ return;
+
+ framedrop_period = msm_isp_get_framedrop_period(
+ stream_cfg_cmd->frame_skip_pattern);
if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
@@ -520,8 +539,17 @@
io_format = stream_info->output_format;
}
- vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+ rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
vfe_dev, stream_info->stream_src, io_format);
+ if (rc) {
+ pr_err("%s: cfg io format failed\n", __func__);
+ msm_isp_axi_free_wm(&vfe_dev->axi_data,
+ stream_info);
+ msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
+ HANDLE_TO_IDX(
+ stream_cfg_cmd->axi_stream_handle));
+ return rc;
+ }
}
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
@@ -763,8 +791,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.
- stream_framedrop_count[stream_idx]++;
+ if(stream_idx < MAX_NUM_STREAM)
+ vfe_dev->error_info.
+ stream_framedrop_count[stream_idx]++;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index b479857..8b83144 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -39,8 +39,9 @@
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
if (rc < 0) {
- vfe_dev->error_info.stats_framedrop_count[
- STATS_IDX(stream_info->stream_handle)]++;
+ uint8_t idx = STATS_IDX(stream_info->stream_handle);
+ if (idx < MSM_ISP_STATS_MAX)
+ vfe_dev->error_info.stats_framedrop_count[idx]++;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ea0195d..3cb48d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -77,6 +77,25 @@
.name = "msm_camera_isp",
};
+static void msm_isp_print_fourcc_error(const char *origin,
+ uint32_t fourcc_format)
+{
+ int i;
+ char text[5];
+ text[4] = '\0';
+ for (i = 0; i < 4; i++) {
+ text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+ if ((text[i] < '0') || (text[i] > 'z')) {
+ pr_err("%s: Invalid output format %d (unprintable)\n",
+ origin, fourcc_format);
+ return;
+ }
+ }
+ pr_err("%s: Invalid output format %s\n",
+ origin, text);
+ return;
+}
+
int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client)
{
int rc = 0;
@@ -735,7 +754,7 @@
break;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return val;
@@ -771,7 +790,7 @@
case V4L2_PIX_FMT_QRGGB12:
return QCOM;
default:
- pr_err("%s: Invalid output format\n", __func__);
+ msm_isp_print_fourcc_error(__func__, output_format);
break;
}
return -EINVAL;
@@ -780,6 +799,10 @@
int msm_isp_get_bit_per_pixel(uint32_t output_format)
{
switch (output_format) {
+ case V4L2_PIX_FMT_Y4:
+ return 4;
+ case V4L2_PIX_FMT_Y6:
+ return 6;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -790,6 +813,29 @@
case V4L2_PIX_FMT_QRGGB8:
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_META:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV14:
+ case V4L2_PIX_FMT_NV41:
+ case V4L2_PIX_FMT_YVU410:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YYUV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV411P:
+ case V4L2_PIX_FMT_Y41P:
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
+ case V4L2_PIX_FMT_YUV32:
+ case V4L2_PIX_FMT_YUV410:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_PAL8:
+ case MSM_V4L2_PIX_FMT_META:
return 8;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
@@ -799,6 +845,8 @@
case V4L2_PIX_FMT_QGBRG10:
case V4L2_PIX_FMT_QGRBG10:
case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_Y10:
+ case V4L2_PIX_FMT_Y10BPACK:
return 10;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
@@ -808,21 +856,17 @@
case V4L2_PIX_FMT_QGBRG12:
case V4L2_PIX_FMT_QGRBG12:
case V4L2_PIX_FMT_QRGGB12:
+ case V4L2_PIX_FMT_Y12:
return 12;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV14:
- case V4L2_PIX_FMT_NV41:
- return 8;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_Y16:
return 16;
/*TD: Add more image format*/
default:
- pr_err("%s: Invalid output format\n", __func__);
- break;
+ msm_isp_print_fourcc_error(__func__, output_format);
+ return -EINVAL;
}
- return -EINVAL;
}
void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 8f080ce..407b81f 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -31,14 +31,19 @@
int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
long clk_rate)
{
- struct msm_cam_clk_info jpeg_core_clk_info[] = {
- {"core_clk", JPEG_CLK_RATE, 0}
- };
+ int rc = 0;
+ struct clk *jpeg_clk;
- jpeg_core_clk_info[0].clk_rate = clk_rate;
+ jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk");
+ if (IS_ERR(jpeg_clk)) {
+ JPEG_PR_ERR("%s get failed\n", "core_clk");
+ rc = PTR_ERR(jpeg_clk);
+ return rc;
+ }
- return msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_core_clk_info,
- pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_core_clk_info), 1);
+ rc = clk_set_rate(jpeg_clk, clk_rate);
+
+ return rc;
}
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index c79b3a3..8a2c8e5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -1001,8 +1001,10 @@
video_set_drvdata(pvdev->vdev, pvdev);
msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
- if (WARN_ON(!msm_session_q))
- goto v4l2_fail;
+ if (WARN_ON(!msm_session_q)) {
+ rc = -ENOMEM;
+ goto session_fail;
+ }
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
@@ -1010,6 +1012,8 @@
INIT_LIST_HEAD(&ordered_sd_list);
goto probe_end;
+session_fail:
+ video_unregister_device(pvdev->vdev);
v4l2_fail:
v4l2_device_unregister(pvdev->vdev->v4l2_dev);
register_fail:
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 69f0a3d..532bebc 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
@@ -1845,6 +1845,11 @@
cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
GFP_KERNEL);
+ if (!cpp_dev->work) {
+ pr_err("cpp_dev->work is NULL\n");
+ rc = -ENOMEM;
+ goto ERROR3;
+ }
INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
cpp_dev->cpp_open_cnt = 0;
cpp_dev->is_firmware_loaded = 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index dc29199..8d14363 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -691,43 +691,47 @@
if (queue->len > 0) {
frame_qcmd = msm_dequeue(queue, list_frame);
- processed_frame = frame_qcmd->command;
- do_gettimeofday(&(processed_frame->out_time));
- kfree(frame_qcmd);
- event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
- if (!event_qcmd) {
- pr_err("%s: Insufficient memory\n", __func__);
- return -ENOMEM;
- }
- atomic_set(&event_qcmd->on_heap, 1);
- event_qcmd->command = processed_frame;
- VPE_DBG("fid %d\n", processed_frame->frame_id);
- msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+ if(frame_qcmd) {
+ processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("%s: Insufficient memory\n", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ VPE_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
- if (!processed_frame->output_buffer_info.processed_divert) {
- memset(&buff_mgr_info, 0 ,
- sizeof(buff_mgr_info));
- buff_mgr_info.session_id =
- ((processed_frame->identity >> 16) & 0xFFFF);
- buff_mgr_info.stream_id =
- (processed_frame->identity & 0xFFFF);
- buff_mgr_info.frame_id = processed_frame->frame_id;
- buff_mgr_info.timestamp = processed_frame->timestamp;
- buff_mgr_info.index =
- processed_frame->output_buffer_info.index;
- rc = msm_vpe_buffer_ops(vpe_dev,
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(buff_mgr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_vpe_buffer_ops(vpe_dev,
VIDIOC_MSM_BUF_MNGR_BUF_DONE,
&buff_mgr_info);
- if (rc < 0) {
- pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
- __func__);
- rc = -EINVAL;
+ if (rc < 0) {
+ pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+ __func__);
+ rc = -EINVAL;
+ }
}
- }
- v4l2_evt.id = processed_frame->inst_id;
- v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
- v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+ v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ }
+ else
+ rc = -EFAULT;
}
return rc;
}
@@ -1368,6 +1372,8 @@
struct msm_vpe_frame_info_t *process_frame;
VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
event_qcmd = msm_dequeue(queue, list_eventdata);
+ if (NULL == event_qcmd)
+ break;
process_frame = event_qcmd->command;
VPE_DBG("fid %d\n", process_frame->frame_id);
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 45db19c..69c1faa 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -809,6 +809,7 @@
e_ctrl->is_supported = 0;
if (!of_node) {
pr_err("%s dev.of_node NULL\n", __func__);
+ kfree(e_ctrl);
return -EINVAL;
}
@@ -817,6 +818,7 @@
CDBG("cell-index %d, rc %d\n", pdev->id, rc);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
+ kfree(e_ctrl);
return rc;
}
e_ctrl->subdev_id = pdev->id;
@@ -826,12 +828,14 @@
CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
rc = of_property_read_u32(of_node, "qcom,slave-addr",
&temp);
if (rc < 0) {
pr_err("%s failed rc %d\n", __func__, rc);
+ kfree(e_ctrl);
return rc;
}
@@ -844,6 +848,7 @@
struct msm_camera_cci_client), GFP_KERNEL);
if (!e_ctrl->i2c_client.cci_client) {
pr_err("%s failed no memory\n", __func__);
+ kfree(e_ctrl);
return -ENOMEM;
}
@@ -936,6 +941,7 @@
kfree(e_ctrl->eboard_info);
cciclient_free:
kfree(e_ctrl->i2c_client.cci_client);
+ kfree(e_ctrl);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 699142a..b88ac00 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -71,9 +71,9 @@
case MSM_CAMERA_LED_LOW:
if (fctrl->torch_trigger) {
max_curr_l = fctrl->torch_max_current;
- if (cfg->led_current > 0 &&
- cfg->led_current < max_curr_l) {
- curr_l = cfg->led_current;
+ if (cfg->torch_current > 0 &&
+ cfg->torch_current < max_curr_l) {
+ curr_l = cfg->torch_current;
} else {
curr_l = fctrl->torch_op_current;
pr_err("LED current clamped to %d\n",
@@ -90,9 +90,9 @@
for (i = 0; i < fctrl->num_sources; i++)
if (fctrl->flash_trigger[i]) {
max_curr_l = fctrl->flash_max_current[i];
- if (cfg->led_current > 0 &&
- cfg->led_current < max_curr_l) {
- curr_l = cfg->led_current;
+ if (cfg->flash_current[i] > 0 &&
+ cfg->flash_current[i] < max_curr_l) {
+ curr_l = cfg->flash_current[i];
} else {
curr_l = fctrl->flash_op_current[i];
pr_err("LED current clamped to %d\n",
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 19a378f..5694658 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -3964,6 +3964,58 @@
}
EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct mpq_video_feed_info *feed_data;
+ struct dvb_ringbuffer *buffer;
+ struct ion_handle *ion_handle;
+ int ret = 0;
+ int i;
+
+ if (!dvb_dmx_is_video_feed(feed)) {
+ if (dvb_dmx_is_sec_feed(feed) ||
+ dvb_dmx_is_pcr_feed(feed)) {
+ buffer = (struct dvb_ringbuffer *)
+ &mpq_feed->sdmx_buf;
+ ion_handle = mpq_feed->sdmx_buf_handle;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ feed->feed.ts.buffer.ringbuff;
+ ion_handle = feed->feed.ts.buffer.priv_handle;
+ }
+
+ ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+ ion_handle, buffer->data,
+ buffer->size, ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Video buffers */
+ feed_data = &mpq_feed->video_info;
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ /* Non-secured buffer */
+ ret = msm_ion_do_cache_op(
+ mpq_feed->mpq_demux->ion_client,
+ feed_data->buffer_desc.ion_handle[i],
+ feed_data->buffer_desc.desc[i].base,
+ feed_data->buffer_desc.desc[i].size,
+ ION_IOC_INV_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+ }
+ }
+
+ return ret;
+}
+
static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
struct sdmx_filter_status *filter_sts,
struct mpq_feed *mpq_feed)
@@ -4757,6 +4809,9 @@
mpq_feed->session_id))
continue;
+ /* Invalidate output buffer before processing the results */
+ mpq_sdmx_invalidate_buffer(mpq_feed);
+
if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
MPQ_DVB_ERR_PRINT(
"%s: meta-data buff for pid %d overflowed!\n",
@@ -4831,7 +4886,6 @@
for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
mpq_feed = &mpq_demux->feeds[i];
if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
- && (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
&& (!mpq_feed->secondary_feed)) {
sts = mpq_demux->sdmx_filters_state.status +
filter_index;
@@ -4950,6 +5004,10 @@
const char *buf,
size_t count)
{
+ struct ion_handle *ion_handle =
+ mpq_demux->demux.dmx.dvr_input.priv_handle;
+ struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+ mpq_demux->demux.dmx.dvr_input.ringbuff;
struct sdmx_buff_descr buf_desc;
u32 read_offset;
int ret;
@@ -4968,6 +5026,19 @@
}
read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
+
+ /*
+ * We must flush the buffer before SDMX starts reading from it
+ * so that it gets a valid data in memory.
+ */
+ ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+ ion_handle, rbuf->data,
+ rbuf->size, ION_IOC_CLEAN_CACHES);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_do_cache_op failed, ret = %d\n",
+ __func__, ret);
+
return mpq_sdmx_process(mpq_demux, &buf_desc, count,
read_offset, mpq_demux->demux.ts_packet_size);
}
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 9a9b385..2e8837d 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -105,6 +105,7 @@
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
FMDERR("Memory not allocated for the socket");
+ kfree(worker);
return;
}
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a554749..3886c52 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3159,7 +3159,7 @@
struct v4l2_ext_controls *ctrl)
{
int retval = 0;
- int bytes_to_copy;
+ size_t bytes_to_copy;
struct hci_fm_tx_ps tx_ps;
struct hci_fm_tx_rt tx_rt;
struct hci_fm_def_data_wr_req default_data;
@@ -3168,18 +3168,20 @@
struct iris_device *radio = video_get_drvdata(video_devdata(file));
char *data = NULL;
- if (radio == NULL) {
- FMDERR(":radio is null");
- return -EINVAL;
+ if ((ctrl == NULL) || (ctrl->controls == NULL)
+ || (ctrl->count == 0)) {
+ retval = -EINVAL;
+ return retval;
}
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME:
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
/*Pass a sample PS string */
memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
- bytes_to_copy = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_to_copy = min(ctrl->controls[0].size,
+ (size_t)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
if (copy_from_user(tx_ps.ps_data,
@@ -3196,7 +3198,7 @@
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
bytes_to_copy =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (size_t)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
@@ -4470,11 +4472,11 @@
if (kfifo_alloc_rc != 0) {
FMDERR("failed allocating buffers %d\n",
kfifo_alloc_rc);
- for (; i > -1; i--) {
+ for (; i > -1; i--)
kfifo_free(&radio->data_buf[i]);
- kfree(radio);
- return -ENOMEM;
- }
+ video_device_release(radio->videodev);
+ kfree(radio);
+ return -ENOMEM;
}
}
@@ -4502,8 +4504,17 @@
} else {
priv_videodev = kzalloc(sizeof(struct video_device),
GFP_KERNEL);
- memcpy(priv_videodev, radio->videodev,
- sizeof(struct video_device));
+ if (priv_videodev != NULL) {
+ memcpy(priv_videodev, radio->videodev,
+ sizeof(struct video_device));
+ } else {
+ video_unregister_device(radio->videodev);
+ video_device_release(radio->videodev);
+ for (; i > -1; i--)
+ kfifo_free(&radio->data_buf[i]);
+ kfree(radio);
+ return -ENOMEM;
+ }
}
return 0;
}
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 6b9f2b3..c44e2a5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -185,6 +185,10 @@
if (bahama_present == -ENODEV)
return -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
if (bahama_present)
radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
else
@@ -216,6 +220,11 @@
* (otherwise, it may have already been there and will not be added a second
* time).
*/
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
queue_delayed_work(radio->wqueue, &radio->work,
msecs_to_jiffies(TAVARUA_DELAY));
return IRQ_HANDLED;
@@ -243,6 +252,12 @@
unsigned char offset, int len)
{
int retval = 0, i = 0;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -282,6 +297,12 @@
unsigned char offset, unsigned char value)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -322,6 +343,12 @@
int i;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = set_fm_slave_id(radio);
if (retval == -ENODEV)
@@ -358,6 +385,11 @@
*/
static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* read all 3 RDS blocks */
return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
}
@@ -376,10 +408,17 @@
*/
static void tavarua_rds_read(struct tavarua_device *radio)
{
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
unsigned char blocknum;
unsigned char tmp[3];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
if (read_data_blocks(radio, RAW_RDS) < 0)
return;
/* copy all four RDS blocks to internal buffer */
@@ -430,6 +469,12 @@
static int request_read_xfr(struct tavarua_device *radio,
enum tavarua_xfr_ctrl_t mode){
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
tavarua_write_register(radio, XFRCTRL, mode);
msleep(TAVARUA_DELAY);
return 0;
@@ -457,8 +502,17 @@
static int copy_from_xfr(struct tavarua_device *radio,
enum tavarua_buf_t buf_type, unsigned int n){
- struct kfifo *data_fifo = &radio->data_buf[buf_type];
- unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+ struct kfifo *data_fifo;
+ unsigned char *xfr_regs;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ data_fifo = &radio->data_buf[buf_type];
+ xfr_regs = &radio->registers[XFRCTRL+1];
+
kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
return 0;
}
@@ -496,6 +550,12 @@
char *buf, int len)
{
char buffer[len+1];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memcpy(buffer+1, buf, len);
/* buffer[0] corresponds to XFRCTRL register
set the CTRL bit to 1 for write mode
@@ -520,6 +580,11 @@
static int xfr_intf_own(struct tavarua_device *radio)
{
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
mutex_lock(&radio->lock);
if (radio->xfr_in_progress) {
radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
@@ -552,6 +617,12 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -590,6 +661,17 @@
enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
{
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
retval = xfr_intf_own(radio);
if (retval < 0)
return retval;
@@ -627,6 +709,12 @@
{
int i;
enum tavarua_xfr_t xfr;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
for (i = 0; i < TAVARUA_XFR_MAX; i++) {
if (radio->pending_xfrs[i]) {
radio->xfr_in_progress = 1;
@@ -681,8 +769,16 @@
enum tavarua_evt_t event)
{
- struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+ struct kfifo *data_b;
unsigned char evt = event;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+
FMDBG("updating event_q with event %x\n", event);
if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
wake_up_interruptible(&radio->event_queue);
@@ -707,12 +803,18 @@
static void tavarua_start_xfr(struct tavarua_device *radio,
enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
{
- if (radio->xfr_in_progress)
- radio->pending_xfrs[pending_id] = 1;
- else {
- radio->xfr_in_progress = 1;
- request_read_xfr(radio, xfr_id);
- }
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
+ if (radio->xfr_in_progress)
+ radio->pending_xfrs[pending_id] = 1;
+ else {
+ radio->xfr_in_progress = 1;
+ request_read_xfr(radio, xfr_id);
+ }
}
/*=============================================================================
@@ -739,6 +841,12 @@
int i;
int retval, adj_channel_tune_req = 0;
unsigned char xfr_status;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
if (!radio->handle_irq) {
FMDBG("IRQ happend, but I wont handle it\n");
return;
@@ -1143,15 +1251,34 @@
*/
static void read_int_stat(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
tavarua_handle_interrupts(radio);
}
static void fm_shutdown(struct work_struct *work)
{
- struct tavarua_device *radio = container_of(work,
- struct tavarua_device, work.work);
+ struct tavarua_device *radio;
+
+ if (unlikely(work == NULL)) {
+ FMDERR("%s:work is null", __func__);
+ return;
+ }
+
+ radio = container_of(work, struct tavarua_device, work.work);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return;
+ }
+
FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
if (radio->pdata->config_i2s_gpio != NULL)
radio->pdata->config_i2s_gpio(FM_I2S_OFF);
@@ -1178,9 +1305,14 @@
static int tavarua_request_irq(struct tavarua_device *radio)
{
int retval;
- int irq = radio->pdata->irq;
- if (radio == NULL)
+ int irq;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
+ irq = radio->pdata->irq;
/* A workqueue created with create_workqueue() will have one worker thread
* for each CPU on the system; create_singlethread_workqueue(), instead,
@@ -1237,8 +1369,12 @@
static int tavarua_disable_irq(struct tavarua_device *radio)
{
int irq;
- if (!radio)
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
return -EINVAL;
+ }
+
irq = radio->pdata->irq;
disable_irq_wake(irq);
free_irq(irq, radio);
@@ -1255,6 +1391,11 @@
unsigned int rdsMask = 0;
unsigned char value = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
switch (region) {
@@ -1435,9 +1576,17 @@
*/
static int tavarua_search(struct tavarua_device *radio, int on, int dir)
{
- enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+ enum search_t srch;
FMDBG("In tavarua_search\n");
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
if (on) {
radio->registers[SRCHRDS1] = 0x00;
radio->registers[SRCHRDS2] = 0x00;
@@ -1503,6 +1652,11 @@
enum tavarua_region_t region = req_region;
unsigned char adie_type_bahma;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
adie_type_bahma = is_bahama();
/* Set freq band */
@@ -1671,6 +1825,17 @@
unsigned short chan;
unsigned int band_bottom;
unsigned int spacing;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
/* read channel */
@@ -1716,6 +1881,12 @@
unsigned char cmd[] = {0x00, 0x00};
unsigned int spacing;
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
band_bottom = radio->region_params.band_low;
spacing = 0.100 * FREQ_MUL;
if ((freq % 1600) == 800) {
@@ -1760,8 +1931,19 @@
size_t count, loff_t *ppos)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
- struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+ struct kfifo *rds_buf;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
+
+ rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
/* block if no new data available */
while (!kfifo_len(rds_buf)) {
if (file->f_flags & O_NONBLOCK)
@@ -1810,6 +1992,17 @@
int bytes_left;
int chunk_index = 0;
unsigned char tx_data[XFR_REG_NUM];
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(data == NULL)) {
+ FMDERR("%s:data is null", __func__);
+ return -EINVAL;
+ }
+
/* Disable TX of this type first */
switch (radio->tx_mode) {
case TAVARUA_TX_RT:
@@ -1897,6 +2090,11 @@
char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
int bahama_present = -ENODEV;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
INIT_DELAYED_WORK(&radio->work, read_int_stat);
if (!atomic_dec_and_test(&radio->users)) {
pr_err("%s: Device already in use."
@@ -2518,6 +2716,16 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(capability == NULL)) {
+ FMDERR("%s:capability is null", __func__);
+ return -EINVAL;
+ }
+
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
sprintf(capability->bus_info, "I2C");
@@ -2553,6 +2761,12 @@
unsigned char i;
int retval = -EINVAL;
+ if (unlikely(qc == NULL)) {
+ FMDERR("%s:qc is null", __func__);
+ return -EINVAL;
+ }
+
+
for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2574,6 +2788,11 @@
int index = 0, offset = 0, addr = 0x0, val = 0;
int retval = 0, temp = 0, cnt = 0, j = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
/* Read the SPUR Table Size */
@@ -2651,6 +2870,15 @@
unsigned char xfr_buf[XFR_REG_NUM + 1];
int retval = 0, temp = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(buf == NULL)) {
+ FMDERR("%s:buf is null", __func__);
+ return -EINVAL;
+ }
/* zero initialize the buffer */
memset(xfr_buf, 0x0, XFR_REG_NUM);
@@ -2725,6 +2953,11 @@
int ct = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/*
Poking the MPX_DCC_BYPASS register to freeze the
value of MPX_DCC from changing while we access it
@@ -2844,6 +3077,16 @@
signed char ioc;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
break;
@@ -3059,6 +3302,18 @@
int extra_name_byte = 0;
int name_bytes = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL) ||
+ unlikely(ctrl->controls == NULL) ||
+ unlikely(ctrl->count <= 0)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
switch ((ctrl->controls[0]).id) {
case V4L2_CID_RDS_TX_PS_NAME: {
FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3191,6 +3446,16 @@
unsigned int freq = 0, mpx_dcc = 0;
unsigned long curr = 0, prev = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(ctrl == NULL)) {
+ FMDERR("%s:ctrl is null", __func__);
+ return -EINVAL;
+ }
+
memset(xfr_buf, 0x0, XFR_REG_NUM);
switch (ctrl->id) {
@@ -3797,6 +4062,16 @@
char rmssi = 0;
unsigned char size = 0;
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3863,6 +4138,17 @@
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int retval;
int audmode;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(tuner == NULL)) {
+ FMDERR("%s:tuner is null", __func__);
+ return -EINVAL;
+ }
+
if (tuner->index > 0)
return -EINVAL;
@@ -3910,6 +4196,17 @@
struct v4l2_frequency *freq)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
freq->type = V4L2_TUNER_RADIO;
return tavarua_get_freq(radio, freq);
@@ -3945,6 +4242,16 @@
FMDBG("%s\n", __func__);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(freq == NULL)) {
+ FMDERR("%s:freq is null", __func__);
+ return -EINVAL;
+ }
+
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -4108,6 +4415,17 @@
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
int dir;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(seek == NULL)) {
+ FMDERR("%s:seek is null", __func__);
+ return -EINVAL;
+ }
+
if (seek->seek_upward)
dir = SRCH_DIR_UP;
else
@@ -4159,6 +4477,11 @@
int retval;
unsigned char int_ctrl[XFR_REG_NUM];
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (!radio->lp_mode)
return 0;
@@ -4222,6 +4545,12 @@
{
unsigned char lpm_buf[XFR_REG_NUM];
int retval;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio->lp_mode)
return 0;
FMDBG("%s\n", __func__);
@@ -4270,6 +4599,12 @@
int retval;
FMDBG("%s <%d>\n", __func__, state);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* set geographic region */
radio->region_params.region = TAVARUA_REGION_US;
@@ -4305,6 +4640,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
if (!users) {
@@ -4336,6 +4677,12 @@
int retval;
int users = 0;
printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
if (radio) {
users = atomic_read(&radio->users);
@@ -4380,8 +4727,12 @@
struct tavarua_device *radio = private_data;
int rx_on = radio->registers[RDCTRL] & FM_RECV;
int retval = 0;
- if (!radio)
- return -ENOMEM;
+
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* RX */
FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
@@ -4469,6 +4820,12 @@
int retval = 0;
int i = 0, j = 0;
FMDBG("%s: probe called\n", __func__);
+
+ if (unlikely(pdev == NULL)) {
+ FMDERR("%s:pdev is null", __func__);
+ return -EINVAL;
+ }
+
/* private data allocation */
radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
if (!radio) {
@@ -4593,6 +4950,11 @@
int i;
struct tavarua_device *radio = platform_get_drvdata(pdev);
+ if (unlikely(radio == NULL)) {
+ FMDERR("%s:radio is null", __func__);
+ return -EINVAL;
+ }
+
/* disable irq */
tavarua_disable_irq(radio);
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9dd06ee..127a231 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -310,6 +310,7 @@
"Scalable High",
"Scalable High Intra",
"Multiview High",
+ "Constrained High",
NULL,
};
static const char * const vui_sar_idc[] = {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 3d69473..19f26f2 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1706,6 +1706,8 @@
dma_free_coherent(NULL, config->desc.size, config->desc.base,
config->desc.phys_base);
+ sps_free_endpoint(channel->pipe);
+
tspp_destroy_buffers(channel_id, channel);
if (channel->dma_pool) {
dma_pool_destroy(channel->dma_pool);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 421774f..b36faff 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -467,6 +467,7 @@
}
kfree(card->wr_pack_stats.packing_events);
+ kfree(card->cached_ext_csd);
put_device(&card->dev);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 997e14b..b295bb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1189,9 +1189,9 @@
mmc_set_timing(card->host, MMC_TIMING_LEGACY);
mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
- err = mmc_select_hs(card, &card->cached_ext_csd);
+ err = mmc_select_hs(card, card->cached_ext_csd);
} else {
- err = mmc_select_hs400(card, &card->cached_ext_csd);
+ err = mmc_select_hs400(card, card->cached_ext_csd);
}
return err;
@@ -1439,7 +1439,7 @@
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
- memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
+ card->cached_ext_csd = ext_csd;
err = mmc_read_ext_csd(card, ext_csd);
if (err)
goto free_card;
@@ -1637,15 +1637,12 @@
if (!oldcard)
host->card = card;
- mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- mmc_free_ext_csd(ext_csd);
-
return err;
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 95f0a04..c335be1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6962,7 +6962,7 @@
static const struct of_device_id msmsdcc_dt_match[] = {
{.compatible = "qcom,msm-sdcc"},
-
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index e391a06..4d3a560 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -3113,6 +3113,7 @@
#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 76eb15b..12c5704 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -50,6 +50,7 @@
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -355,7 +356,7 @@
int fw_cal_available;
int user_cal_read;
int user_cal_available;
- int user_cal_rcvd;
+ u32 user_cal_rcvd;
int user_cal_exp_size;
int device_opened;
int iris_xo_mode_set;
@@ -2134,7 +2135,7 @@
*user_buffer, size_t count, loff_t *position)
{
int rc = 0;
- int size = 0;
+ size_t size = 0;
if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
@@ -2142,7 +2143,7 @@
if (penv->user_cal_rcvd == 0 && count >= 4
&& !penv->user_cal_data) {
rc = copy_from_user((void *)&size, user_buffer, 4);
- if (size > MAX_CALIBRATED_DATA_SIZE) {
+ if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
pr_err(DEVICE " invalid size to write %d\n", size);
return -EFAULT;
}
@@ -2161,7 +2162,8 @@
} else if (penv->user_cal_rcvd == 0 && count < 4)
return -EFAULT;
- if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+ if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+ MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
pr_err(DEVICE " invalid size to write %d\n", count +
penv->user_cal_rcvd);
rc = -ENOMEM;
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
index c55ed09..696c84f 100644
--- a/drivers/platform/msm/qpnp-clkdiv.c
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* 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
@@ -202,6 +202,7 @@
if (!res) {
dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
__func__);
+ return -EINVAL;
}
q_clkdiv->slave = spmi->sid;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8572616..6ea4ea6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1285,6 +1285,21 @@
return 0;
}
+static int
+qpnp_chg_vddmax_get(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 vddmax = 0;
+
+ rc = qpnp_chg_read(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+ if (rc) {
+ pr_err("Failed to write vddmax: %d\n", rc);
+ return rc;
+ }
+
+ return QPNP_CHG_V_MIN_MV + (int)vddmax * QPNP_CHG_V_STEP_MV;
+}
+
/* JEITA compliance logic */
static void
qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -2077,6 +2092,8 @@
if (battery_status != POWER_SUPPLY_STATUS_CHARGING
&& bms_status != POWER_SUPPLY_STATUS_CHARGING
&& charger_in
+ && !chip->bat_is_cool
+ && !chip->bat_is_warm
&& !chip->resuming_charging
&& !chip->charging_disabled
&& chip->soc_resume_limit
@@ -3118,10 +3135,17 @@
count = 0;
} else {
if (count == CONSECUTIVE_COUNT) {
- pr_info("End of Charging\n");
+ if (!chip->bat_is_cool && !chip->bat_is_warm) {
+ pr_info("End of Charging\n");
+ chip->chg_done = true;
+ } else {
+ pr_info("stop charging: battery is %s, vddmax = %d reached\n",
+ chip->bat_is_cool
+ ? "cool" : "warm",
+ qpnp_chg_vddmax_get(chip));
+ }
chip->delta_vddmax_mv = 0;
qpnp_chg_set_appropriate_vddmax(chip);
- chip->chg_done = true;
qpnp_chg_charge_en(chip, 0);
/* sleep for a second before enabling */
msleep(2000);
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 01dce2d..0d17026 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,7 +7,7 @@
obj-$(CONFIG_THERMAL_TSENS) += msm_tsens.o
obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
obj-$(CONFIG_THERMAL_PM8XXX) += pm8xxx-tm.o
-obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o
+obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o msm_thermal-dev.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o
obj-$(CONFIG_THERMAL_QPNP) += qpnp-temp-alarm.o
diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c
new file mode 100644
index 0000000..c34dd27
--- /dev/null
+++ b/drivers/thermal/msm_thermal-dev.c
@@ -0,0 +1,224 @@
+/* Copyright (c) 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/kernel.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/msm_thermal_ioctl.h>
+#include <linux/msm_thermal.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+
+struct msm_thermal_ioctl_dev {
+ struct semaphore sem;
+ struct cdev char_dev;
+};
+
+static int msm_thermal_major;
+static struct class *thermal_class;
+static struct msm_thermal_ioctl_dev *msm_thermal_dev;
+
+static int msm_thermal_ioctl_open(struct inode *node, struct file *filep)
+{
+ int ret = 0;
+ struct msm_thermal_ioctl_dev *dev;
+
+ dev = container_of(node->i_cdev, struct msm_thermal_ioctl_dev,
+ char_dev);
+ filep->private_data = dev;
+
+ return ret;
+}
+
+static int msm_thermal_ioctl_release(struct inode *node, struct file *filep)
+{
+ pr_debug("%s: IOCTL: release\n", KBUILD_MODNAME);
+ return 0;
+}
+
+static long validate_and_copy(unsigned int *cmd, unsigned long *arg,
+ struct msm_thermal_ioctl *query)
+{
+ long ret = 0, err_val = 0;
+
+ if ((_IOC_TYPE(*cmd) != MSM_THERMAL_MAGIC_NUM) ||
+ (_IOC_NR(*cmd) >= MSM_CMD_MAX_NR)) {
+ ret = -ENOTTY;
+ goto validate_exit;
+ }
+
+ if (_IOC_DIR(*cmd) & _IOC_READ) {
+ err_val = !access_ok(VERIFY_WRITE, (void __user *)*arg,
+ _IOC_SIZE(*cmd));
+ } else if (_IOC_DIR(*cmd) & _IOC_WRITE) {
+ err_val = !access_ok(VERIFY_READ, (void __user *)*arg,
+ _IOC_SIZE(*cmd));
+ }
+ if (err_val) {
+ ret = -EFAULT;
+ goto validate_exit;
+ }
+
+ if (copy_from_user(query, (void __user *)(*arg),
+ sizeof(struct msm_thermal_ioctl))) {
+ ret = -EACCES;
+ goto validate_exit;
+ }
+
+ if (query->size != sizeof(struct msm_thermal_ioctl)) {
+ pr_err("%s: Invalid input argument size\n", __func__);
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+
+ switch (*cmd) {
+ case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+ case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+ if (query->cpu_freq.cpu_num >= num_possible_cpus()) {
+ pr_err("%s: Invalid CPU number: %u\n", __func__,
+ query->cpu_freq.cpu_num);
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ goto validate_exit;
+ break;
+ }
+
+validate_exit:
+ return ret;
+}
+
+static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+ struct msm_thermal_ioctl query;
+
+ pr_debug("%s: IOCTL: processing cmd:%u\n", KBUILD_MODNAME, cmd);
+
+ ret = validate_and_copy(&cmd, &arg, &query);
+ if (ret)
+ goto process_exit;
+
+ switch (cmd) {
+ case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
+ ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+ query.cpu_freq.freq_req, true);
+ break;
+ case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
+ ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
+ query.cpu_freq.freq_req, false);
+ break;
+ default:
+ ret = -ENOTTY;
+ goto process_exit;
+ }
+process_exit:
+ return ret;
+}
+
+static const struct file_operations msm_thermal_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_thermal_ioctl_open,
+ .unlocked_ioctl = msm_thermal_ioctl_process,
+ .release = msm_thermal_ioctl_release,
+};
+
+int msm_thermal_ioctl_init()
+{
+ int ret = 0;
+ dev_t thermal_dev;
+ struct device *therm_device;
+
+ ret = alloc_chrdev_region(&thermal_dev, 0, 1,
+ MSM_THERMAL_IOCTL_NAME);
+ if (ret < 0) {
+ pr_err("%s: Error in allocating char device region. Err:%d\n",
+ KBUILD_MODNAME, ret);
+ goto ioctl_init_exit;
+ }
+
+ msm_thermal_major = MAJOR(thermal_dev);
+
+ thermal_class = class_create(THIS_MODULE, "msm_thermal");
+ if (IS_ERR(thermal_class)) {
+ pr_err("%s: Error in creating class\n",
+ KBUILD_MODNAME);
+ ret = PTR_ERR(thermal_class);
+ goto ioctl_class_fail;
+ }
+
+ therm_device = device_create(thermal_class, NULL, thermal_dev, NULL,
+ MSM_THERMAL_IOCTL_NAME);
+ if (IS_ERR(therm_device)) {
+ pr_err("%s: Error in creating character device\n",
+ KBUILD_MODNAME);
+ ret = PTR_ERR(therm_device);
+ goto ioctl_dev_fail;
+ }
+ msm_thermal_dev = kmalloc(sizeof(struct msm_thermal_ioctl_dev),
+ GFP_KERNEL);
+ if (!msm_thermal_dev) {
+ pr_err("%s: Error allocating memory\n",
+ KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto ioctl_clean_all;
+ }
+
+ memset(msm_thermal_dev, 0, sizeof(struct msm_thermal_ioctl_dev));
+ sema_init(&msm_thermal_dev->sem, 1);
+ cdev_init(&msm_thermal_dev->char_dev, &msm_thermal_fops);
+ ret = cdev_add(&msm_thermal_dev->char_dev, thermal_dev, 1);
+ if (ret < 0) {
+ pr_err("%s: Error in adding character device\n",
+ KBUILD_MODNAME);
+ goto ioctl_clean_all;
+ }
+
+ return ret;
+
+ioctl_clean_all:
+ device_destroy(thermal_class, thermal_dev);
+ioctl_dev_fail:
+ class_destroy(thermal_class);
+ioctl_class_fail:
+ unregister_chrdev_region(thermal_dev, 1);
+ioctl_init_exit:
+ return ret;
+}
+
+void msm_thermal_ioctl_cleanup()
+{
+ dev_t thermal_dev = MKDEV(msm_thermal_major, 0);
+
+ if (!msm_thermal_dev) {
+ pr_err("%s: Thermal IOCTL cleanup already done\n",
+ KBUILD_MODNAME);
+ return;
+ }
+
+ device_destroy(thermal_class, thermal_dev);
+ class_destroy(thermal_class);
+ cdev_del(&msm_thermal_dev->char_dev);
+ unregister_chrdev_region(thermal_dev, 1);
+ kfree(msm_thermal_dev);
+ msm_thermal_dev = NULL;
+ thermal_class = NULL;
+}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index e9bb553..c366086 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -35,13 +35,13 @@
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
+#include <linux/msm_thermal_ioctl.h>
+#define MAX_CURRENT_UA 1000000
#define MAX_RAILS 5
#define MAX_THRESHOLD 2
static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = UINT_MAX;
-static uint32_t limited_min_freq;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -52,11 +52,14 @@
static struct kobject *cc_kobj;
static struct work_struct timer_work;
static struct task_struct *hotplug_task;
+static struct task_struct *freq_mitigation_task;
static struct completion hotplug_notify_complete;
+static struct completion freq_mitigation_complete;
static int enabled;
static int rails_cnt;
static int psm_rails_cnt;
+static int ocr_rail_cnt;
static int limit_idx;
static int limit_idx_low;
static int limit_idx_high;
@@ -71,18 +74,38 @@
static bool psm_nodes_called;
static bool psm_probed;
static bool hotplug_enabled;
+static bool freq_mitigation_enabled;
+static bool ocr_enabled;
+static bool ocr_nodes_called;
+static bool ocr_probed;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
+static DEFINE_MUTEX(ocr_mutex);
+static uint32_t min_freq_limit;
+
+enum thermal_threshold {
+ HOTPLUG_THRESHOLD_HIGH,
+ HOTPLUG_THRESHOLD_LOW,
+ FREQ_THRESHOLD_HIGH,
+ FREQ_THRESHOLD_LOW,
+ THRESHOLD_MAX_NR,
+};
struct cpu_info {
uint32_t cpu;
- bool offline;
- bool user_offline;
- bool thresh_cleared;
const char *sensor_type;
uint32_t sensor_id;
- struct sensor_threshold thresh[MAX_THRESHOLD];
+ bool offline;
+ bool user_offline;
+ bool hotplug_thresh_clear;
+ struct sensor_threshold threshold[THRESHOLD_MAX_NR];
+ bool max_freq;
+ uint32_t user_max_freq;
+ uint32_t user_min_freq;
+ uint32_t limited_max_freq;
+ uint32_t limited_min_freq;
+ bool freq_thresh_clear;
};
struct rail {
@@ -104,10 +127,12 @@
uint8_t mode;
struct kobj_attribute mode_attr;
struct rpm_regulator *reg;
+ struct regulator *phase_reg;
struct attribute_group attr_gp;
};
static struct psm_rail *psm_rails;
+static struct psm_rail *ocr_rails;
static struct rail *rails;
static struct cpu_info cpus[NR_CPUS];
@@ -123,6 +148,12 @@
PMIC_PWM_MODE = RPM_REGULATOR_MODE_HPM,
};
+enum ocr_request {
+ OPTIMUM_CURRENT_MIN,
+ OPTIMUM_CURRENT_MAX,
+ OPTIMUM_CURRENT_NR,
+};
+
#define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
ko_attr.attr.name = __stringify(_name); \
ko_attr.attr.mode = 444; \
@@ -148,6 +179,14 @@
#define VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr) \
(container_of(attr, struct rail, level_attr));
+#define OCR_RW_ATTRIB(_rail, ko_attr, j, _name) \
+ ko_attr.attr.name = __stringify(_name); \
+ ko_attr.attr.mode = 644; \
+ ko_attr.show = ocr_reg_##_name##_show; \
+ ko_attr.store = ocr_reg_##_name##_store; \
+ sysfs_attr_init(&ko_attr.attr); \
+ _rail.attr_gp.attrs[j] = &ko_attr.attr;
+
#define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
ko_attr.attr.name = __stringify(_name); \
ko_attr.attr.mode = 644; \
@@ -163,11 +202,20 @@
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
+ uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq;
+ uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq;
switch (event) {
case CPUFREQ_INCOMPATIBLE:
- cpufreq_verify_within_limits(policy, limited_min_freq,
- limited_max_freq);
+ pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n",
+ KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req);
+
+ cpufreq_verify_within_limits(policy, min_freq_req,
+ max_freq_req);
+
+ if (max_freq_req < min_freq_req)
+ pr_err("Invalid frequency request Max:%u Min:%u\n",
+ max_freq_req, min_freq_req);
break;
}
return NOTIFY_OK;
@@ -193,9 +241,17 @@
return ret;
}
+static void update_cpu_freq(int cpu)
+{
+ if (cpu_online(cpu)) {
+ if (cpufreq_update_policy(cpu))
+ pr_err("Unable to update policy for cpu:%d\n", cpu);
+ }
+}
+
static int update_cpu_min_freq_all(uint32_t min)
{
- int cpu = 0;
+ uint32_t cpu = 0;
int ret = 0;
if (!freq_table_get) {
@@ -208,15 +264,17 @@
/* If min is larger than allowed max */
min = min(min, table[limit_idx_high].frequency);
- limited_min_freq = min;
-
- get_online_cpus();
- for_each_online_cpu(cpu) {
- if (cpufreq_update_policy(cpu))
- pr_info("%s: Unable to update policy for cpu:%d\n",
- KBUILD_MODNAME, cpu);
+ if (freq_mitigation_task) {
+ min_freq_limit = min;
+ complete(&freq_mitigation_complete);
+ } else {
+ get_online_cpus();
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].limited_min_freq = min;
+ update_cpu_freq(cpu);
+ }
+ put_online_cpus();
}
- put_online_cpus();
return ret;
}
@@ -446,6 +504,92 @@
return count;
}
+static int request_optimum_current(struct psm_rail *rail, enum ocr_request req)
+{
+ int ret = 0;
+
+ if ((!rail) || (req >= OPTIMUM_CURRENT_NR) ||
+ (req < 0)) {
+ pr_err("%s:%s Invalid input\n", KBUILD_MODNAME, __func__);
+ ret = -EINVAL;
+ goto request_ocr_exit;
+ }
+
+ ret = regulator_set_optimum_mode(rail->phase_reg,
+ (req == OPTIMUM_CURRENT_MAX) ? MAX_CURRENT_UA : 0);
+ if (ret < 0) {
+ pr_err("%s: Optimum current request failed\n", KBUILD_MODNAME);
+ goto request_ocr_exit;
+ }
+ ret = 0; /*regulator_set_optimum_mode returns the mode on success*/
+ pr_debug("%s: Requested optimum current mode: %d\n",
+ KBUILD_MODNAME, req);
+
+request_ocr_exit:
+ return ret;
+}
+
+static int ocr_set_mode_all(enum ocr_request req)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ if (ocr_rails[i].mode == req)
+ continue;
+ ret = request_optimum_current(&ocr_rails[i], req);
+ if (ret)
+ goto ocr_set_mode_exit;
+ ocr_rails[i].mode = req;
+ }
+
+ocr_set_mode_exit:
+ return ret;
+}
+
+static int ocr_reg_mode_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+ return snprintf(buf, PAGE_SIZE, "%d\n", reg->mode);
+}
+
+static ssize_t ocr_reg_mode_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret = 0;
+ int val = 0;
+ struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
+
+ if (!ocr_enabled)
+ return count;
+
+ mutex_lock(&ocr_mutex);
+ ret = kstrtoint(buf, 10, &val);
+ if (ret) {
+ pr_err("%s: Invalid input %s for mode\n",
+ KBUILD_MODNAME, buf);
+ goto done_ocr_store;
+ }
+
+ if ((val != OPTIMUM_CURRENT_MAX) &&
+ (val != OPTIMUM_CURRENT_MIN)) {
+ pr_err("%s: Invalid value %d for mode\n",
+ KBUILD_MODNAME, val);
+ goto done_ocr_store;
+ }
+
+ if (val != reg->mode) {
+ ret = request_optimum_current(reg, val);
+ if (ret)
+ goto done_ocr_store;
+ reg->mode = val;
+ }
+
+done_ocr_store:
+ mutex_unlock(&ocr_mutex);
+ return count;
+}
+
static int psm_reg_mode_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
@@ -607,27 +751,6 @@
return ret;
}
-static int update_cpu_max_freq(int cpu, uint32_t max_freq)
-{
- int ret = 0;
-
- if (max_freq != UINT_MAX)
- pr_info("%s: Limiting cpu%d max frequency to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
- else
- pr_info("%s: Max frequency reset for cpu%d\n",
- KBUILD_MODNAME, cpu);
- get_online_cpus();
- for_each_online_cpu(cpu) {
- if (cpufreq_update_policy(cpu))
- pr_info("%s: Unable to update policy for cpu:%d\n",
- KBUILD_MODNAME, cpu);
- }
- put_online_cpus();
-
- return ret;
-}
-
static int set_and_activate_threshold(uint32_t sensor_id,
struct sensor_threshold *threshold)
{
@@ -788,10 +911,11 @@
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
if (hotplug_enabled &&
- cpus[cpu].thresh_cleared) {
+ cpus[cpu].hotplug_thresh_clear) {
set_threshold(cpus[cpu].sensor_id,
- cpus[cpu].thresh);
- cpus[cpu].thresh_cleared = false;
+ &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]);
+
+ cpus[cpu].hotplug_thresh_clear = false;
}
if (cpus[cpu].offline || cpus[cpu].user_offline)
mask |= BIT(cpu);
@@ -816,6 +940,63 @@
}
#endif
+static int do_ocr(void)
+{
+ struct tsens_device tsens_dev;
+ long temp = 0;
+ int ret = 0;
+ int i = 0, j = 0;
+ int auto_cnt = 0;
+
+ if (!ocr_enabled)
+ return ret;
+
+ mutex_lock(&ocr_mutex);
+ for (i = 0; i < max_tsens_num; i++) {
+ tsens_dev.sensor_num = tsens_id_map[i];
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (ret) {
+ pr_debug("%s: Unable to read TSENS sensor %d\n",
+ __func__, tsens_dev.sensor_num);
+ auto_cnt++;
+ continue;
+ }
+
+ if (temp > msm_thermal_info.ocr_temp_degC) {
+ if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+ for (j = 0; j < ocr_rail_cnt; j++)
+ ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+ ret = ocr_set_mode_all(OPTIMUM_CURRENT_MAX);
+ if (ret)
+ pr_err("Error setting max optimum current\n");
+ goto do_ocr_exit;
+ } else if (temp <= (msm_thermal_info.ocr_temp_degC -
+ msm_thermal_info.ocr_temp_hyst_degC))
+ auto_cnt++;
+ }
+
+ if (auto_cnt == max_tsens_num ||
+ ocr_rails[0].init != OPTIMUM_CURRENT_NR) {
+ /* 'init' not equal to OPTIMUM_CURRENT_NR means this is the
+ ** first polling iteration after device probe. During first
+ ** iteration, if temperature is less than the set point, clear
+ ** the max current request made and reset the 'init'.
+ */
+ if (ocr_rails[0].init != OPTIMUM_CURRENT_NR)
+ for (j = 0; j < ocr_rail_cnt; j++)
+ ocr_rails[j].init = OPTIMUM_CURRENT_NR;
+ ret = ocr_set_mode_all(OPTIMUM_CURRENT_MIN);
+ if (ret) {
+ pr_err("Error setting min optimum current\n");
+ goto do_ocr_exit;
+ }
+ }
+
+do_ocr_exit:
+ mutex_unlock(&ocr_mutex);
+ return ret;
+}
+
static int do_vdd_restriction(void)
{
struct tsens_device tsens_dev;
@@ -915,14 +1096,14 @@
static void __ref do_freq_control(long temp)
{
- int cpu = 0;
- uint32_t max_freq = limited_max_freq;
+ uint32_t cpu = 0;
+ uint32_t max_freq = cpus[cpu].limited_max_freq;
if (temp >= msm_thermal_info.limit_temp_degC) {
if (limit_idx == limit_idx_low)
return;
- limit_idx -= msm_thermal_info.freq_step;
+ limit_idx -= msm_thermal_info.bootup_freq_step;
if (limit_idx < limit_idx_low)
limit_idx = limit_idx_low;
max_freq = table[limit_idx].frequency;
@@ -931,7 +1112,7 @@
if (limit_idx == limit_idx_high)
return;
- limit_idx += msm_thermal_info.freq_step;
+ limit_idx += msm_thermal_info.bootup_freq_step;
if (limit_idx >= limit_idx_high) {
limit_idx = limit_idx_high;
max_freq = UINT_MAX;
@@ -939,16 +1120,18 @@
max_freq = table[limit_idx].frequency;
}
- if (max_freq == limited_max_freq)
+ if (max_freq == cpus[cpu].limited_max_freq)
return;
- limited_max_freq = max_freq;
/* Update new limits */
+ get_online_cpus();
for_each_possible_cpu(cpu) {
- if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+ if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu)))
continue;
- update_cpu_max_freq(cpu, max_freq);
+ cpus[cpu].limited_max_freq = max_freq;
+ update_cpu_freq(cpu);
}
+ put_online_cpus();
}
static void __ref check_temp(struct work_struct *work)
@@ -977,6 +1160,7 @@
do_core_control(temp);
do_vdd_restriction();
do_psm();
+ do_ocr();
do_freq_control(temp);
reschedule:
@@ -988,7 +1172,7 @@
static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
- unsigned int cpu = (unsigned long)hcpu;
+ uint32_t cpu = (uint32_t)hcpu;
if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
if (core_control_enabled &&
@@ -1064,7 +1248,7 @@
break;
}
if (hotplug_task) {
- cpu_node->thresh_cleared = true;
+ cpu_node->hotplug_thresh_clear = true;
complete(&hotplug_notify_complete);
} else {
pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
@@ -1076,7 +1260,7 @@
{
struct tsens_device tsens_dev;
long temp = 0;
- int cpu = 0;
+ uint32_t cpu = 0;
if (!hotplug_enabled)
return 0;
@@ -1113,7 +1297,8 @@
static void hotplug_init(void)
{
- int cpu = 0;
+ uint32_t cpu = 0;
+ struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
if (hotplug_task)
return;
@@ -1122,23 +1307,22 @@
goto init_kthread;
for_each_possible_cpu(cpu) {
- cpus[cpu].cpu = (uint32_t)cpu;
- cpus[cpu].thresh_cleared = false;
cpus[cpu].sensor_id =
sensor_get_id((char *)cpus[cpu].sensor_type);
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
- cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
- cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
- cpus[cpu].thresh[0].notify = hotplug_notify;
- cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
- cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+ hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH];
+ low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW];
+ hi_thresh->temp = msm_thermal_info.hotplug_temp_degC;
+ hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ low_thresh->temp = msm_thermal_info.hotplug_temp_degC -
msm_thermal_info.hotplug_temp_hysteresis_degC;
- cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
- cpus[cpu].thresh[1].notify = hotplug_notify;
- cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
- set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
+ low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ hi_thresh->notify = low_thresh->notify = hotplug_notify;
+ hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+
+ set_threshold(cpus[cpu].sensor_id, hi_thresh);
}
init_kthread:
init_completion(&hotplug_notify_complete);
@@ -1156,6 +1340,167 @@
kthread_stop(hotplug_task);
}
+static __ref int do_freq_mitigation(void *data)
+{
+ int ret = 0;
+ uint32_t cpu = 0, max_freq_req = 0, min_freq_req = 0;
+
+ while (!kthread_should_stop()) {
+ wait_for_completion(&freq_mitigation_complete);
+ INIT_COMPLETION(freq_mitigation_complete);
+
+ get_online_cpus();
+ for_each_possible_cpu(cpu) {
+ max_freq_req = (cpus[cpu].max_freq) ?
+ msm_thermal_info.freq_limit :
+ UINT_MAX;
+ max_freq_req = min(max_freq_req,
+ cpus[cpu].user_max_freq);
+
+ min_freq_req = max(min_freq_limit,
+ cpus[cpu].user_min_freq);
+
+ if ((max_freq_req == cpus[cpu].limited_max_freq)
+ && (min_freq_req ==
+ cpus[cpu].limited_min_freq))
+ goto reset_threshold;
+
+ cpus[cpu].limited_max_freq = max_freq_req;
+ cpus[cpu].limited_min_freq = min_freq_req;
+ update_cpu_freq(cpu);
+reset_threshold:
+ if (freq_mitigation_enabled &&
+ cpus[cpu].freq_thresh_clear) {
+ set_threshold(cpus[cpu].sensor_id,
+ &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]);
+
+ cpus[cpu].freq_thresh_clear = false;
+ }
+ }
+ put_online_cpus();
+ }
+ return ret;
+}
+
+static int freq_mitigation_notify(enum thermal_trip_type type,
+ int temp, void *data)
+{
+ struct cpu_info *cpu_node = (struct cpu_info *) data;
+
+ pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME,
+ cpu_node->sensor_type, temp);
+
+ if (!(msm_thermal_info.freq_mitig_control_mask &
+ BIT(cpu_node->cpu)))
+ return 0;
+
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (!cpu_node->max_freq) {
+ pr_info("%s: Mitigating cpu %d frequency to %d\n",
+ KBUILD_MODNAME, cpu_node->cpu,
+ msm_thermal_info.freq_limit);
+
+ cpu_node->max_freq = true;
+ }
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (cpu_node->max_freq) {
+ pr_info("%s: Removing frequency mitigation for cpu%d\n",
+ KBUILD_MODNAME, cpu_node->cpu);
+
+ cpu_node->max_freq = false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (freq_mitigation_task) {
+ cpu_node->freq_thresh_clear = true;
+ complete(&freq_mitigation_complete);
+ } else {
+ pr_err("%s: Frequency mitigation task is not initialized\n",
+ KBUILD_MODNAME);
+ }
+
+ return 0;
+}
+
+static void freq_mitigation_init(void)
+{
+ uint32_t cpu = 0;
+ struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL;
+
+ if (freq_mitigation_task)
+ return;
+ if (!freq_mitigation_enabled)
+ goto init_freq_thread;
+
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu)))
+ continue;
+ hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH];
+ low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW];
+
+ hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc;
+ hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc -
+ msm_thermal_info.freq_mitig_temp_hysteresis_degc;
+ low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ hi_thresh->notify = low_thresh->notify =
+ freq_mitigation_notify;
+ hi_thresh->data = low_thresh->data = (void *)&cpus[cpu];
+
+ set_threshold(cpus[cpu].sensor_id, hi_thresh);
+ }
+init_freq_thread:
+ init_completion(&freq_mitigation_complete);
+ freq_mitigation_task = kthread_run(do_freq_mitigation, NULL,
+ "msm_thermal:freq_mitig");
+
+ if (IS_ERR(freq_mitigation_task)) {
+ pr_err("%s: Failed to create frequency mitigation thread\n",
+ KBUILD_MODNAME);
+ return;
+ }
+}
+
+int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq, bool is_max)
+{
+ int ret = 0;
+
+ if (cpu >= num_possible_cpus()) {
+ pr_err("%s: Invalid input\n", KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto set_freq_exit;
+ }
+
+ if (is_max) {
+ if (cpus[cpu].user_max_freq == freq)
+ goto set_freq_exit;
+
+ cpus[cpu].user_max_freq = freq;
+ } else {
+ if (cpus[cpu].user_min_freq == freq)
+ goto set_freq_exit;
+
+ cpus[cpu].user_min_freq = freq;
+ }
+
+ if (freq_mitigation_task) {
+ complete(&freq_mitigation_complete);
+ } else {
+ pr_err("%s: Frequency mitigation task is not initialized\n",
+ KBUILD_MODNAME);
+ ret = -ESRCH;
+ goto set_freq_exit;
+ }
+
+set_freq_exit:
+ return ret;
+}
+
/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
@@ -1163,21 +1508,20 @@
*/
static void __ref disable_msm_thermal(void)
{
- int cpu = 0;
+ uint32_t cpu = 0;
/* make sure check_temp is no longer running */
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
- if (limited_max_freq == UINT_MAX)
- return;
-
- limited_max_freq = UINT_MAX;
get_online_cpus();
- for_each_online_cpu(cpu) {
- if (cpufreq_update_policy(cpu))
- pr_info("%s: Unable to update policy for cpu:%d\n",
- KBUILD_MODNAME, cpu);
+ for_each_possible_cpu(cpu) {
+ if (cpus[cpu].limited_max_freq == UINT_MAX &&
+ cpus[cpu].limited_min_freq == 0)
+ continue;
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ update_cpu_freq(cpu);
}
put_online_cpus();
}
@@ -1190,6 +1534,7 @@
if (!enabled) {
disable_msm_thermal();
hotplug_init();
+ freq_mitigation_init();
} else
pr_info("%s: no action for enabled = %d\n",
KBUILD_MODNAME, enabled);
@@ -1257,7 +1602,7 @@
{
int ret = 0;
uint32_t val = 0;
- int cpu;
+ uint32_t cpu;
mutex_lock(&core_control_mutex);
ret = kstrtouint(buf, 10, &val);
@@ -1422,6 +1767,7 @@
int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
{
int ret = 0;
+ uint32_t cpu;
BUG_ON(!pdata);
tsens_get_max_sensor_num(&max_tsens_num);
@@ -1433,13 +1779,15 @@
return -EINVAL;
enabled = 1;
-
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ }
ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
CPUFREQ_POLICY_NOTIFIER);
if (ret)
pr_err("%s: cannot register cpufreq notifier\n",
KBUILD_MODNAME);
-
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1449,6 +1797,42 @@
return ret;
}
+static int ocr_reg_init(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i, j;
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ /* Check if vdd_restriction has already initialized any
+ * regualtor handle. If so use the same handle.*/
+ for (j = 0; j < rails_cnt; j++) {
+ if (!strcmp(ocr_rails[i].name, rails[j].name)) {
+ if (rails[j].reg == NULL)
+ break;
+ ocr_rails[i].phase_reg = rails[j].reg;
+ goto reg_init;
+ }
+
+ }
+ ocr_rails[i].phase_reg = devm_regulator_get(&pdev->dev,
+ ocr_rails[i].name);
+ if (IS_ERR_OR_NULL(ocr_rails[i].phase_reg)) {
+ ret = PTR_ERR(ocr_rails[i].phase_reg);
+ if (ret != -EPROBE_DEFER) {
+ pr_err("%s, could not get regulator: %s\n",
+ __func__, ocr_rails[i].name);
+ ocr_rails[i].phase_reg = NULL;
+ ocr_rails[i].mode = 0;
+ ocr_rails[i].init = 0;
+ }
+ return ret;
+ }
+reg_init:
+ ocr_rails[i].mode = OPTIMUM_CURRENT_MIN;
+ }
+ return ret;
+}
+
static int vdd_restriction_reg_init(struct platform_device *pdev)
{
int ret = 0;
@@ -1618,6 +2002,80 @@
return rc;
}
+static int msm_thermal_add_ocr_nodes(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *ocr_kobj = NULL;
+ struct kobject *ocr_reg_kobj[MAX_RAILS] = {0};
+ int rc = 0;
+ int i = 0;
+
+ if (!ocr_probed) {
+ ocr_nodes_called = true;
+ return rc;
+ }
+
+ if (ocr_probed && ocr_rail_cnt == 0)
+ return rc;
+
+ 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 ocr_node_exit;
+ }
+
+ ocr_kobj = kobject_create_and_add("opt_curr_req", module_kobj);
+ if (!ocr_kobj) {
+ pr_err("%s: cannot create ocr kobject\n", KBUILD_MODNAME);
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ ocr_reg_kobj[i] = kobject_create_and_add(ocr_rails[i].name,
+ ocr_kobj);
+ if (!ocr_reg_kobj[i]) {
+ pr_err("%s: cannot create for kobject for %s\n",
+ KBUILD_MODNAME, ocr_rails[i].name);
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+ ocr_rails[i].attr_gp.attrs = kzalloc( \
+ sizeof(struct attribute *) * 2, GFP_KERNEL);
+ if (!ocr_rails[i].attr_gp.attrs) {
+ rc = -ENOMEM;
+ goto ocr_node_exit;
+ }
+
+ OCR_RW_ATTRIB(ocr_rails[i], ocr_rails[i].mode_attr, 0, mode);
+ ocr_rails[i].attr_gp.attrs[1] = NULL;
+
+ rc = sysfs_create_group(ocr_reg_kobj[i], &ocr_rails[i].attr_gp);
+ if (rc) {
+ pr_err("%s: cannot create attribute group for %s\n",
+ KBUILD_MODNAME, ocr_rails[i].name);
+ goto ocr_node_exit;
+ }
+ }
+
+ocr_node_exit:
+ if (rc) {
+ for (i = 0; i < ocr_rail_cnt; i++) {
+ if (ocr_reg_kobj[i])
+ kobject_del(ocr_reg_kobj[i]);
+ if (ocr_rails[i].attr_gp.attrs) {
+ kfree(ocr_rails[i].attr_gp.attrs);
+ ocr_rails[i].attr_gp.attrs = NULL;
+ }
+ }
+ if (ocr_kobj)
+ kobject_del(ocr_kobj);
+ }
+ return rc;
+}
+
static int msm_thermal_add_psm_nodes(void)
{
struct kobject *module_kobj = NULL;
@@ -1790,6 +2248,83 @@
return ret;
}
+static int probe_ocr(struct device_node *node, struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ int ret = 0;
+ int j = 0;
+ char *key = NULL;
+
+ if (ocr_probed) {
+ pr_info("%s: Nodes already probed\n",
+ __func__);
+ goto read_ocr_exit;
+ }
+ ocr_rails = NULL;
+
+ key = "qti,pmic-opt-curr-temp";
+ ret = of_property_read_u32(node, key, &data->ocr_temp_degC);
+ if (ret)
+ goto read_ocr_fail;
+
+ key = "qti,pmic-opt-curr-temp-hysteresis";
+ ret = of_property_read_u32(node, key, &data->ocr_temp_hyst_degC);
+ if (ret)
+ goto read_ocr_fail;
+
+ key = "qti,pmic-opt-curr-regs";
+ ocr_rail_cnt = of_property_count_strings(node, key);
+ ocr_rails = kzalloc(sizeof(struct psm_rail) * ocr_rail_cnt,
+ GFP_KERNEL);
+ if (!ocr_rails) {
+ pr_err("%s: Fail to allocate memory for ocr rails\n", __func__);
+ ocr_rail_cnt = 0;
+ return -ENOMEM;
+ }
+
+ for (j = 0; j < ocr_rail_cnt; j++) {
+ ret = of_property_read_string_index(node, key, j,
+ &ocr_rails[j].name);
+ if (ret)
+ goto read_ocr_fail;
+ ocr_rails[j].phase_reg = NULL;
+ ocr_rails[j].init = OPTIMUM_CURRENT_MAX;
+ }
+
+ if (ocr_rail_cnt) {
+ ret = ocr_reg_init(pdev);
+ if (ret) {
+ pr_info("%s:Failed to get regulators. KTM continues.\n",
+ __func__);
+ goto read_ocr_fail;
+ }
+ ocr_enabled = true;
+ ocr_nodes_called = false;
+ /*
+ * Vote for max optimum current by default until we have made
+ * our first temp reading
+ */
+ if (ocr_set_mode_all(OPTIMUM_CURRENT_MAX))
+ pr_err("Set max optimum current failed\n");
+ }
+
+read_ocr_fail:
+ ocr_probed = true;
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ __func__, node->full_name, key);
+ if (ocr_rails)
+ kfree(ocr_rails);
+ ocr_rails = NULL;
+ ocr_rail_cnt = 0;
+ }
+ if (ret == -EPROBE_DEFER)
+ ocr_probed = false;
+read_ocr_exit:
+ return ret;
+}
+
static int probe_psm(struct device_node *node, struct msm_thermal_data *data,
struct platform_device *pdev)
{
@@ -1854,9 +2389,9 @@
struct platform_device *pdev)
{
char *key = NULL;
- int cpu_cnt = 0;
+ uint32_t cpu_cnt = 0;
int ret = 0;
- int cpu = 0;
+ uint32_t cpu = 0;
if (num_possible_cpus() > 1) {
core_control_enabled = 1;
@@ -1901,6 +2436,7 @@
cpus[cpu].cpu = cpu;
cpus[cpu].offline = 0;
cpus[cpu].user_offline = 0;
+ cpus[cpu].hotplug_thresh_clear = false;
ret = of_property_read_string_index(node, key, cpu,
&cpus[cpu].sensor_type);
if (ret)
@@ -1928,6 +2464,55 @@
return ret;
}
+static int probe_freq_mitigation(struct device_node *node,
+ struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ char *key = NULL;
+ int ret = 0;
+ uint32_t cpu;
+
+ key = "qcom,freq-mitigation-temp";
+ ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-temp-hysteresis";
+ ret = of_property_read_u32(node, key,
+ &data->freq_mitig_temp_hysteresis_degc);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-value";
+ ret = of_property_read_u32(node, key, &data->freq_limit);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ key = "qcom,freq-mitigation-control-mask";
+ ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask);
+ if (ret)
+ goto PROBE_FREQ_EXIT;
+
+ freq_mitigation_enabled = 1;
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].max_freq = false;
+ cpus[cpu].user_max_freq = UINT_MAX;
+ cpus[cpu].user_min_freq = 0;
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ cpus[cpu].freq_thresh_clear = false;
+ }
+
+PROBE_FREQ_EXIT:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ __func__, node->full_name, key);
+ freq_mitigation_enabled = 0;
+ }
+ return ret;
+}
+
static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -1958,18 +2543,23 @@
goto fail;
key = "qcom,freq-step";
- ret = of_property_read_u32(node, key, &data.freq_step);
+ ret = of_property_read_u32(node, key, &data.bootup_freq_step);
if (ret)
goto fail;
key = "qcom,freq-control-mask";
- ret = of_property_read_u32(node, key, &data.freq_control_mask);
+ ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask);
ret = probe_cc(node, &data, pdev);
+
+ ret = probe_freq_mitigation(node, &data, pdev);
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
* before devm_regulator_get
+ * probe_ocr should be called after probe_vdd_rstr to reuse the
+ * regualtor handle. calling devm_regulator_get more than once
+ * will fail.
*/
ret = probe_psm(node, &data, pdev);
if (ret == -EPROBE_DEFER)
@@ -1977,6 +2567,9 @@
ret = probe_vdd_rstr(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
+ ret = probe_ocr(node, &data, pdev);
+ if (ret == -EPROBE_DEFER)
+ goto fail;
/*
* In case sysfs add nodes get called before probe function.
@@ -1990,6 +2583,11 @@
msm_thermal_add_vdd_rstr_nodes();
vdd_rstr_nodes_called = false;
}
+ if (ocr_nodes_called) {
+ msm_thermal_add_ocr_nodes();
+ ocr_nodes_called = false;
+ }
+ msm_thermal_ioctl_init();
ret = msm_thermal_init(&data);
return ret;
@@ -2001,6 +2599,11 @@
return ret;
}
+static int msm_thermal_dev_exit(struct platform_device *inp_dev)
+{
+ msm_thermal_ioctl_cleanup();
+ return 0;
+}
static struct of_device_id msm_thermal_match_table[] = {
{.compatible = "qcom,msm-thermal"},
@@ -2014,6 +2617,7 @@
.owner = THIS_MODULE,
.of_match_table = msm_thermal_match_table,
},
+ .remove = msm_thermal_dev_exit,
};
int __init msm_thermal_device_init(void)
@@ -2027,6 +2631,7 @@
msm_thermal_add_cc_nodes();
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
+ msm_thermal_add_ocr_nodes();
alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
thermal_rtc_callback);
INIT_WORK(&timer_work, timer_work_fn);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index dd04f49..7ae0a54 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1063,7 +1063,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &data) != 1)
@@ -1088,7 +1088,7 @@
memset(kbuf, 0, 10);
- if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+ if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
return -EFAULT;
if (sscanf(kbuf, "%x", &temp) != 1)
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index b49e08e..01edf92 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -28,3 +28,10 @@
seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller
fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status
to HAL layer to reset the controller.
+
+config FB_MSM_MDSS_MDP3
+ depends on FB_MSM_MDSS
+ bool "MDP3 display controller"
+ ---help---
+ The MDP3 provides support for an older version display controller
+ included in latest display sub-system, known as MDSS.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 0fc6245..fd03b63 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,6 +1,6 @@
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
-obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
mdss-mdp-objs += mdss_mdp_pp.o
@@ -17,7 +17,7 @@
endif
dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
-obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o
+obj-$(CONFIG_FB_MSM_MDSS_MDP3) += dsi-v2.o
mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o
mdss-dsi-objs += mdss_dsi_panel.o
@@ -42,4 +42,8 @@
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+ifeq ($(CONFIG_FB_MSM_MDSS_MDP3),y)
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += dsi_status_v2.o
+else
obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
+endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index aa41cb2..4173e3f 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -78,6 +78,9 @@
if (status) {
MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
+
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -220,6 +223,12 @@
spin_unlock(&ctrl->mdp_lock);
+ if (isr & DSI_INTR_BTA_DONE)
+ complete(&ctrl->bta_comp);
+
+ if (isr & DSI_INTR_CMD_MDP_DONE)
+ complete(&ctrl->mdp_comp);
+
return IRQ_HANDLED;
}
@@ -261,6 +270,49 @@
}
}
+static int msm_dsi_wait4mdp_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc;
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->mdp_comp);
+ msm_dsi_set_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+ rc = wait_for_completion_timeout(&ctrl->mdp_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 4));
+
+ if (rc == 0) {
+ pr_err("DSI wait 4 mdp done time out\n");
+ rc = -ETIME;
+ } else if (!IS_ERR_VALUE(rc)) {
+ rc = 0;
+ }
+
+ msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK);
+
+ return rc;
+}
+
+void msm_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int rc;
+ u32 dsi_status;
+ unsigned char *ctrl_base = dsi_host_private->dsi_base;
+
+ if (ctrl->panel_mode == DSI_VIDEO_MODE)
+ return;
+
+ dsi_status = MIPI_INP(ctrl_base + DSI_STATUS);
+ if (dsi_status & 0x04) {
+ pr_debug("dsi command engine is busy\n");
+ rc = msm_dsi_wait4mdp_done(ctrl);
+ if (rc)
+ pr_err("Timed out waiting for mdp done");
+ }
+}
+
static int msm_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc;
@@ -883,17 +935,18 @@
if (req->cb)
req->cb(len);
}
-void msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
struct dcs_cmd_req *req;
int dsi_on;
+ int ret = -EINVAL;
mutex_lock(&ctrl->mutex);
dsi_on = dsi_host_private->dsi_on;
mutex_unlock(&ctrl->mutex);
if (!dsi_on) {
pr_err("try to send DSI commands while dsi is off\n");
- return;
+ return ret;
}
mutex_lock(&ctrl->cmd_mutex);
@@ -901,7 +954,7 @@
if (!req) {
mutex_unlock(&ctrl->cmd_mutex);
- return;
+ return ret;
}
msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
@@ -916,6 +969,7 @@
msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
mutex_unlock(&ctrl->cmd_mutex);
+ return 0;
}
static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
@@ -1166,6 +1220,38 @@
return 0;
}
+int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int ret = 0;
+
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return 0;
+ }
+
+ mutex_lock(&ctrl_pdata->cmd_mutex);
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1);
+ msm_dsi_cmd_mdp_busy(ctrl_pdata);
+ msm_dsi_set_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+ INIT_COMPLETION(ctrl_pdata->bta_comp);
+
+ /* BTA trigger */
+ MIPI_OUTP(dsi_host_private->dsi_base + DSI_CMD_MODE_BTA_SW_TRIGGER,
+ 0x01);
+ wmb();
+ ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+ HZ/10);
+ msm_dsi_clear_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0);
+ mutex_unlock(&ctrl_pdata->cmd_mutex);
+
+ if (ret <= 0)
+ pr_err("%s: DSI BTA error: %i\n", __func__, __LINE__);
+
+ pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+ return ret;
+}
+
static void msm_dsi_debug_enable_clock(int on)
{
if (dsi_host_private->debug_enable_clk)
@@ -1329,6 +1415,7 @@
{
init_completion(&ctrl->dma_comp);
init_completion(&ctrl->mdp_comp);
+ init_completion(&ctrl->bta_comp);
init_completion(&ctrl->video_comp);
spin_lock_init(&ctrl->irq_lock);
spin_lock_init(&ctrl->mdp_lock);
@@ -1339,6 +1426,7 @@
dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
ctrl->cmdlist_commit = msm_dsi_cmdlist_commit;
ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
+ ctrl->check_status = msm_dsi_bta_status_check;
}
static int __devinit msm_dsi_probe(struct platform_device *pdev)
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index cec9774..b297452 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -17,6 +17,8 @@
#define DSI_INTR_ERROR_MASK BIT(25)
#define DSI_INTR_ERROR BIT(24)
+#define DSI_INTR_BTA_DONE_MASK BIT(21)
+#define DSI_INTR_BTA_DONE BIT(20)
#define DSI_INTR_VIDEO_DONE_MASK BIT(17)
#define DSI_INTR_VIDEO_DONE BIT(16)
#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9)
@@ -24,6 +26,8 @@
#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1)
#define DSI_INTR_CMD_DMA_DONE BIT(0)
+#define DSI_BTA_TERM BIT(1)
+
#define DSI_CTRL 0x0000
#define DSI_STATUS 0x0004
#define DSI_FIFO_STATUS 0x0008
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
new file mode 100644
index 0000000..d62ddf3
--- /dev/null
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 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/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdp3_ctrl.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+/**
+ * dsi_status_data - Stores all the data necessary for this module
+ * @fb_notif: Used to egister for the fb events
+ * @live_status: Delayed worker structure, used to associate the
+ * delayed worker function
+ * @mfd: Used to store the msm_fb_data_type received when the notifier
+ * call back happens
+ * @root: Stores the dir created by debuugfs
+ * @debugfs_reset_panel: The debugfs variable used to inject errors
+ */
+
+struct dsi_status_data {
+ struct notifier_block fb_notifier;
+ struct delayed_work check_status;
+ struct msm_fb_data_type *mfd;
+ uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+void check_dsi_ctrl_status(struct work_struct *work)
+{
+ struct dsi_status_data *pdsi_status = NULL;
+ struct mdss_panel_data *pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdp3_session_data *mdp3_session = NULL;
+ int ret = 0;
+
+ pdsi_status = container_of(to_delayed_work(work),
+ struct dsi_status_data, check_status);
+ if (!pdsi_status) {
+ pr_err("%s: DSI status data not available\n", __func__);
+ return;
+ }
+
+ pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("%s: Panel data not available\n", __func__);
+ return;
+ }
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+ if (!ctrl_pdata || !ctrl_pdata->check_status) {
+ pr_err("%s: DSI ctrl or status_check callback not avilable\n",
+ __func__);
+ return;
+ }
+ mdp3_session = pdsi_status->mfd->mdp.private1;
+ mutex_lock(&mdp3_session->lock);
+
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+
+ mutex_unlock(&mdp3_session->lock);
+
+ if ((pdsi_status->mfd->panel_power_on)) {
+ if (ret > 0) {
+ schedule_delayed_work(&pdsi_status->check_status,
+ msecs_to_jiffies(pdsi_status->check_interval));
+ } else {
+ char *envp[2] = {"PANEL_ALIVE=0", NULL};
+ pdata->panel_info.panel_dead = true;
+ ret = kobject_uevent_env(
+ &pdsi_status->mfd->fbi->dev->kobj,
+ KOBJ_CHANGE, envp);
+ pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+ __func__, envp[0]);
+ }
+ }
+}
+
+/**
+ * fb_notifier_callback() - Call back function for the fb_register_client()
+ * notifying events
+ * @self : notifier block
+ * @event : The event that was triggered
+ * @data : Of type struct fb_event
+ *
+ * - This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * - Based on the event the delayed work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled
+ */
+static int fb_event_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = (struct fb_event *)data;
+ struct dsi_status_data *pdata = container_of(self,
+ struct dsi_status_data, fb_notifier);
+ pdata->mfd = (struct msm_fb_data_type *)evdata->info->par;
+
+ if (event == FB_EVENT_BLANK && evdata) {
+ int *blank = evdata->data;
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ schedule_delayed_work(&pdata->check_status,
+ msecs_to_jiffies(STATUS_CHECK_INTERVAL));
+ break;
+ case FB_BLANK_POWERDOWN:
+ cancel_delayed_work(&pdata->check_status);
+ break;
+ }
+ }
+ return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+ int rc;
+
+ pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
+ if (!pstatus_data) {
+ pr_err("%s: can't alloc mem\n", __func__);
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ memset(pstatus_data, 0, sizeof(struct dsi_status_data));
+
+ pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+ rc = fb_register_client(&pstatus_data->fb_notifier);
+ if (rc < 0) {
+ pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+ __func__, rc);
+ kfree(pstatus_data);
+ return -EPERM;
+ }
+
+ pstatus_data->check_interval = interval;
+ pr_info("%s: DSI status check interval:%d\n", __func__, interval);
+
+ INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+ pr_debug("%s: DSI ctrl status thread initialized\n", __func__);
+
+ return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+ fb_unregister_client(&pstatus_data->fb_notifier);
+ cancel_delayed_work_sync(&pstatus_data->check_status);
+ kfree(pstatus_data);
+ pr_debug("%s: DSI ctrl status thread removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+ "Duration in milliseconds to send BTA command for checking"
+ "DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6219737..e6d4ff2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -613,9 +613,6 @@
panel = mdp3_session->panel;
mutex_lock(&mdp3_session->lock);
- if (panel && panel->set_backlight)
- panel->set_backlight(panel, 0);
-
if (!mdp3_session->status) {
pr_debug("fb%d is off already", mfd->index);
goto off_error;
@@ -838,6 +835,14 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+ struct fb_info *fbi = mfd->fbi;
+ int stride;
+
+ fix = &fbi->fix;
+ var = &fbi->var;
+ stride = req->src.width * var->bits_per_pixel/8;
mutex_lock(&mdp3_session->lock);
@@ -846,6 +851,9 @@
mdp3_session->overlay = *req;
if (req->id == MSMFB_NEW_REQUEST) {
+ if (fix->line_length != stride)
+ mdp3_session->dma->config_stride(
+ mdp3_session->dma, stride);
mdp3_session->overlay.id = 1;
req->id = 1;
}
@@ -859,10 +867,15 @@
{
int rc = 0;
struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct fb_info *fbi = mfd->fbi;
+ struct fb_fix_screeninfo *fix;
+ fix = &fbi->fix;
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
+ mdp3_session->dma->config_stride(mdp3_session->dma,
+ fix->line_length);
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
} else {
@@ -1708,14 +1721,14 @@
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+ if (mdp3_get_cont_spash_en())
+ mdp3_session->clk_on = 1;
+
if (splash_mismatch) {
pr_err("splash memory mismatch, stop splash\n");
mdp3_ctrl_off(mfd);
}
- if (mdp3_get_cont_spash_en())
- mdp3_session->clk_on = 1;
-
mdp3_session->vsync_before_commit = true;
init_done:
if (IS_ERR_VALUE(rc))
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3a2c94b..2ebcb8a 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -268,6 +268,23 @@
return 0;
}
+static void mdp3_dma_stride_config(struct mdp3_dma *dma, int stride)
+{
+ struct mdp3_dma_source *source_config;
+ u32 dma_stride_offset;
+
+ if (dma->dma_sel == MDP3_DMA_P)
+ dma_stride_offset = MDP3_REG_DMA_P_IBUF_Y_STRIDE;
+ else
+ dma_stride_offset = MDP3_REG_DMA_S_IBUF_Y_STRIDE;
+
+ source_config = &dma->source_config;
+ source_config->stride = stride;
+ pr_debug("%s: Update the fb stride for DMA to %d", __func__,
+ (u32)source_config->stride);
+ MDP3_REG_WRITE(dma_stride_offset, source_config->stride);
+}
+
static int mdp3_dmap_config(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
struct mdp3_dma_output_config *output_config)
@@ -855,6 +872,7 @@
dma->vsync_enable = mdp3_dma_vsync_enable;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
+ dma->config_stride = mdp3_dma_stride_config;
break;
case MDP3_DMA_S:
dma->dma_config = mdp3_dmas_config;
@@ -869,6 +887,7 @@
dma->vsync_enable = mdp3_dma_vsync_enable;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
+ dma->config_stride = mdp3_dma_stride_config;
break;
case MDP3_DMA_E:
default:
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6983e55..9d439ad 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -287,6 +287,8 @@
int (*histo_op)(struct mdp3_dma *dma, u32 op);
+ void (*config_stride)(struct mdp3_dma *dma, int stride);
+
void (*vsync_enable)(struct mdp3_dma *dma,
struct mdp3_vsync_notification *vsync_client);
};
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index a64a6b4..d778af8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -412,12 +412,47 @@
mdp3_ppp_kickoff();
}
-static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+static int solid_fill_workaround(struct mdp_blit_req *req,
+ struct ppp_blit_op *blit_op)
+{
+ /* Make width 2 when there is a solid fill of width 1, and make
+ sure width does not become zero while trying to avoid odd width */
+ if (blit_op->dst.roi.width == 1) {
+ if (req->dst_rect.x + 2 > req->dst.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->dst.roi.width = 2;
+ }
+ if (blit_op->src.roi.width == 1) {
+ if (req->src_rect.x + 2 > req->src.width) {
+ pr_err("%s: Unable to handle solid fill of width 1",
+ __func__);
+ return -EINVAL;
+ }
+ blit_op->src.roi.width = 2;
+ }
+
+ /* Avoid odd width, as it could hang ppp during solid fill */
+ blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
+ blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
+
+ /* Avoid RGBA format, as it could hang ppp during solid fill */
+ if (blit_op->src.color_fmt == MDP_RGBA_8888)
+ blit_op->src.color_fmt = MDP_RGBX_8888;
+ if (blit_op->dst.color_fmt == MDP_RGBA_8888)
+ blit_op->dst.color_fmt = MDP_RGBX_8888;
+ return 0;
+}
+
+static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
struct mdp_blit_req *req, struct mdp3_img_data *src_data,
struct mdp3_img_data *dst_data)
{
unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
uint32_t dst_width, dst_height;
+ int ret = 0;
srcp0_start = (unsigned long) src_data->addr;
srcp0_len = (unsigned long) src_data->len;
@@ -510,24 +545,19 @@
blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
if (req->flags & MDP_SOLID_FILL) {
- blit_op->solid_fill = true;
+ ret = solid_fill_workaround(req, blit_op);
+ if (ret)
+ return ret;
- /* Avoid odd width, as it could hang ppp during solid fill */
- blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
- blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
-
- /* Avoid RGBA format, as it could hang ppp during solid fill */
- if (blit_op->src.color_fmt == MDP_RGBA_8888)
- blit_op->src.color_fmt = MDP_RGBX_8888;
- if (blit_op->dst.color_fmt == MDP_RGBA_8888)
- blit_op->dst.color_fmt = MDP_RGBX_8888;
blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
(req->const_color.r & 0xFF) << 8 |
(req->const_color.b & 0xFF) << 16 |
(req->const_color.alpha & 0xFF) << 24;
+ blit_op->solid_fill = true;
} else {
blit_op->solid_fill = false;
}
+ return ret;
}
static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -626,6 +656,7 @@
struct mdp3_img_data *dst_data)
{
struct ppp_blit_op blit_op;
+ int ret = 0;
memset(&blit_op, 0, sizeof(blit_op));
@@ -639,7 +670,11 @@
return -EINVAL;
}
- mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+ if (ret) {
+ pr_err("%s: Failed to process the blit request", __func__);
+ return ret;
+ }
if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
(req->src.format == MDP_ARGB_8888) ||
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index d743c42..855ec6c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,7 +233,7 @@
int (*off) (struct mdss_panel_data *pdata);
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
- void (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+ int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
int reg_size;
@@ -336,7 +336,7 @@
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
index 9a3e638..8fc1115c0 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.c
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -655,7 +655,7 @@
{
struct dcs_cmd_req *req;
struct dcs_cmd_list *clist;
- int ret = 0;
+ int ret = -EINVAL;
mutex_lock(&ctrl->cmd_mutex);
clist = &ctrl->cmdlist;
@@ -674,7 +674,6 @@
}
mutex_unlock(&ctrl->cmd_mutex);
- ret++;
pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
clist->tot, clist->put, clist->get);
@@ -682,7 +681,7 @@
if (!ctrl->cmdlist_commit)
pr_err("cmdlist_commit not implemented!\n");
else
- ctrl->cmdlist_commit(ctrl, 0);
+ ret = ctrl->cmdlist_commit(ctrl, 0);
}
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 37ccd4f..65e6214 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1155,38 +1155,55 @@
__func__, current->pid);
}
-void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
- int ret;
+ int ret, ret_val = -EINVAL;
ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+ if (!IS_ERR_VALUE(ret))
+ ret_val = 0;
+
if (req->cb)
req->cb(ret);
+
+ return ret_val;
}
-void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *req)
{
struct dsi_buf *rp;
- int len = 0;
+ int len = 0, ret = -EINVAL;
if (req->rbuf) {
rp = &ctrl->rx_buf;
len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
memcpy(req->rbuf, rp->data, rp->len);
+ /*
+ * For dual DSI cases, early return of controller - 0
+ * is valid. Hence, for those cases the return value
+ * is zero even though we don't send any commands.
+ *
+ */
+ if ((ctrl->shared_pdata.broadcast_enable &&
+ ctrl->ndx == DSI_CTRL_0) || (len != 0))
+ ret = 0;
} else {
pr_err("%s: No rx buffer provided\n", __func__);
}
if (req->cb)
req->cb(len);
+
+ return ret;
}
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
{
struct dcs_cmd_req *req;
+ int ret = -EINVAL;
mutex_lock(&ctrl->cmd_mutex);
req = mdss_dsi_cmdlist_get(ctrl);
@@ -1211,9 +1228,9 @@
mdss_dsi_clk_ctrl(ctrl, 1);
if (req->flags & CMD_REQ_RX)
- mdss_dsi_cmdlist_rx(ctrl, req);
+ ret = mdss_dsi_cmdlist_rx(ctrl, req);
else
- mdss_dsi_cmdlist_tx(ctrl, req);
+ ret = mdss_dsi_cmdlist_tx(ctrl, req);
mdss_dsi_clk_ctrl(ctrl, 0);
mdss_bus_bandwidth_ctrl(0);
@@ -1224,6 +1241,7 @@
mdss_dsi_cmd_mdp_start(ctrl);
mutex_unlock(&ctrl->cmd_mutex);
+ return ret;
}
static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
@@ -1313,6 +1331,8 @@
if (status) {
MIPI_OUTP(base + 0x0068, status);
+ /* Writing of an extra 0 needed to clear error bits */
+ MIPI_OUTP(base + 0x0068, 0);
pr_err("%s: status=%x\n", __func__, status);
}
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c15c02b..94b2cbd 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2187,6 +2187,7 @@
struct platform_device *fb_pdev, *mdss_pdev;
struct device_node *node;
int rc = 0;
+ bool master_panel = true;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
@@ -2214,6 +2215,8 @@
fb_pdev = of_find_device_by_node(node);
if (fb_pdev) {
rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+ if (rc == 0)
+ master_panel = false;
} else {
pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
fb_pdev = of_platform_device_create(node, NULL,
@@ -2221,7 +2224,7 @@
fb_pdev->dev.platform_data = pdata;
}
- if (mdp_instance->panel_register_done)
+ if (master_panel && mdp_instance->panel_register_done)
mdp_instance->panel_register_done(pdata);
mdss_notfound:
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 769f9b2..fad6b0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -289,6 +289,7 @@
struct mdss_ad_info {
u8 num;
u8 calc_hw_num;
+ u32 ops;
u32 sts;
u32 reg_sts;
u32 state;
@@ -516,7 +517,7 @@
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index bad4d06..f73b583 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1062,26 +1062,34 @@
return rc;
}
-static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
u32 outsize, temp;
int ret = 0;
int i, nmixers;
- if (ctl->start_fnc)
- ret = ctl->start_fnc(ctl);
- else
- pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
- ctl->panel_data->panel_info.type);
-
- if (ret) {
- pr_err("unable to start intf\n");
- return ret;
- }
-
pr_debug("ctl_num=%d\n", ctl->num);
+ /*
+ * Need start_fnc in 2 cases:
+ * (1) handoff
+ * (2) continuous splash finished.
+ */
+ if (handoff || !ctl->panel_data->panel_info.cont_splash_enabled) {
+ if (ctl->start_fnc)
+ ret = ctl->start_fnc(ctl);
+ else
+ pr_warn("no start function for ctl=%d type=%d\n",
+ ctl->num,
+ ctl->panel_data->panel_info.type);
+
+ if (ret) {
+ pr_err("unable to start intf\n");
+ return ret;
+ }
+ }
+
if (!ctl->panel_data->panel_info.cont_splash_enabled) {
nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
MDSS_MDP_WB_MAX_LAYERMIXER;
@@ -1108,7 +1116,7 @@
return ret;
}
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_ctl *sctl;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -1123,12 +1131,17 @@
if (ret)
return ret;
-
sctl = mdss_mdp_get_split_ctl(ctl);
mutex_lock(&ctl->lock);
- ctl->power_on = true;
+ /*
+ * keep power_on false during handoff to avoid unexpected
+ * operations to overlay.
+ */
+ if (!handoff)
+ ctl->power_on = true;
+
ctl->bus_ab_quota = 0;
ctl->bus_ib_quota = 0;
ctl->clk_rate = 0;
@@ -1141,10 +1154,10 @@
goto error;
}
- ret = mdss_mdp_ctl_start_sub(ctl);
+ ret = mdss_mdp_ctl_start_sub(ctl, handoff);
if (ret == 0) {
if (sctl) { /* split display is available */
- ret = mdss_mdp_ctl_start_sub(sctl);
+ ret = mdss_mdp_ctl_start_sub(sctl, handoff);
if (!ret)
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
} else if (ctl->mixer_right) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 14b486a..4c89064 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -859,7 +859,7 @@
mdss_hw_init(mdss_res);
}
- rc = mdss_mdp_ctl_start(ctl);
+ rc = mdss_mdp_ctl_start(ctl, false);
if (rc == 0) {
atomic_inc(&ov_active_panels);
@@ -1580,8 +1580,8 @@
return -ENODEV;
if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
return -EOPNOTSUPP;
-
- if (!ctl->power_on) {
+ if (!ctl->panel_data->panel_info.cont_splash_enabled
+ && !ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
return -EPERM;
@@ -1698,7 +1698,9 @@
u64 vsync_ticks;
int ret;
- if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+ if (!mdp5_data->ctl ||
+ (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
+ && !mdp5_data->ctl->power_on))
return -EAGAIN;
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -2535,9 +2537,15 @@
mdp5_data->ctl = ctl;
}
- rc = mdss_mdp_ctl_setup(ctl);
- if (rc)
+ /*
+ * vsync interrupt needs on during continuous splash, this is
+ * to initialize necessary ctl members here.
+ */
+ rc = mdss_mdp_ctl_start(ctl, true);
+ if (rc) {
+ pr_err("Failed to initialize ctl\n");
goto error;
+ }
ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0dc61d0..d0d2157 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -205,6 +205,10 @@
#define PP_AD_BAD_HW_NUM 255
+#define MDSS_SIDE_NONE 0
+#define MDSS_SIDE_LEFT 1
+#define MDSS_SIDE_RIGHT 2
+
#define PP_AD_STATE_INIT 0x2
#define PP_AD_STATE_CFG 0x4
#define PP_AD_STATE_DATA 0x8
@@ -293,15 +297,15 @@
struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
- /* physical info */
struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
+ /* physical info */
struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
static DEFINE_MUTEX(mdss_pp_mutex);
static struct mdss_pp_res_type *mdss_pp_res;
-static void pp_hist_read(char __iomem *v_addr,
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info);
static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
@@ -340,8 +344,9 @@
static void pp_dither_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_dither_cfg_data *dither_cfg);
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
- int mdp_rev);
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode);
static void pp_sharp_config(char __iomem *addr,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
@@ -375,11 +380,15 @@
struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
struct mdss_ad_info *ad);
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode);
static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
+static inline bool pp_sts_is_enabled(u32 sts, int side);
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
static u32 last_sts, last_state;
@@ -511,6 +520,7 @@
pp_sts->gamut_sts &= ~PP_STS_ENABLE;
else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
pp_sts->gamut_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
}
static void pp_pa_config(unsigned long flags, char __iomem *addr,
@@ -679,6 +689,7 @@
if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
+ pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
}
static void pp_pcc_config(unsigned long flags, char __iomem *addr,
@@ -693,6 +704,7 @@
pp_sts->pcc_sts &= ~PP_STS_ENABLE;
else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->pcc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
}
}
@@ -720,6 +732,7 @@
pp_sts->igc_sts &= ~PP_STS_ENABLE;
else if (igc_config->ops & MDP_PP_OPS_ENABLE)
pp_sts->igc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
}
}
@@ -1324,12 +1337,20 @@
pp_sts->dither_sts &= ~PP_STS_ENABLE;
else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
pp_sts->dither_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
}
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
- int mdp_rev)
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+ struct pp_sts_type *pp_sts, int mdp_rev,
+ u32 *opmode)
{
- if (pp_sts->pa_sts & PP_STS_ENABLE)
+ int side;
+ side = pp_num_to_side(ctl, num);
+
+ if (side < 0)
+ return;
+
+ if (pp_sts_is_enabled(pp_sts->pa_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
if (mdp_rev >= MDSS_MDP_HW_REV_103) {
if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
@@ -1357,10 +1378,10 @@
if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
}
- if (pp_sts->pcc_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
- if (pp_sts->igc_sts & PP_STS_ENABLE) {
+ if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
*opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
(pp_sts->igc_tbl_idx << 1);
}
@@ -1368,14 +1389,14 @@
*opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
}
- if (pp_sts->dither_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->dither_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
- if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+ if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
*opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
*opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
}
- if (pp_sts->pgc_sts & PP_STS_ENABLE)
+ if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
*opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
}
@@ -1481,6 +1502,7 @@
pp_sts->pgc_sts &= ~PP_STS_ENABLE;
else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
pp_sts->pgc_sts |= PP_STS_ENABLE;
+ pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
}
if (ad_hw) {
@@ -1492,12 +1514,12 @@
pp_ad_init_write(ad_hw, ad, ctl);
if (ad_flags & PP_AD_STS_DIRTY_CFG)
pp_ad_cfg_write(ad_hw, ad);
- pp_ad_bypass_config(ad, &ad_bypass);
+ pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
writel_relaxed(ad_bypass, ad_hw->base);
mutex_unlock(&ad->lock);
}
- pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev);
+ pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
flush_exit:
writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
ctl->flush_bits |= BIT(13 + dspp_num);
@@ -1836,6 +1858,12 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) ==
+ MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2119,6 +2147,11 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2238,6 +2271,11 @@
if (config->len != IGC_LUT_ENTRIES)
return -EINVAL;
+ if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2437,6 +2475,11 @@
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2608,6 +2651,11 @@
if (config->flags & MDP_PP_OPS_READ)
return -ENOTSUPP;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
@@ -2657,6 +2705,11 @@
if (pp_gm_has_invalid_lut_size(config))
return -EINVAL;
+ if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2773,19 +2826,27 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
-static void pp_hist_read(char __iomem *v_addr,
+
+static u32 pp_hist_read(char __iomem *v_addr,
struct pp_hist_col_info *hist_info)
{
int i, i_start;
+ u32 sum = 0;
u32 data;
data = readl_relaxed(v_addr);
i_start = data >> 24;
hist_info->data[i_start] = data & 0xFFFFFF;
- for (i = i_start + 1; i < HIST_V_SIZE; i++)
+ sum += hist_info->data[i_start];
+ for (i = i_start + 1; i < HIST_V_SIZE; i++) {
hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
- for (i = 0; i < i_start - 1; i++)
+ sum += hist_info->data[i];
+ }
+ for (i = 0; i < i_start; i++) {
hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+ sum += hist_info->data[i];
+ }
hist_info->hist_cnt_read++;
+ return sum;
}
/* Assumes that relevant clocks are enabled */
@@ -3168,10 +3229,10 @@
static int pp_hist_collect(struct mdp_histogram_data *hist,
struct pp_hist_col_info *hist_info,
- char __iomem *ctl_base)
+ char __iomem *ctl_base, u32 expect_sum)
{
int wait_ret, ret = 0;
- u32 timeout;
+ u32 timeout, sum;
char __iomem *v_base;
unsigned long flag;
struct mdss_pipe_pp_res *res;
@@ -3238,10 +3299,13 @@
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
v_base = ctl_base + 0x1C;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pp_hist_read(v_base, hist_info);
+ sum = pp_hist_read(v_base, hist_info);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
spin_lock_irqsave(&hist_info->hist_lock, flag);
- hist_info->read_request = false;
+ if (!expect_sum || sum == expect_sum)
+ hist_info->read_request = false;
+ else
+ ret = -ENODATA;
hist_info->col_state = HIST_IDLE;
}
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -3261,6 +3325,7 @@
u32 *hist_data_addr;
u32 pipe_cnt = 0;
u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+ u32 exp_sum = 0;
struct mdss_mdp_pipe *pipe;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -3290,7 +3355,10 @@
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
+ exp_sum = (mdata->mixer_intf[dspp_num].width *
+ mdata->mixer_intf[dspp_num].height);
+ ret = pp_hist_collect(hist, hist_info, ctl_base,
+ exp_sum);
if (ret)
goto hist_collect_exit;
}
@@ -3359,7 +3427,8 @@
hist_info = &pipe->pp_res.hist;
ctl_base = pipe->base +
MDSS_MDP_REG_VIG_HIST_CTL_BASE;
- ret = pp_hist_collect(hist, hist_info, ctl_base);
+ ret = pp_hist_collect(hist, hist_info, ctl_base,
+ exp_sum);
mdss_mdp_pipe_unmap(pipe);
if (ret)
goto hist_collect_exit;
@@ -3490,6 +3559,53 @@
return out;
}
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
+{
+ u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+ u32 mixer_num;
+
+ if (!ctl || !ctl->mfd)
+ return -EINVAL;
+ mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+ if (mixer_num < 2)
+ return MDSS_SIDE_NONE;
+ else if (mixer_id[1] == num)
+ return MDSS_SIDE_RIGHT;
+ else if (mixer_id[0] == num)
+ return MDSS_SIDE_LEFT;
+ else
+ pr_err("invalid, not on any side");
+ return -EINVAL;
+}
+
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits)
+{
+ u32 tmp = *sts;
+ tmp &= ~MDSS_PP_SPLIT_MASK;
+ tmp |= bits & MDSS_PP_SPLIT_MASK;
+ *sts = tmp;
+}
+
+static inline bool pp_sts_is_enabled(u32 sts, int side)
+{
+ bool ret = false;
+ /*
+ * If there are no sides, or if there are no split mode bits set, the
+ * side can't be disabled via split mode.
+ *
+ * Otherwise, if the side being checked opposes the split mode
+ * configuration, the side is disabled.
+ */
+ if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT))
+ ret = true;
+ else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT))
+ ret = true;
+
+ return ret && (sts & PP_STS_ENABLE);
+}
+
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
{
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -3586,7 +3702,7 @@
struct mdss_mdp_ctl *ctl;
struct msm_fb_data_type *bl_mfd;
int lin_ret = -1, inv_ret = -1, ret = 0;
- u32 ratio_temp, shift = 0;
+ u32 ratio_temp, shift = 0, last_ops;
ret = mdss_mdp_get_ad(mfd, &ad);
if (ret)
@@ -3599,6 +3715,11 @@
bl_mfd = mfd;
}
+ if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+ pr_warn("Can't set both split bits\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ad->lock);
if (init_cfg->ops & MDP_PP_AD_INIT) {
memcpy(&ad->init, &init_cfg->params.init,
@@ -3638,6 +3759,22 @@
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
+ last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
+ ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
+ /*
+ * if there is a change in the split mode config, the init values
+ * need to be re-written to hardware (if they have already been
+ * written or if there is data pending to be written). Check for
+ * pending data (DIRTY_INIT) is not checked here since it will not
+ * affect the outcome of this conditional (i.e. if init hasn't
+ * already been written (*_STATE_INIT is set), this conditional will
+ * only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
+ * already been set).
+ */
+ if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
+ ad->sts |= PP_AD_STS_DIRTY_INIT;
+
+
if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
ad->sts &= ~PP_STS_ENABLE;
mutex_unlock(&ad->lock);
@@ -3792,8 +3929,9 @@
u32 temp;
u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
u32 num;
+ int side;
char __iomem *base;
- bool is_calc, is_dual_pipe;
+ bool is_calc, is_dual_pipe, split_mode;
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 mixer_num;
mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
@@ -3804,6 +3942,7 @@
base = ad_hw->base;
is_calc = ad->calc_hw_num == ad_hw->num;
+ split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
writel_relaxed(ad->init.i_control[0] & 0x1F,
base + MDSS_MDP_REG_AD_CON_CTRL_0);
@@ -3829,7 +3968,10 @@
writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
- temp = ad->init.frame_w << 16;
+ if (split_mode)
+ temp = mdata->mixer_intf[ad_hw->num].width << 16;
+ else
+ temp = ad->init.frame_w << 16;
temp |= ad->init.frame_h & 0xFFFF;
writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
@@ -3841,17 +3983,26 @@
pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
- if (is_dual_pipe) {
+ if (is_dual_pipe && !split_mode) {
num = ad_hw->num;
+ side = pp_num_to_side(ctl, num);
tile_ctrl = 0x5;
- if (is_calc) {
+ if ((ad->calc_hw_num + 1) == num)
+ tile_ctrl |= 0x10;
+
+ if (side <= MDSS_SIDE_NONE) {
+ WARN(1, "error finding sides, %d", side);
+ frame_start = 0;
+ procs_start = frame_start;
+ frame_end = 0;
+ procs_end = frame_end;
+ } else if (side == MDSS_SIDE_LEFT) {
frame_start = 0;
procs_start = 0;
frame_end = mdata->mixer_intf[num].width +
MDSS_AD_MERGED_WIDTH;
procs_end = mdata->mixer_intf[num].width;
} else {
- tile_ctrl |= 0x10;
procs_start = ad->init.frame_w -
(mdata->mixer_intf[num].width);
procs_end = ad->init.frame_w;
@@ -3866,8 +4017,13 @@
frame_end = 0xFFFF;
procs_start = 0x0;
procs_end = 0xFFFF;
- tile_ctrl = 0x1;
+ if (split_mode)
+ tile_ctrl = 0x0;
+ else
+ tile_ctrl = 0x1;
}
+
+
writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
@@ -3931,12 +4087,17 @@
}
#define MDSS_PP_AD_BYPASS_DEF 0x101
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode)
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+ struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
{
- if (ad->reg_sts & PP_STS_ENABLE)
+ int side = pp_num_to_side(ctl, num);
+
+ if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
+ side)) {
*opmode = 0;
- else
+ } else {
*opmode = MDSS_PP_AD_BYPASS_DEF;
+ }
}
static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
@@ -3951,6 +4112,8 @@
/* default to left mixer */
ad->calc_hw_num = mixer_id[0];
+ if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
+ ad->calc_hw_num = mixer_id[1];
return 0;
}
@@ -4258,6 +4421,7 @@
mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
mdata->ad_off[i].num = i;
mdata->ad_cfgs[i].num = i;
+ mdata->ad_cfgs[i].ops = 0;
mdata->ad_cfgs[i].reg_sts = 0;
mdata->ad_cfgs[i].calc_itr = 0;
mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index d9b1ef7..329b58e 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -454,3 +454,4 @@
header-y += msm_audio_amrwbplus.h
header-y += avtimer.h
header-y += msm_ipa.h
+header-y += msm_thermal_ioctl.h
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f36298b..7131da3 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -22,6 +22,8 @@
#include <linux/types.h>
struct ion_handle;
+typedef struct ion_handle *ion_user_handle_t;
+
/**
* enum ion_heap_types - list of all possible types of heaps
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
@@ -350,7 +352,7 @@
size_t align;
unsigned int heap_mask;
unsigned int flags;
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
@@ -364,7 +366,7 @@
* provides the file descriptor and the kernel returns the handle.
*/
struct ion_fd_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
int fd;
};
@@ -373,7 +375,7 @@
* @handle: a handle
*/
struct ion_handle_data {
- struct ion_handle *handle;
+ ion_user_handle_t handle;
};
/**
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 1bcfd28..43aebb5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -392,7 +392,7 @@
unsigned int idle_timeout;
struct notifier_block reboot_notify;
bool issue_long_pon;
- u8 cached_ext_csd;
+ u8 *cached_ext_csd;
};
/*
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 724e573..4903939 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -802,6 +802,10 @@
DCM_BLANK,
};
+#define MDSS_PP_SPLIT_LEFT_ONLY 0x10000000
+#define MDSS_PP_SPLIT_RIGHT_ONLY 0x20000000
+#define MDSS_PP_SPLIT_MASK 0x30000000
+
#define MDSS_MAX_BL_BRIGHTNESS 255
#define AD_BL_LIN_LEN 256
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2ca9900..25b5363 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -19,22 +19,30 @@
uint32_t poll_ms;
int32_t limit_temp_degC;
int32_t temp_hysteresis_degC;
- uint32_t freq_step;
- uint32_t freq_control_mask;
+ uint32_t bootup_freq_step;
+ uint32_t bootup_freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
int32_t hotplug_temp_degC;
int32_t hotplug_temp_hysteresis_degC;
uint32_t core_control_mask;
+ uint32_t freq_mitig_temp_degc;
+ uint32_t freq_mitig_temp_hysteresis_degc;
+ uint32_t freq_mitig_control_mask;
+ uint32_t freq_limit;
int32_t vdd_rstr_temp_degC;
int32_t vdd_rstr_temp_hyst_degC;
int32_t psm_temp_degC;
int32_t psm_temp_hyst_degC;
+ int32_t ocr_temp_degC;
+ int32_t ocr_temp_hyst_degC;
};
#ifdef CONFIG_THERMAL_MONITOR
extern int msm_thermal_init(struct msm_thermal_data *pdata);
extern int msm_thermal_device_init(void);
+extern int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+ bool is_max);
#else
static inline int msm_thermal_init(struct msm_thermal_data *pdata)
{
@@ -44,6 +52,11 @@
{
return -ENOSYS;
}
+static inline int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
+ bool is_max)
+{
+ return -ENOSYS;
+}
#endif
#endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/msm_thermal_ioctl.h b/include/linux/msm_thermal_ioctl.h
new file mode 100644
index 0000000..7b36493
--- /dev/null
+++ b/include/linux/msm_thermal_ioctl.h
@@ -0,0 +1,41 @@
+#ifndef _MSM_THERMAL_IOCTL_H
+#define _MSM_THERMAL_IOCTL_H
+
+#include <linux/ioctl.h>
+
+#define MSM_THERMAL_IOCTL_NAME "msm_thermal_query"
+
+struct __attribute__((__packed__)) cpu_freq_arg {
+ uint32_t cpu_num;
+ uint32_t freq_req;
+};
+
+struct __attribute__((__packed__)) msm_thermal_ioctl {
+ uint32_t size;
+ union {
+ struct cpu_freq_arg cpu_freq;
+ };
+};
+
+enum {
+ /*Set CPU Frequency*/
+ MSM_SET_CPU_MAX_FREQ = 0x00,
+ MSM_SET_CPU_MIN_FREQ = 0x01,
+
+ MSM_CMD_MAX_NR,
+};
+
+#define MSM_THERMAL_MAGIC_NUM 0xCA /*Unique magic number*/
+
+#define MSM_THERMAL_SET_CPU_MAX_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+ MSM_SET_CPU_MAX_FREQ, struct msm_thermal_ioctl)
+
+#define MSM_THERMAL_SET_CPU_MIN_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
+ MSM_SET_CPU_MIN_FREQ, struct msm_thermal_ioctl)
+
+#ifdef __KERNEL__
+extern int msm_thermal_ioctl_init(void);
+extern void msm_thermal_ioctl_cleanup(void);
+#endif
+
+#endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 560accb..bfafe00 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1904,6 +1904,9 @@
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index c48586e..a01dd9a 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -571,7 +571,8 @@
struct msm_camera_led_cfg_t {
enum msm_camera_led_config_t cfgtype;
- uint32_t led_current;
+ uint32_t torch_current;
+ uint32_t flash_current[2];
};
#define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 75fe3a2..2c969cd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -7172,5 +7172,7 @@
#define US_POINT_EPOS_FORMAT_V2 0x0001272D
#define US_RAW_FORMAT_V2 0x0001272C
#define US_PROX_FORMAT_V2 0x0001272E
+#define US_RAW_SYNC_FORMAT 0x0001272F
+#define US_GES_SYNC_FORMAT 0x00012730
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9a459b8..b00cfc9 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -67,6 +67,8 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
#define SYNC_IO_MODE 0x0001
#define ASYNC_IO_MODE 0x0002
#define COMPRESSED_IO 0x0040
@@ -218,6 +220,9 @@
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopback_v2(struct audio_client *ac,
+ uint16_t bits_per_sample);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e174693..fa8a793 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,36 +184,6 @@
return ret;
}
-#ifdef ENABLE_VMALLOC_SAVING
-int is_vmalloc_addr(const void *x)
-{
- struct rb_node *n;
- struct vmap_area *va;
- int ret = 0;
-
- spin_lock(&vmap_area_lock);
-
- for (n = rb_first(vmap_area_root); n; rb_next(n)) {
- va = rb_entry(n, struct vmap_area, rb_node);
- if (x >= va->va_start && x < va->va_end) {
- ret = 1;
- break;
- }
- }
-
- spin_unlock(&vmap_area_lock);
- return ret;
-}
-#else
-int is_vmalloc_addr(const void *x)
-{
- unsigned long addr = (unsigned long)x;
-
- return addr >= VMALLOC_START && addr < VMALLOC_END;
-}
-#endif
-EXPORT_SYMBOL(is_vmalloc_addr);
-
int is_vmalloc_or_module_addr(const void *x)
{
/*
@@ -302,6 +272,47 @@
static unsigned long vmap_area_pcpu_hole;
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+int is_vmalloc_addr(const void *x)
+{
+ struct vmap_area *va;
+ int ret = 0;
+
+ spin_lock(&vmap_area_lock);
+ list_for_each_entry(va, &vmap_area_list, list) {
+ if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
+ continue;
+
+ if (!(va->flags & VM_VM_AREA))
+ continue;
+
+ if (va->vm == NULL)
+ continue;
+
+ if (va->vm->flags & VM_LOWMEM)
+ continue;
+
+ if ((unsigned long)x >= va->va_start &&
+ (unsigned long)x < va->va_end) {
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&vmap_area_lock);
+ return ret;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
+
+
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9962c88..6c78c0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
head = p; id++;
}
- sprintf(hdev->name, "hci%d", id);
+ snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
hdev->id = id;
list_add(&hdev->list, head);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2628937..b2b0e99 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3443,10 +3443,7 @@
tcp_done(sk);
bh_unlock_sock(sk);
local_bh_enable();
- if (!sock_flag(sk, SOCK_DEAD)) {
- sock_orphan(sk);
- sock_put(sk);
- }
+ sock_put(sk);
goto restart;
}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..9a11f9f 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -55,6 +55,7 @@
static unsigned int table_size, table_cnt;
static int all_symbols = 0;
static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
int token_profit[0x10000];
@@ -65,7 +66,10 @@
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+ "[--symbol-prefix=<prefix char>] "
+ "[--page-offset=<CONFIG_PAGE_OFFSET>] "
+ "< in.map > out.S\n");
exit(1);
}
@@ -194,6 +198,9 @@
int i;
int offset = 1;
+ if (s->addr < kernel_start_addr)
+ return 0;
+
/* skip prefix char */
if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
offset++;
@@ -646,6 +653,9 @@
if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
p++;
symbol_prefix_char = *p;
+ } else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ const char *p = &argv[i][14];
+ kernel_start_addr = strtoull(p, NULL, 16);
} else
usage();
}
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 55fec32..1962ff0 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1396,7 +1396,10 @@
switch (decimator) {
case 1:
case 2:
- adc_dmic_sel = 0x0;
+ if ((dec_mux == 3) || (dec_mux == 4))
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
break;
default:
dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 28d4c84..14218d8 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -213,7 +213,6 @@
/* called under codec_resource_lock acquisition */
static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
- s16 v_brh, v_b1_hu;
struct snd_soc_codec *codec = mbhc->codec;
int mbhc_state = mbhc->mbhc_state;
@@ -254,17 +253,6 @@
/* set to max */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-
- v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- v_brh & 0xFF);
- v_b1_hu = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
}
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
@@ -325,22 +313,32 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
0xFF);
- /* Threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
- 0xFF);
- /* Threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ /* Threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
__func__);
}
@@ -376,22 +374,31 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
0xFF);
- /* Revert threshods for button press */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
- 0xFF);
- /* Revert threshods for button release */
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /* Revert threshods for button press */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button release */
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec,
+ WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ }
pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
__func__);
}
@@ -489,19 +496,25 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(v_ins_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (v_b1_h >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
- mbhc->mbhc_data.v_brl & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
- (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (v_b1_h >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
+ mbhc->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
+ (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+ }
}
static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
@@ -3148,15 +3161,22 @@
mv = ceilmv + btn_det->v_btn_press_delta_cic;
pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
- /* update LSB first so mbhc hardware block doesn't see too low value */
- v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (v_b1_hu >> 8) & 0xFF);
- v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (v_brh >> 8) & 0xFF);
+ if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+ /*
+ * update LSB first so mbhc hardware block
+ * doesn't see too low value.
+ */
+ v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (v_b1_hu >> 8) & 0xFF);
+ v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (v_brh >> 8) & 0xFF);
+ }
return 0;
}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 39cb470..6f94d99 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -422,6 +422,30 @@
},
{
.playback = {
+ .stream_name = "INT_HFP_BT Hostless Playback",
+ .aif_name = "INTHFP_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .capture = {
+ .stream_name = "INT_HFP_BT Hostless Capture",
+ .aif_name = "INTHFP_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT_HFP_BT_HOSTLESS",
+ },
+ {
+ .playback = {
.stream_name = "AFE-PROXY Playback",
.aif_name = "PCM_RX",
.rates = (SNDRV_PCM_RATE_8000 |
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index ceea3d2..b4ae0a4 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1420,6 +1420,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_LSM1,
},
+ {
+ .name = "MSM8226 Compr8",
+ .stream_name = "COMPR8",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c120e0c..69a6671 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2203,6 +2203,37 @@
.codec_name = "snd-soc-dummy",
},
{
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM8974 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
.name = LPASS_BE_SLIMBUS_4_TX,
.stream_name = "Slimbus4 Capture",
.cpu_dai_name = "msm-dai-q6-dev.16393",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 408ec03..c1ba26a 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -163,6 +163,8 @@
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
};
static int msm8x10_ext_spk_power_amp_init(void)
{
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index ea16f47..f0f5db6 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -3,7 +3,8 @@
msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
- msm-lsm-client.o msm-audio-effects-q6-v2.o
+ msm-lsm-client.o msm-audio-effects-q6-v2.o \
+ msm-pcm-loopback-v2.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
msm-dai-stub-v2.o
obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58c3cdf..4e04bef 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -405,9 +405,9 @@
done:
mutex_unlock(&acdb_data.acdb_mutex);
-ret:
pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
__func__, path, entry->sample_rate, entry->delay_usec, result);
+ret:
return result;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..57fc268
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 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/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+ int volume;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ BUG_ON(!pcm);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+ int rc = -EINVAL;
+
+ pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd && prtd->audio_client) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm;
+ int ret = 0;
+ uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
+
+ pcm = dev_get_drvdata(rtd->platform->dev);
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+ pcm->volume = 0x2000;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopback_v2(pcm->audio_client,
+ bits_per_sample);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+ int volume = ucontrol->value.integer.value[0];
+
+ rc = pcm_loopback_set_volume(prtd, volume);
+ return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-loopback");
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!pcm) {
+ dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+ __func__);
+ return -ENOMEM;
+ } else {
+ mutex_init(&pcm->lock);
+ dev_set_drvdata(&pdev->dev, pcm);
+ }
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ pcm = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pcm->lock);
+ kfree(pcm);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+ {.compatible = "qti,msm-pcm-loopback"},
+ {}
+};
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pcm_loopback_dt_match,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index dc41948..f25f746 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -109,6 +109,25 @@
.mask = 0,
};
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_audio *prtd = priv_data;
+
+ BUG_ON(!prtd);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_BUF_RECFG:
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ q6asm_run(prtd->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -151,18 +170,31 @@
pr_debug("token = 0x%08x\n", token);
in_frame_info[token][0] = payload[4];
in_frame_info[token][1] = payload[5];
- prtd->pcm_irq_pos += in_frame_info[token][0];
- pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- if (atomic_read(&prtd->in_count) <= prtd->periods)
- atomic_inc(&prtd->in_count);
- wake_up(&the_locks.read_wait);
- if (prtd->mmap_flag
- && q6asm_is_cpu_buf_avail_nolock(OUT,
+ /* assume data size = 0 during flushing */
+ if (in_frame_info[token][0]) {
+ prtd->pcm_irq_pos += in_frame_info[token][0];
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag &&
+ q6asm_is_cpu_buf_avail_nolock(OUT,
prtd->audio_client,
&size, &idx))
- q6asm_read_nolock(prtd->audio_client);
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ pr_debug("%s: reclaim flushed buf in_count %x\n",
+ __func__, atomic_read(&prtd->in_count));
+ atomic_inc(&prtd->in_count);
+ if (atomic_read(&prtd->in_count) == prtd->periods) {
+ pr_info("%s: reclaimed all bufs\n", __func__);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.read_wait);
+ }
+ }
break;
}
case APR_BASIC_RSP_RESULT: {
@@ -681,6 +713,7 @@
int dir, ret;
struct msm_plat_data *pdata;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_evt event;
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
@@ -737,9 +770,12 @@
pr_debug("%s: session ID %d\n",
__func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) prtd;
+ msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
+ prtd->session_id, substream->stream,
+ event);
}
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 537719f..711291da 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,12 @@
unsigned int format;
};
+struct msm_pcm_routing_fdai_data {
+ u16 be_srate; /* track prior backend sample rate for flushing purpose */
+ int strm_id; /* ASM stream ID */
+ struct msm_pcm_routing_evt event_info;
+};
+
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
@@ -250,25 +256,35 @@
/* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+ fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
/* MULTIMEDIA1 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA2 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA3 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA4 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA5 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA6 */
- {INVALID_SESSION, INVALID_SESSION},
- /* MULTIMEDIA7 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
+ /* MULTIMEDIA7*/
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA8 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA9 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
};
/* Track performance mode of all front-end multimedia sessions.
@@ -334,7 +350,7 @@
mutex_lock(&routing_lock);
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -376,7 +392,7 @@
mutex_lock(&routing_lock);
payload.num_copps = 0; /* only RX needs to use payload */
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
/* re-enable EQ if active */
@@ -435,6 +451,19 @@
mutex_unlock(&routing_lock);
}
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info)
+{
+ msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+ stream_type);
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+ fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+ else
+ fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+}
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
{
int i, port_type, session_type, path_type, topology;
@@ -470,8 +499,8 @@
}
}
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].be_srate = 0;
mutex_unlock(&routing_lock);
}
@@ -497,6 +526,7 @@
int session_type, path_type, port_id, topology;
u32 channels;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -523,10 +553,23 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
set_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
channels = msm_bedais[reg].channel;
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__, fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -549,8 +592,14 @@
msm_bedais[reg].sample_rate, channels,
topology, false, bits_per_sample);
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
+
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
@@ -566,7 +615,8 @@
(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
voc_start_playback(set, msm_bedais[reg].port_id);
clear_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
adm_close(msm_bedais[reg].port_id,
fe_dai_perf_mode[val][session_type]);
@@ -574,7 +624,7 @@
(fe_dai_perf_mode[val][session_type] == false))
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[val][session_type]);
}
}
@@ -1203,12 +1253,12 @@
static void msm_send_eq_values(int eq_idx)
{
int result;
- struct audio_client *ac =
- q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ struct audio_client *ac = q6asm_get_audio_client(
+ fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
if (ac == NULL) {
pr_err("%s: Could not get audio client for session: %d\n",
- __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
goto done;
}
@@ -2034,6 +2084,15 @@
};
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -3040,6 +3099,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -3068,6 +3128,10 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3218,6 +3282,8 @@
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3474,6 +3540,7 @@
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3484,6 +3551,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3516,6 +3584,7 @@
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3527,6 +3596,7 @@
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3716,6 +3786,8 @@
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+ {"INTHFP_UL_HL", NULL, "INT_BT_SCO_TX"},
+ {"INT_BT_SCO_RX", NULL, "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"MI2S_RX", NULL, "MI2S_DL_HL"},
@@ -3881,7 +3953,9 @@
mutex_lock(&routing_lock);
topology = get_topology(path_type);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+ fe_dai_map[i][session_type].be_srate =
+ bedai->sample_rate;
adm_close(bedai->port_id,
fe_dai_perf_mode[i][session_type]);
srs_port_id = -1;
@@ -3908,6 +3982,7 @@
u32 channels;
bool playback, capture;
uint16_t bits_per_sample = 16;
+ struct msm_pcm_routing_fdai_data *fdai;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3939,8 +4014,21 @@
capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ if (session_type == SESSION_TYPE_TX &&
+ fdai->be_srate &&
+ (fdai->be_srate != bedai->sample_rate)) {
+ pr_debug("%s: flush strm %d diff BE rates\n",
+ __func__,
+ fdai->strm_id);
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
channels = bedai->channel;
if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
@@ -3967,7 +4055,7 @@
}
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type,
+ fdai->strm_id, path_type,
fe_dai_perf_mode[i][session_type]);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 10be150..4f7c4e3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -133,6 +133,12 @@
MSM_BACKEND_DAI_MAX,
};
+enum msm_pcm_routing_event {
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ MSM_PCM_RT_EVT_MAX,
+};
+
/* dai_id: front-end ID,
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
@@ -142,6 +148,15 @@
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type);
+struct msm_pcm_routing_evt {
+ void (*event_func)(enum msm_pcm_routing_event, void *);
+ void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info);
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
int msm_routing_check_backend_enabled(int fedai_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 95114e0..631e9bd 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1256,6 +1256,7 @@
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_WRITE_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_CMD_ADD_TOPOLOGIES:
@@ -1744,6 +1745,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_READ_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1837,6 +1839,7 @@
rc);
goto fail_cmd;
}
+ ac->io_mode |= TUN_WRITE_IO_MODE;
return 0;
fail_cmd:
return -EINVAL;
@@ -1977,6 +1980,49 @@
return -EINVAL;
}
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback_v2 open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+ open.bits_per_sample = bits_per_sample;
+ open.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s open failed op[0x%x]rc[%d]\n", __func__,
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s timeout. waited for open_loopback rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
@@ -4217,9 +4263,11 @@
{
int cnt = 0;
int loopcnt = 0;
+ int used;
struct audio_port_data *port = NULL;
if (ac->io_mode & SYNC_IO_MODE) {
+ used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
mutex_lock(&ac->cmd_lock);
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
@@ -4229,7 +4277,7 @@
while (cnt >= 0) {
if (!port->buf)
continue;
- port->buf[cnt].used = 1;
+ port->buf[cnt].used = used;
cnt--;
}
}