Merge "mac80211: implement HS2.0 gratuitous ARP/unsolicited NA dropping"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 02d6df9..f6b4923 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -257,6 +257,37 @@
- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets.
- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets.
- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode.
+- qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid
+ tearing. Other tear-check properties are ignored if this property is present.
+ The below tear check configuration properties can be individually tuned if
+ tear check is enabled.
+- qcom,mdss-tear-check-sync-cfg-height: Specifies the vertical total number of lines.
+ The default value is 0xfff0.
+- qcom,mdss-tear-check-sync-init-val: Specifies the init value at which the read pointer gets loaded
+ at vsync edge. The reader pointer refers to the line number of
+ panel buffer that is currently being updated.
+ The default value is panel height.
+- qcom,mdss-tear-check-sync-threshold-start:
+ Allows the first ROI line write to an panel when read pointer is
+ between the range of ROI start line and ROI start line plus this
+ setting.
+ The default value is 4.
+- qcom,mdss-tear-check-sync-threshold-continue:
+ The minimum number of lines the write pointer needs to be
+ above the read pointer so that it is safe to write to the panel.
+ (This check is not done for the first ROI line write of an update)
+ The default value is 4.
+- qcom,mdss-tear-check-start-pos: Specify the y position from which the start_threshold value is
+ added and write is kicked off if the read pointer falls within that
+ region.
+ The default value is panel height.
+- qcom,mdss-tear-check-rd-ptr-trigger-intr:
+ Specify the read pointer value at which an interrupt has to be
+ generated.
+ The default value is panel height + 1.
+- qcom,mdss-tear-check-frame-rate: Specify the value to be a real frame rate(fps) x 100 factor to tune the
+ timing of TE simulation with more precision.
+ The default value is 6000 with 60 fps.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -354,5 +385,12 @@
mdss-dsi-rx-eot-ignore;
mdss-dsi-tx-eot-append;
qcom,ulps-enabled;
+ qcom,mdss-tear-check-sync-cfg-height = <0xfff0>;
+ qcom,mdss-tear-check-sync-init-val = <1280>;
+ qcom,mdss-tear-check-sync-threshold-start = <4>;
+ qcom,mdss-tear-check-sync-threshold-continue = <4>;
+ qcom,mdss-tear-check-start-pos = <1280>;
+ qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>;
+ qcom,mdss-tear-check-frame-rate = <6000>;
};
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 21e09ef..bd11551 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -275,6 +275,12 @@
used to reduce the pending writes limit dynamically
and can be tuned to match performance requirements
depending upon system state.
+- qcom,mdss-clk-levels: This array indicates the mdp core clock level selection
+ array. Core clock is calculated for each frame and
+ hence depending upon calculated value, clock rate
+ will be rounded up to the next level according to
+ this table. Order of entries need to be ordered in
+ ascending order.
Fudge Factors: Fudge factors are used to boost demand for
resources like bus bandswidth, clk rate etc. to
@@ -363,6 +369,9 @@
qcom,mdss-ib-factor = <3 2>; /* 1.5 times */
qcom,mdss-clk-factor = <5 4>; /* 1.25 times */
+ /* Clock levels */
+ qcom,mdss-clk-levels = <92310000, 177780000, 200000000>;
+
qcom,max-clk-rate = <320000000>;
qcom,vbif-settings = <0x0004 0x00000001>,
<0x00D8 0x00000707>;
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index e199e55..d25b456 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -54,11 +54,11 @@
are to be used, so that application processor can query
logical address of the ported generic device to be used.
Other than PC, fields of EA are same across platforms.
- -qcom,slim-mdm: This value indicates presence of slimbus component on
+ - qcom,slim-mdm: This value provides the identifier of slimbus component on
external mdm. This property enables the slimbus driver to
- receive subsytem restart notification from mdm and follow
- appropriate steps to ensure communication on the bus can be
- resumed after mdm-restart.
+ register and receive subsytem restart notification from mdm
+ and follow appropriate steps to ensure communication on the bus
+ can be resumed after mdm-restart.
Example:
slim@fe12f000 {
cell-index = <1>;
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 1504dc0..da71e19 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -33,6 +33,9 @@
When this entry is not present, voting is done by the runtime-pm callbacks.
- qcom,master-id : Master endpoint number used for voting on clocks using the
bus-scaling driver.
+ - qcom,rt-priority : whether spi message queue is set to run as a realtime task.
+ With this spi transaction message pump with high (realtime) priority to reduce
+ the transfer latency on the bus by minimising the delay between a transfer request
Optional properties which are required for support of BAM-mode:
- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
@@ -92,4 +95,5 @@
qcom,bam-producer-pipe-index = <13>;
qcom,ver-reg-exists;
qcom,master-id = <86>;
+ qcom,rt-priority;
};
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 344b57e..969ddcb 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -63,6 +63,29 @@
8 - SIGSEGV faults
16 - SIGBUS faults
+config FORCE_PAGES
+ bool "Force lowmem to be mapped with 4K pages"
+ help
+ There are some advanced debug features that can only be done when
+ memory is mapped with pages instead of sections. Enable this option
+ to always map lowmem pages with pages. This may have a performance
+ cost due to increased TLB pressure.
+
+ If unsure say N.
+
+config FREE_PAGES_RDONLY
+ bool "Set pages as read only while on the buddy list"
+ select FORCE_PAGES
+ select PAGE_POISONING
+ help
+ Pages are always mapped in the kernel. This means that anyone
+ can write to the page if they have the address. Enable this option
+ to mark pages as read only to trigger a fault if any code attempts
+ to write to a page on the buddy list. This may have a performance
+ impact.
+
+ If unsure, say N.
+
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions (read help!)"
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
index 3106cd4..e6aaa41 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -167,5 +167,9 @@
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
qcom,mdss-pan-physical-width-dimension = <52>;
qcom,mdss-pan-physical-height-dimension = <86>;
+ qcom,mdss-tear-check-rd-ptr-trigger-intr = <0x5>;
+ qcom,mdss-tear-check-sync-threshold-start = <0x2>;
+ qcom,mdss-tear-check-sync-threshold-continue = <0x4>;
+ qcom,mdss-tear-check-start-pos = <0x18>;
};
};
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index c070443..93f05c4 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -837,5 +837,53 @@
status = "disabled";
};
};
+
+ pma8084_lpg1: pwm@b100 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb100 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <0>;
+ };
+
+ pma8084_lpg2: pwm@b200 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb200 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <1>;
+ };
+
+ pma8084_lpg3: pwm@b300 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb300 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <2>;
+ };
+
+ pma8084_lpg4: pwm@b400 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb400 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <3>;
+ };
+
+ pma8084_lpg5: pwm@b500 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb500 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <4>;
+ };
+
+ pma8084_lpg6: pwm@b600 {
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xb600 0x100>,
+ <0xb042 0x7e>;
+ reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+ qcom,channel-id = <5>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 1bbc517..5776926 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,6 +36,10 @@
qcom,mdss-ib-factor = <2 1>; /* 2 times */
qcom,mdss-clk-factor = <5 4>; /* 1.25 times */
+ /* Clock levels */
+ qcom,mdss-clk-levels = <92310000 100000000
+ 133330000 177780000 200000000>;
+
qcom,max-clk-rate = <200000000>;
qcom,mdss-pipe-vig-off = <0x00001200>;
qcom,mdss-pipe-rgb-off = <0x00001E00>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 2599c46..8d2414c 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -1387,6 +1387,12 @@
qcom,irq-is-percpu;
interrupts = <1 7 0xf00>;
};
+
+ bimc_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0xfc380000 0x00100000>;
+ reg-names = "bimc";
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 04eca14..9344e89 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,15 +39,15 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 03 00 1E 07 0D 00 00
+ 1D 05 00 1D 0B 0D 00 00
/* Object 7, Instance = 0 */
- 20 08 32
+ 20 0A 32
/* Object 8, Instance = 0 */
- 19 00 14 14 FF 00 FF 00 00 00
+ 19 00 14 14 FF 00 05 00 32 19
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
- 00 32 05 30 0A 05 0A 00 70 03
- FC 01 04 2F F8 DC 00 00 40 00
+ 00 0A 05 30 0A 05 0A 00 70 03
+ FC 01 04 2F 08 24 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -59,16 +59,16 @@
00 00 00 00 00 00 00 00 00 00
00
/* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00
+ 03 19 1E 14 80 05 00 00
/* Object 46, Instance = 0 */
04 03 08 10 00 00 00 00 00
/* Object 47, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
/* Object 48, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
+ 1D C0 22 00 00 00 00 00 00 00
+ 20 19 00 06 06 00 00 64 04 40
+ 00 00 00 05 00 2A 00 00 00 19
+ 34 0C 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00
/* Object 55, Instance = 0 */
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index 929659e..70d53e9 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
reg = <0xfd900000 0x100000>;
reg-names = "mdp_phys";
interrupts = <0 72 0>;
+ vdd-cx-supply = <&pm8110_s1_corner>;
mdss_fb0: qcom,mdss_fb_primary {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index aad838e..d88aba6 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,15 +39,15 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 05 01 0D 01 0E 00 00
+ 1D 05 00 1D 0B 0D 00 00
/* Object 7, Instance = 0 */
- 20 08 32
+ 20 0A 32
/* Object 8, Instance = 0 */
- 19 00 14 14 FF 00 FF 00 00 00
+ 19 00 14 14 FF 00 05 00 32 19
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
- 00 32 05 30 05 05 0A 00 70 03
- FC 01 04 2F F8 DC 00 00 40 00
+ 00 0A 05 30 0A 05 0A 00 70 03
+ FC 01 04 2F 08 24 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -59,16 +59,16 @@
00 00 00 00 00 00 00 00 00 00
00
/* Object 42, Instance = 0 */
- 00 00 00 00 00 00 00 00
+ 03 19 1E 14 80 05 00 00
/* Object 46, Instance = 0 */
04 03 08 10 00 00 00 00 00
/* Object 47, Instance = 0 */
00 00 00 00 00 00 00 00 00 00
/* Object 48, Instance = 0 */
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
+ 1D C0 22 00 00 00 00 00 00 00
+ 20 19 00 06 06 00 00 64 04 40
+ 00 00 00 05 00 2A 00 00 00 19
+ 34 0C 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00
/* Object 55, Instance = 0 */
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index 53abb95..d731ce0 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -96,3 +96,14 @@
qcom,master-en = <1>;
};
};
+
+&sdhc_2 {
+ qcom,nonremovable;
+
+ interrupts = <0 1>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ /delete-property/ cd-gpios;
+};
+
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 1554575..336553a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -183,3 +183,14 @@
&dsi_otm8018b_fwvga_vid {
qcom,cont-splash-enabled;
};
+
+&sdhc_2 {
+ qcom,nonremovable;
+
+ interrupts = <0 1>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ /delete-property/ cd-gpios;
+};
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
index 77f5276..debfc23 100644
--- a/arch/arm/boot/dts/msm8610-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -22,4 +22,6 @@
qcom,board-id = <8 0>;
};
-
+&sdhc_2 {
+ qcom,pad-drv-on = <0x5 0x4 0x4>; /* 12mA, 10mA, 10mA */
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index a409510..90dae06 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -593,6 +593,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 10 0>;
qcom,scl-gpio = <&msmgpio 11 0>;
+ qcom,clk-ctl-xfer;
qcom,master-id = <86>;
};
@@ -1042,6 +1043,12 @@
qcom,irq-is-percpu;
interrupts = <1 7 0xf00>;
};
+
+ bimc_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0xfc380000 0x00100000>;
+ reg-names = "bimc";
+ };
};
&gdsc_vfe {
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dtsi b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
index c93ea12..dabadda 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
@@ -98,3 +98,13 @@
&dsi_ssd2080m_720_vid {
qcom,cont-splash-enabled;
};
+
+&sdhc_2 {
+ qcom,nonremovable;
+
+ interrupts = <0 1>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+ /delete-property/ cd-gpios;
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index 157c136..2e58167 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -27,130 +27,13 @@
qcom,cci-master = <0>;
};
- qcom,camera@6e {
- compatible = "qcom,s5k3l1yx";
- reg = <0x6e>;
- qcom,slave-id = <0x6e 0x0 0x3121>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,actuator-src = <&actuator0>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "s5k3l1yx";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
- qcom,camera@20 {
- compatible = "qcom,imx135";
- reg = <0x20>;
- qcom,slave-id = <0x20 0x0016 0x0135>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "imx135";
- qcom,actuator-src = <&actuator1>;
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,sensor-type = <0>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
- qcom,camera@6c {
- compatible = "qcom,ov2720";
- reg = <0x6c>;
- qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,csiphy-sd-index = <2>;
- qcom,csid-sd-index = <2>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "ov2720";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
- qcom,cam-vreg-type = <0 0 1>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-op-mode = <105000 80000 0>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x7>;
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- status = "ok";
- };
qcom,camera@90 {
compatible = "qcom,mt9m114";
reg = <0x90>;
qcom,slave-id = <0x90 0x0 0x2481>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
+ qcom,csid-sd-index = <1>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
cam_vdig-supply = <&pm8941_l3>;
@@ -178,16 +61,15 @@
qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
};
+
qcom,camera@0 {
cell-index = <0>;
compatible = "qcom,camera";
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,actuator-src = <&actuator0>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,mount-angle = <90>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
+ qcom,actuator-src = <&actuator0>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -206,9 +88,9 @@
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0";
qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
@@ -221,9 +103,7 @@
reg = <0x1>;
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,mount-angle = <90>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -241,10 +121,10 @@
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
"CAM_RESET1",
- "CAM_STANDBY";
- qcom,sensor-position = <1>;
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
@@ -253,28 +133,29 @@
qcom,camera@2 {
cell-index = <2>;
compatible = "qcom,camera";
- reg = <0x2>;
+ reg = <0x02>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
- qcom,cam-vreg-type = <0 0 1>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
+ <&msmgpio 18 0>,
+ <&msmgpio 28 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
qcom,sensor-position = <1>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 1b70557..a22355a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -28,124 +28,6 @@
qcom,cci-master = <0>;
};
- qcom,camera@6e {
- compatible = "qcom,s5k3l1yx";
- reg = <0x6e>;
- qcom,slave-id = <0x6e 0x0 0x3121>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <0>;
- qcom,actuator-src = <&actuator0>;
- qcom,sensor-name = "s5k3l1yx";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs2>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
- qcom,camera@20 {
- compatible = "qcom,imx135";
- reg = <0x20>;
- qcom,slave-id = <0x20 0x0016 0x0135>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <0>;
- qcom,sensor-name = "imx135";
- qcom,actuator-src = <&actuator1>;
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs2>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,sensor-type = <0>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
- qcom,camera@6c {
- compatible = "qcom,ov2720";
- reg = <0x6c>;
- qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,csiphy-sd-index = <2>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <180>;
- qcom,sensor-name = "ov2720";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs2>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
- qcom,cam-vreg-type = <0 0 1>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-op-mode = <105000 80000 0>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x7>;
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
qcom,camera@90 {
compatible = "qcom,mt9m114";
reg = <0x90>;
@@ -179,16 +61,15 @@
qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
};
+
qcom,camera@0 {
cell-index = <0>;
compatible = "qcom,camera";
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <90>;
qcom,actuator-src = <&actuator0>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -199,6 +80,7 @@
qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
<&msmgpio 90 0>,
<&msmgpio 89 0>;
@@ -206,9 +88,9 @@
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0";
qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
@@ -220,10 +102,8 @@
compatible = "qcom,camera";
reg = <0x1>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <1>;
- qcom,mount-angle = <180>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -232,15 +112,17 @@
qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
qcom,cam-vreg-op-mode = <105000 80000 0>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>,
+ <&msmgpio 91 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,sensor-position = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
@@ -249,12 +131,10 @@
qcom,camera@2 {
cell-index = <2>;
compatible = "qcom,camera";
- reg = <0x2>;
+ reg = <0x02>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
- qcom,mount-angle = <180>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
+ qcom,mount-angle = <90>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -265,6 +145,7 @@
qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 17 0>,
<&msmgpio 18 0>,
<&msmgpio 28 0>;
@@ -272,9 +153,9 @@
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
qcom,sensor-position = <1>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index f3dff1a..c3c0d47 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,127 +37,6 @@
qcom,cci-master = <0>;
};
- qcom,camera@6e {
- compatible = "qcom,s5k3l1yx";
- reg = <0x6e>;
- qcom,slave-id = <0x6e 0x0 0x3121>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,actuator-src = <&actuator0>;
- qcom,led-flash-src = <&led_flash0>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "s5k3l1yx";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
- qcom,camera@20 {
- compatible = "qcom,imx135";
- reg = <0x20>;
- qcom,slave-id = <0x20 0x0016 0x0135>;
- qcom,csiphy-sd-index = <0>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "imx135";
- qcom,actuator-src = <&actuator1>;
- qcom,led-flash-src = <&led_flash0>;
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>,
- <&msmgpio 89 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 30000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x1F>;
- qcom,sensor-position = <0>;
- qcom,sensor-mode = <0>;
- qcom,sensor-type = <0>;
- qcom,cci-master = <0>;
- status = "ok";
- };
-
-
- qcom,camera@6c {
- compatible = "qcom,ov2720";
- reg = <0x6c>;
- qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,csiphy-sd-index = <2>;
- qcom,csid-sd-index = <2>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "ov2720";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
- qcom,cam-vreg-type = <0 0 1>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-op-mode = <105000 80000 0>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x7>;
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <1>;
- status = "ok";
- };
-
qcom,camera@90 {
compatible = "qcom,mt9m114";
reg = <0x90>;
@@ -191,6 +70,7 @@
qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
};
+
qcom,camera@0 {
cell-index = <0>;
compatible = "qcom,camera";
@@ -200,8 +80,6 @@
qcom,mount-angle = <90>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -212,6 +90,7 @@
qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
<&msmgpio 90 0>,
<&msmgpio 89 0>;
@@ -219,9 +98,9 @@
qcom,gpio-standby = <2>;
qcom,gpio-req-tbl-num = <0 1 2>;
qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1",
- "CAM_STANDBY";
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0";
qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
@@ -233,10 +112,8 @@
compatible = "qcom,camera";
reg = <0x1>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
- qcom,vdd-cx-supply = <&pm8841_s2>;
- qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -246,14 +123,17 @@
qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
- gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>,
+ <&msmgpio 91 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,sensor-position = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0>;
qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
@@ -276,16 +156,18 @@
qcom,cam-vreg-op-mode = <105000 80000 0>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>;
+ <&msmgpio 18 0>,
+ <&msmgpio 28 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
qcom,sensor-position = <1>;
qcom,sensor-mode = <0>;
qcom,cci-master = <1>;
status = "ok";
};
-
};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 7e102fe..fd4221f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -198,17 +198,17 @@
&cci {
- qcom,camera@6e {
+ qcom,camera@0 {
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
};
- qcom,camera@20 {
+ qcom,camera@1 {
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
};
- qcom,camera@6c {
+ qcom,camera@2 {
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b85af9f..e0f2ef2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -2448,6 +2448,12 @@
interrupts = <0 1 0>;
};
+ bimc_sharedmem {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0xfc380000 0x00100000>;
+ reg-names = "bimc";
+ };
+
qcom,smdtty {
compatible = "qcom,smdtty";
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
index d679880..df04f82 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -74,6 +74,54 @@
qcom,auto-mode-enable = <0>;
status = "okay";
};
+
+ pwm@b100 {
+ status = "disabled";
+ };
+
+ pwm@b200 {
+ status = "disabled";
+ };
+
+ pwm@b300 {
+ status = "disabled";
+ };
+
+ pwm@b400 {
+ status = "disabled";
+ };
+
+ pwm@b500 {
+ status = "disabled";
+ };
+
+ pwm@b600 {
+ status = "disabled";
+ };
+
+ pwm@b700 {
+ status = "disabled";
+ };
+
+ pwm@b800 {
+ status = "disabled";
+ };
+
+ pwm@e400 {
+ status = "disabled";
+ };
+
+ pwm@e500 {
+ status = "disabled";
+ };
+
+ pwm@e600 {
+ status = "disabled";
+ };
+
+ pwm@e700 {
+ status = "disabled";
+ };
};
&pma8084_mvs1 {
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
index 680674d..12ed7d4 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -200,9 +200,12 @@
};
gpio@c700 { /* GPIO 8 */
- /* Unused */
- qcom,mode = <0>; /* Digital input */
- qcom,pull = <0>; /* Pull up 30 uA */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <0>; /* Do not invert the output */
+ qcom,vin-sel = <2>; /* PMA8084 S4 = 1.8V */
+ qcom,src-sel = <2>; /* Special function 1=LPG 3 */
+ qcom,out-strength = <3>; /* High drive Strength*/
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index c06ebf8..ab4ffb5 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -210,3 +210,7 @@
status = "ok";
};
};
+
+&dsi_generic_720p_cmd {
+ qcom,mdss-dsi-bl-pmic-bank-select = <3>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index ae0547f..d398f72 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1723,7 +1723,7 @@
<3240000 1600000>,
<4048000 1600000>,
<4264000 1600000>;
- qcom,max-hw-load = <1281600>; /* max(4k X 2304 @ 24, 4k X 2160 @ 30) + 1080p @ 30 */
+ qcom,max-hw-load = <1216800>; /* 3840 X 2160 @ 30 fps + 1920 X 1088 @ 30 fps */
qcom,buffer-type-tz-usage-table = <0x241 0x1>,
<0x106 0x2>,
<0x480 0x3>;
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index a26e247..5f008d5 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -487,6 +487,7 @@
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index a908217..6874b28 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -453,6 +453,7 @@
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index a27baba..c5c16c2 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -524,6 +524,7 @@
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 0e8f4916..0fd3191 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -385,4 +385,12 @@
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
+#ifdef CONFIG_FREE_PAGES_RDONLY
+#define mark_addr_rdonly(a) set_memory_ro((unsigned long)a, 1);
+#define mark_addr_rdwrite(a) set_memory_rw((unsigned long)a, 1);
+#else
+#define mark_addr_rdonly(a)
+#define mark_addr_rdwrite(a)
+#endif
+
#endif
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c5fa883..4d24305 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/user.h>
@@ -378,7 +379,12 @@
printk("%04lx ", (unsigned long)p & 0xffff);
for (j = 0; j < 8; j++) {
u32 data;
- if (probe_kernel_address(p, data)) {
+ /*
+ * vmalloc addresses may point to
+ * memory-mapped peripherals
+ */
+ if (is_vmalloc_addr(p) ||
+ probe_kernel_address(p, data)) {
printk(" ********");
} else {
printk(" %08x", data);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
old mode 100755
new mode 100644
index a0f2601..b730091
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4871,13 +4871,7 @@
CLK_LOOKUP("gpll4", gpll4_clk_src.c, ""),
CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "0.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "1.qcom,camera"),
@@ -4888,20 +4882,14 @@
};
static struct clk_lookup msm_clocks_8974_only[] __initdata = {
- CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
- CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "0.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "2.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "1.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "2.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "0.qcom,camera"),
- CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "2.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "1.qcom,camera"),
+ CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "2.qcom,camera"),
};
static struct clk_lookup msm_clocks_8974_common[] __initdata = {
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 19f9c0e..670efe6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -40,6 +40,17 @@
#define SMEM_NUM_SMD_STREAM_CHANNELS 64
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+ (((type)~0 - (a)) < (b) ? true : false)
+
enum {
/* fixed items */
SMEM_PROC_COMM = 0,
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
index 608927c..52d88a1 100644
--- a/arch/arm/mach-msm/include/mach/msm_spi.h
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -22,6 +22,9 @@
* runtime pm (optimizes for power).
* @master_id master id number of the controller's wrapper (BLSP or GSBI).
* When zero, clock path voting is disabled.
+ * @rt when set, spi will pump transaction messages with high (realtime)
+ * priority to reduce the transfer latency on the bus by minimising
+ * the delay between a transfer request.
*/
struct msm_spi_platform_data {
u32 max_clock_speed;
@@ -37,4 +40,5 @@
bool use_bam;
u32 bam_consumer_pipe_index;
u32 bam_producer_pipe_index;
+ bool rt_priority;
};
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
index 5081e7b..2f4185e 100644
--- a/arch/arm/mach-msm/krait-regulator-pmic.c
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -58,7 +58,8 @@
#define REG_GANG_CTL2 0xC1
#define GANG_EN_BIT BIT(7)
-#define REG_PWM_CL 0x60
+#define REG_PWM_CL 0x60
+#define REG_SEC_ACCESS 0xD0
struct krait_vreg_pmic_chip {
struct spmi_device *spmi;
@@ -89,11 +90,21 @@
return 0;
}
-static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+static int write_secure_byte(struct spmi_device *spmi, u16 base,
+ u16 addr, u8 *val)
{
int rc;
+ u8 sec_val = 0xA5;
- rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid,
+ base + REG_SEC_ACCESS, &sec_val, 1);
+ if (rc) {
+ pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+ spmi->sid, base + REG_SEC_ACCESS, sec_val, rc);
+ return rc;
+ }
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid,
+ base + addr, val, 1);
if (rc) {
pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
spmi->sid, addr, *val, rc);
@@ -127,7 +138,7 @@
bool krait_pmic_is_ready(void)
{
if (the_chip == NULL) {
- pr_debug("kait_regulator_pmic not ready yet\n");
+ pr_debug("krait_regulator_pmic not ready yet\n");
return false;
}
return true;
@@ -149,7 +160,7 @@
int rc;
if (the_chip == NULL) {
- pr_debug("kait_regulator_pmic not ready yet\n");
+ pr_debug("krait_regulator_pmic not ready yet\n");
return -ENXIO;
}
@@ -157,8 +168,8 @@
return 0;
setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
- rc = write_byte(the_chip->spmi,
- the_chip->ps_base + REG_PWM_CL, &setpoint);
+ rc = write_secure_byte(the_chip->spmi,
+ the_chip->ps_base, REG_PWM_CL, &setpoint);
pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
the_chip->spmi->sid,
the_chip->ps_base + REG_PWM_CL, rc);
@@ -180,7 +191,7 @@
int rc;
if (the_chip == NULL) {
- pr_debug("kait_regulator_pmic not ready yet\n");
+ pr_debug("krait_regulator_pmic not ready yet\n");
return -ENXIO;
}
@@ -190,8 +201,8 @@
udelay(50);
setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
- rc = write_byte(the_chip->spmi,
- the_chip->ps_base + REG_PWM_CL, &setpoint);
+ rc = write_secure_byte(the_chip->spmi,
+ the_chip->ps_base, REG_PWM_CL, &setpoint);
pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
the_chip->spmi->sid,
the_chip->ps_base + REG_PWM_CL, rc);
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index c99f0ec..af4a6d2 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -30,7 +30,6 @@
#include <linux/kernel_stat.h>
#include <linux/tick.h>
#include <asm/smp_plat.h>
-#include "acpuclock.h"
#include <linux/suspend.h>
#define MAX_LONG_SIZE 24
@@ -199,7 +198,7 @@
switch (val) {
case CPU_ONLINE:
if (!this_cpu->cur_freq)
- this_cpu->cur_freq = acpuclk_get_rate(cpu);
+ this_cpu->cur_freq = cpufreq_quick_get(cpu);
case CPU_ONLINE_FROZEN:
this_cpu->avg_load_maxfreq = 0;
}
@@ -402,7 +401,7 @@
cpufreq_get_policy(&cpu_policy, i);
pcpu->policy_max = cpu_policy.cpuinfo.max_freq;
if (cpu_online(i))
- pcpu->cur_freq = acpuclk_get_rate(i);
+ pcpu->cur_freq = cpufreq_quick_get(i);
cpumask_copy(pcpu->related_cpus, cpu_policy.cpus);
}
freq_transition.notifier_call = cpufreq_transition_handler;
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index a7fc204..a91331e 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -62,6 +62,9 @@
#define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR 0x2004
+#define PRONTO_PMU_SPARE 0x1088
+#define PRONTO_PMU_SPARE_SSR_BIT BIT(23)
+
#define CLK_CTL_WCNSS_RESTART_BIT BIT(0)
#define AXI_HALTREQ 0x0
@@ -376,7 +379,15 @@
struct pronto_data *drv = subsys_to_drv(subsys);
struct platform_device *pdev = wcnss_get_platform_device();
struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
- int ret = -1;
+ void __iomem *base = drv->base;
+ u32 reg;
+ int ret = -1;
+
+ if (base) {
+ reg = readl_relaxed(base + PRONTO_PMU_SPARE);
+ reg |= PRONTO_PMU_SPARE_SSR_BIT;
+ writel_relaxed(reg, base + PRONTO_PMU_SPARE);
+ }
if (pdev && pwlanconfig)
ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index cf69e17..192aaf9 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -70,6 +70,7 @@
USF_OPENED_STATE,
USF_CONFIGURED_STATE,
USF_WORK_STATE,
+ USF_ADSP_RESTART_STATE,
USF_ERROR_STATE
};
@@ -406,6 +407,13 @@
case Q6USM_EVENT_WRITE_DONE:
wake_up(&usf_xx->wait);
break;
+
+ case RESET_EVENTS:
+ pr_err("%s: received RESET_EVENTS\n", __func__);
+ usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+ wake_up(&usf_xx->wait);
+ break;
+
default:
break;
}
@@ -445,6 +453,12 @@
}
break;
+ case RESET_EVENTS:
+ pr_err("%s: received RESET_EVENTS\n", __func__);
+ usf_xx->usf_state = USF_ADSP_RESTART_STATE;
+ wake_up(&usf_xx->wait);
+ break;
+
default:
break;
}
@@ -865,7 +879,9 @@
if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
rc = wait_event_interruptible(usf_xx->wait,
(usf_xx->us_detect_type !=
- USF_US_DETECT_UNDEF));
+ USF_US_DETECT_UNDEF) ||
+ (usf_xx->usf_state ==
+ USF_ADSP_RESTART_STATE));
} else {
if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
timeout = USF_TIMEOUT_JIFFIES;
@@ -874,8 +890,14 @@
}
rc = wait_event_interruptible_timeout(usf_xx->wait,
(usf_xx->us_detect_type !=
- USF_US_DETECT_UNDEF),
- timeout);
+ USF_US_DETECT_UNDEF) ||
+ (usf_xx->usf_state ==
+ USF_ADSP_RESTART_STATE), timeout);
+
+ /* In the case of aDSP restart, "no US" is assumed */
+ if (usf_xx->usf_state == USF_ADSP_RESTART_STATE) {
+ rc = -EFAULT;
+ }
/* In the case of timeout, "no US" is assumed */
if (rc < 0)
pr_err("%s: Getting US detection failed rc[%d]\n",
@@ -1336,7 +1358,8 @@
case US_STOP_TX: {
usf_xx = &usf->usf_tx;
- if (usf_xx->usf_state == USF_WORK_STATE)
+ if ((usf_xx->usf_state == USF_WORK_STATE)
+ || (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
rc = usf_stop_tx(usf);
else {
pr_err("%s: stop_tx: wrong state[%d]\n",
@@ -1349,7 +1372,8 @@
case US_STOP_RX: {
usf_xx = &usf->usf_rx;
- if (usf_xx->usf_state == USF_WORK_STATE)
+ if ((usf_xx->usf_state == USF_WORK_STATE)
+ || (usf_xx->usf_state == USF_ADSP_RESTART_STATE))
usf_disable(usf_xx);
else {
pr_err("%s: stop_rx: wrong state[%d]\n",
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 51a51c5..af3c1f5 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
@@ -488,6 +488,24 @@
}
switch (data->opcode) {
+ case RESET_EVENTS: {
+ pr_err("%s: Reset event is received: %d %d\n",
+ __func__,
+ data->reset_event,
+ data->reset_proc);
+
+ opcode = RESET_EVENTS;
+
+ apr_reset(this_mmap.apr);
+ this_mmap.apr = NULL;
+
+ apr_reset(usc->apr);
+ usc->apr = NULL;
+
+ break;
+ }
+
+
case USM_DATA_EVENT_READ_DONE: {
struct us_port_data *port = &usc->port[OUT];
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
old mode 100644
new mode 100755
index 58e8588..1809cea
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -52,6 +52,7 @@
char *data;
u32 len;
u32 pos;
+ struct mutex mutex;
u32 max_len;
u32 read_idx;
struct msm_rpm_log_platform_data *pdata;
@@ -218,6 +219,7 @@
if (!access_ok(VERIFY_WRITE, bufu, count))
return -EFAULT;
+ mutex_lock(&buf->mutex);
/* check for more messages if local buffer empty */
if (buf->pos == buf->len) {
buf->pos = 0;
@@ -226,6 +228,7 @@
}
if ((file->f_flags & O_NONBLOCK) && buf->len == 0)
+ mutex_unlock(&buf->mutex);
return -EAGAIN;
/* loop until new messages arrive */
@@ -241,6 +244,7 @@
remaining = __copy_to_user(bufu, &(buf->data[buf->pos]), out_len);
buf->pos += out_len - remaining;
+ mutex_unlock(&buf->mutex);
return out_len - remaining;
}
@@ -287,6 +291,7 @@
buf->pdata = pdata;
buf->len = 0;
buf->pos = 0;
+ mutex_init(&buf->mutex);
buf->max_len = PRINTED_LENGTH(pdata->log_len);
buf->read_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
MSM_RPM_LOG_HEAD);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 1241e44..32f9b3b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1035,12 +1035,19 @@
{
unsigned head = ch->half_ch->get_head(ch->recv);
unsigned tail = ch->half_ch->get_tail(ch->recv);
- *ptr = (void *) (ch->recv_data + tail);
+ unsigned fifo_size = ch->fifo_size;
+ BUG_ON(fifo_size >= SZ_1M);
+ BUG_ON(head >= fifo_size);
+ BUG_ON(tail >= fifo_size);
+ BUG_ON(OVERFLOW_ADD_UNSIGNED(uintptr_t, (uintptr_t)ch->recv_data,
+ tail));
+
+ *ptr = (void *) (ch->recv_data + tail);
if (tail <= head)
return head - tail;
else
- return ch->fifo_size - tail;
+ return fifo_size - tail;
}
static int read_intr_blocked(struct smd_channel *ch)
@@ -1140,16 +1147,23 @@
{
unsigned head = ch->half_ch->get_head(ch->send);
unsigned tail = ch->half_ch->get_tail(ch->send);
- *ptr = (void *) (ch->send_data + head);
+ unsigned fifo_size = ch->fifo_size;
+ BUG_ON(fifo_size >= SZ_1M);
+ BUG_ON(head >= fifo_size);
+ BUG_ON(tail >= fifo_size);
+ BUG_ON(OVERFLOW_ADD_UNSIGNED(uintptr_t, (uintptr_t)ch->send_data,
+ head));
+
+ *ptr = (void *) (ch->send_data + head);
if (head < tail) {
return tail - head - SMD_FIFO_FULL_RESERVE;
} else {
if (tail < SMD_FIFO_FULL_RESERVE)
- return ch->fifo_size + tail - head
+ return fifo_size + tail - head
- SMD_FIFO_FULL_RESERVE;
else
- return ch->fifo_size - head;
+ return fifo_size - head;
}
}
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index f41240a..3c7cbeb 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -27,17 +27,6 @@
#include "smem_private.h"
-/**
- * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
- *
- * @type: type to check for overflow
- * @a: left value to use
- * @b: right value to use
- * @returns: true if a + b will result in overflow; false otherwise
- */
-#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
- (((type)~0 - (a)) < (b) ? true : false)
-
#define MODEM_SBL_VERSION_INDEX 7
#define SMEM_VERSION_INFO_SIZE (32 * 4)
#define SMEM_VERSION 0x000B
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 269ae80..3d52735 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -344,11 +344,13 @@
unsigned long size = PAGE_SIZE*numpages; \
unsigned end = start + size; \
\
- if (start < MODULES_VADDR || start >= MODULES_END) \
- return -EINVAL;\
+ if (!IS_ENABLED(CONFIG_FORCE_PAGES)) { \
+ if (start < MODULES_VADDR || start >= MODULES_END) \
+ return -EINVAL;\
\
- if (end < MODULES_VADDR || end >= MODULES_END) \
- return -EINVAL; \
+ if (end < MODULES_VADDR || end >= MODULES_END) \
+ return -EINVAL; \
+ } \
\
apply_to_page_range(&init_mm, start, size, callback, NULL); \
flush_tlb_kernel_range(start, end); \
@@ -1507,6 +1509,100 @@
}
}
+#ifdef CONFIG_FORCE_PAGES
+/*
+ * remap a PMD into pages
+ * We split a single pmd here none of this two pmd nonsense
+ */
+static noinline void split_pmd(pmd_t *pmd, unsigned long addr,
+ unsigned long end, unsigned long pfn,
+ const struct mem_type *type)
+{
+ pte_t *pte, *start_pte;
+
+ start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+
+ pte = start_pte;
+
+ do {
+ set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0);
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ *pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1);
+ mb();
+ flush_pmd_entry(pmd);
+ flush_tlb_all();
+}
+
+/*
+ * It's significantly easier to remap as pages later after all memory is
+ * mapped. Everything is sections so all we have to do is split
+ */
+static void __init remap_pages(void)
+{
+ struct memblock_region *reg;
+
+ for_each_memblock(memory, reg) {
+ phys_addr_t phys_start = reg->base;
+ phys_addr_t phys_end = reg->base + reg->size;
+ unsigned long addr = (unsigned long)__va(phys_start);
+ unsigned long end = (unsigned long)__va(phys_end);
+ pmd_t *pmd = NULL;
+ unsigned long next;
+ unsigned long pfn = __phys_to_pfn(phys_start);
+ bool fixup = false;
+ unsigned long saved_start = addr;
+
+ if (phys_end > arm_lowmem_limit)
+ end = (unsigned long)__va(arm_lowmem_limit);
+ if (phys_start >= phys_end)
+ break;
+
+ pmd = pmd_offset(
+ pud_offset(pgd_offset(&init_mm, addr), addr), addr);
+
+#ifndef CONFIG_ARM_LPAE
+ if (addr & SECTION_SIZE) {
+ fixup = true;
+ pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK);
+ pmd++;
+ }
+
+ if (end & SECTION_SIZE)
+ pmd_empty_section_gap(end);
+#endif
+
+ do {
+ next = addr + SECTION_SIZE;
+
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ split_pmd(pmd, addr, next, pfn,
+ &mem_types[MT_MEMORY]);
+ pmd++;
+ pfn += SECTION_SIZE >> PAGE_SHIFT;
+
+ } while (addr = next, addr < end);
+
+ if (fixup) {
+ /*
+ * Put a faulting page table here to avoid detecting no
+ * pmd when accessing an odd section boundary. This
+ * needs to be faulting to help catch errors and avoid
+ * speculation
+ */
+ pmd = pmd_off_k(saved_start);
+ pmd[0] = pmd[1] & ~1;
+ }
+ }
+}
+#else
+static void __init remap_pages(void)
+{
+
+}
+#endif
+
/*
* paging_init() sets up the page tables, initialises the zone memory
* maps, and sets up the zero page, bad page and bad page tables.
@@ -1521,6 +1617,7 @@
prepare_page_table();
map_lowmem();
dma_contiguous_remap();
+ remap_pages();
devicemaps_init(mdesc);
kmap_init();
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 6312bcd..2adcbbc 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -527,6 +527,7 @@
page = pfn_to_page(pfn);
break;
} else if (ret != -EBUSY) {
+ pfn = 0;
clear_cma_bitmap(cma, pfn, count);
break;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 99647a7..95d90b3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -241,6 +241,7 @@
int in_busy_1;
int in_busy_2;
+ spinlock_t in_busy_lock;
unsigned char *buf_in_1;
unsigned char *buf_in_2;
@@ -383,6 +384,7 @@
struct work_struct diag_usb_disconnect_work;
#endif
struct workqueue_struct *diag_wq;
+ struct workqueue_struct *diag_usb_wq;
struct work_struct diag_drain_work;
struct workqueue_struct *diag_cntl_wq;
uint8_t *msg_masks;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0e475c9..ba13ec1 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1171,6 +1171,7 @@
int remote_token;
int exit_stat;
int clear_read_wakelock;
+ unsigned long flags;
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
@@ -1250,7 +1251,10 @@
process_lock_on_copy(&data->nrt_lock);
clear_read_wakelock++;
}
+ spin_lock_irqsave(&data->in_busy_lock, flags);
data->in_busy_1 = 0;
+ spin_unlock_irqrestore(&data->in_busy_lock,
+ flags);
}
if (data->in_busy_2 == 1) {
num_data++;
@@ -1265,7 +1269,10 @@
process_lock_on_copy(&data->nrt_lock);
clear_read_wakelock++;
}
+ spin_lock_irqsave(&data->in_busy_lock, flags);
data->in_busy_2 = 0;
+ spin_unlock_irqrestore(&data->in_busy_lock,
+ flags);
}
}
if (driver->supports_separate_cmdrsp) {
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 0bbb012..f7e720f 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -73,6 +73,8 @@
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
+ int err;
+ unsigned long flags;
if (buf_length > APPS_BUF_SIZE) {
pr_err("diag: In %s, invalid len %d, permissible len %d\n",
@@ -85,6 +87,7 @@
send.last = (void *)(driver->apps_rsp_buf + buf_length);
send.terminate = 1;
if (!data->in_busy_1) {
+ spin_lock_irqsave(&data->in_busy_lock, flags);
enc.dest = data->buf_in_1;
enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
diag_hdlc_encode(&send, &enc);
@@ -92,9 +95,15 @@
data->write_ptr_1->length = (int)(enc.dest -
(void *)(data->buf_in_1));
data->in_busy_1 = 1;
- diag_device_write(data->buf_in_1, data->peripheral,
+ err = diag_device_write(data->buf_in_1, data->peripheral,
data->write_ptr_1);
+ if (err) {
+ pr_err("diag: In %s, Unable to write to device, err: %d\n",
+ __func__, err);
+ data->in_busy_1 = 0;
+ }
memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
+ spin_unlock_irqrestore(&data->in_busy_lock, flags);
}
}
@@ -462,6 +471,7 @@
struct diag_request *write_ptr_modem = NULL;
int *in_busy_ptr = 0;
int err = 0;
+ unsigned long flags;
/*
* Do not process data on command channel if the
@@ -489,16 +499,16 @@
}
if (write_ptr_modem) {
+ spin_lock_irqsave(&smd_info->in_busy_lock, flags);
write_ptr_modem->length = total_recd;
*in_busy_ptr = 1;
err = diag_device_write(buf, smd_info->peripheral,
write_ptr_modem);
if (err) {
- /* Free up the buffer for future use */
- *in_busy_ptr = 0;
pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
__func__, err);
}
+ spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
}
} else {
/* The data is raw and needs to be hdlc encoded */
@@ -526,6 +536,8 @@
success = diag_add_hdlc_encoding(smd_info, buf,
total_recd, write_buf,
&write_length);
+ spin_lock_irqsave(&smd_info->in_busy_lock,
+ flags);
if (success) {
write_ptr_modem->length = write_length;
*in_busy_ptr = 1;
@@ -533,15 +545,12 @@
smd_info->peripheral,
write_ptr_modem);
if (err) {
- /*
- * Free up the buffer for
- * future use
- */
- *in_busy_ptr = 0;
pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
__func__, err);
}
}
+ spin_unlock_irqrestore(&smd_info->in_busy_lock,
+ flags);
}
}
}
@@ -814,6 +823,43 @@
diag_smd_send_req(smd_info);
}
+#ifdef CONFIG_DIAG_OVER_USB
+static int diag_write_to_usb(struct usb_diag_ch *ch,
+ struct diag_request *write_ptr)
+{
+ int err = 0;
+ uint8_t retry_count, max_retries;
+
+ if (!ch || !write_ptr)
+ return -EIO;
+
+ retry_count = 0;
+ max_retries = 3;
+
+ while (retry_count < max_retries) {
+ retry_count++;
+ /* If USB is not connected, don't try to write */
+ if (!driver->usb_connected) {
+ err = -ENODEV;
+ break;
+ }
+ err = usb_diag_write(ch, write_ptr);
+ if (err == -EAGAIN) {
+ /*
+ * USB is not configured. Wait for sometime and
+ * try again. The value 10000 was chosen empirically
+ * as an optimum value for USB to be configured.
+ */
+ usleep_range(10000, 10100);
+ continue;
+ } else {
+ break;
+ }
+ }
+ return err;
+}
+#endif
+
int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0, index;
@@ -919,7 +965,7 @@
if (driver->write_ptr_svc) {
driver->write_ptr_svc->length = driver->used;
driver->write_ptr_svc->buf = buf;
- err = usb_diag_write(driver->legacy_ch,
+ err = diag_write_to_usb(driver->legacy_ch,
driver->write_ptr_svc);
/* Free the buffer if write failed */
if (err) {
@@ -941,7 +987,7 @@
" USB: ", 16, 1, DUMP_PREFIX_ADDRESS,
buf, write_ptr->length, 1);
#endif /* DIAG DEBUG */
- err = usb_diag_write(driver->legacy_ch, write_ptr);
+ err = diag_write_to_usb(driver->legacy_ch, write_ptr);
}
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (data_type == SDIO_DATA) {
@@ -1817,10 +1863,14 @@
void diag_reset_smd_data(int queue)
{
int i;
+ unsigned long flags;
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ spin_lock_irqsave(&driver->smd_data[i].in_busy_lock, flags);
driver->smd_data[i].in_busy_1 = 0;
driver->smd_data[i].in_busy_2 = 0;
+ spin_unlock_irqrestore(&driver->smd_data[i].in_busy_lock,
+ flags);
if (queue)
/* Poll SMD data channels to check for data */
queue_work(driver->smd_data[i].wq,
@@ -1829,8 +1879,12 @@
if (driver->supports_separate_cmdrsp) {
for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ spin_lock_irqsave(&driver->smd_cmd[i].in_busy_lock,
+ flags);
driver->smd_cmd[i].in_busy_1 = 0;
driver->smd_cmd[i].in_busy_2 = 0;
+ spin_unlock_irqrestore(&driver->smd_cmd[i].in_busy_lock,
+ flags);
if (queue)
/* Poll SMD data channels to check for data */
queue_work(driver->diag_wq,
@@ -1868,11 +1922,10 @@
N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
N_LEGACY_READ);
if (err)
- printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
-
+ goto exit;
driver->usb_connected = 1;
diag_reset_smd_data(RESET_AND_QUEUE);
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
/* Poll SMD CNTL channels to check for data */
diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
}
@@ -1889,26 +1942,40 @@
printk(KERN_INFO "diag: No USB MDM ch");
}
#endif
+
return 0;
+exit:
+ pr_err("diag: unable to alloc USB req on legacy ch, err: %d", err);
+ return err;
}
int diagfwd_disconnect(void)
{
int i;
+ unsigned long flags;
+ struct diag_smd_info *smd_info = NULL;
printk(KERN_DEBUG "diag: USB disconnected\n");
driver->usb_connected = 0;
driver->debug_flag = 1;
if (driver->logging_mode == USB_MODE) {
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 1;
- driver->smd_data[i].in_busy_2 = 1;
+ smd_info = &driver->smd_data[i];
+ spin_lock_irqsave(&smd_info->in_busy_lock, flags);
+ smd_info->in_busy_1 = 1;
+ smd_info->in_busy_2 = 1;
+ spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
}
if (driver->supports_separate_cmdrsp) {
for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
- driver->smd_cmd[i].in_busy_1 = 1;
- driver->smd_cmd[i].in_busy_2 = 1;
+ smd_info = &driver->smd_cmd[i];
+ spin_lock_irqsave(&smd_info->in_busy_lock,
+ flags);
+ smd_info->in_busy_1 = 1;
+ smd_info->in_busy_2 = 1;
+ spin_unlock_irqrestore(&smd_info->in_busy_lock,
+ flags);
}
}
}
@@ -1928,7 +1995,9 @@
{
int i;
int found_it = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&data->in_busy_lock, flags);
for (i = 0; i < num_channels; i++) {
if (buf == (void *)data[i].buf_in_1) {
data[i].in_busy_1 = 0;
@@ -1940,6 +2009,7 @@
break;
}
}
+ spin_unlock_irqrestore(&data->in_busy_lock, flags);
if (found_it) {
if (data[i].type == SMD_DATA_TYPE)
@@ -2053,11 +2123,11 @@
{
switch (event) {
case USB_DIAG_CONNECT:
- queue_work(driver->diag_wq,
+ queue_work(driver->diag_usb_wq,
&driver->diag_usb_connect_work);
break;
case USB_DIAG_DISCONNECT:
- queue_work(driver->diag_wq,
+ queue_work(driver->diag_usb_wq,
&driver->diag_usb_disconnect_work);
break;
case USB_DIAG_READ_DONE:
@@ -2071,7 +2141,6 @@
break;
}
}
-
#endif /* DIAG OVER USB */
void diag_smd_notify(void *ctxt, unsigned event)
@@ -2283,6 +2352,7 @@
smd_info->type = type;
smd_info->encode_hdlc = 0;
mutex_init(&smd_info->smd_ch_mutex);
+ spin_lock_init(&smd_info->in_busy_lock);
switch (peripheral) {
case MODEM_DATA:
@@ -2596,6 +2666,7 @@
kmemleak_not_leak(driver->apps_rsp_buf);
}
driver->diag_wq = create_singlethread_workqueue("diag_wq");
+ driver->diag_usb_wq = create_singlethread_workqueue("diag_usb_wq");
#ifdef CONFIG_DIAG_OVER_USB
INIT_WORK(&(driver->diag_usb_connect_work),
diag_usb_connect_work_fn);
@@ -2643,6 +2714,8 @@
kfree(driver->user_space_data_buf);
if (driver->diag_wq)
destroy_workqueue(driver->diag_wq);
+ if (driver->diag_usb_wq)
+ destroy_workqueue(driver->diag_usb_wq);
}
void diagfwd_exit(void)
@@ -2680,4 +2753,5 @@
kfree(driver->apps_rsp_buf);
kfree(driver->user_space_data_buf);
destroy_workqueue(driver->diag_wq);
+ destroy_workqueue(driver->diag_usb_wq);
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 56f55b7..d7f0bcb 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -59,58 +59,60 @@
#define QCRYPTO_HIGH_BANDWIDTH_TIMEOUT 1000
struct crypto_stat {
- u32 aead_sha1_aes_enc;
- u32 aead_sha1_aes_dec;
- u32 aead_sha1_des_enc;
- u32 aead_sha1_des_dec;
- u32 aead_sha1_3des_enc;
- u32 aead_sha1_3des_dec;
- u32 aead_ccm_aes_enc;
- u32 aead_ccm_aes_dec;
- u32 aead_rfc4309_ccm_aes_enc;
- u32 aead_rfc4309_ccm_aes_dec;
- u32 aead_op_success;
- u32 aead_op_fail;
- u32 aead_bad_msg;
- u32 ablk_cipher_aes_enc;
- u32 ablk_cipher_aes_dec;
- u32 ablk_cipher_des_enc;
- u32 ablk_cipher_des_dec;
- u32 ablk_cipher_3des_enc;
- u32 ablk_cipher_3des_dec;
- u32 ablk_cipher_op_success;
- u32 ablk_cipher_op_fail;
- u32 sha1_digest;
- u32 sha256_digest;
- u32 sha_op_success;
- u32 sha_op_fail;
- u32 sha1_hmac_digest;
- u32 sha256_hmac_digest;
- u32 sha_hmac_op_success;
- u32 sha_hmac_op_fail;
+ u64 aead_sha1_aes_enc;
+ u64 aead_sha1_aes_dec;
+ u64 aead_sha1_des_enc;
+ u64 aead_sha1_des_dec;
+ u64 aead_sha1_3des_enc;
+ u64 aead_sha1_3des_dec;
+ u64 aead_ccm_aes_enc;
+ u64 aead_ccm_aes_dec;
+ u64 aead_rfc4309_ccm_aes_enc;
+ u64 aead_rfc4309_ccm_aes_dec;
+ u64 aead_op_success;
+ u64 aead_op_fail;
+ u64 aead_bad_msg;
+ u64 ablk_cipher_aes_enc;
+ u64 ablk_cipher_aes_dec;
+ u64 ablk_cipher_des_enc;
+ u64 ablk_cipher_des_dec;
+ u64 ablk_cipher_3des_enc;
+ u64 ablk_cipher_3des_dec;
+ u64 ablk_cipher_op_success;
+ u64 ablk_cipher_op_fail;
+ u64 sha1_digest;
+ u64 sha256_digest;
+ u64 sha_op_success;
+ u64 sha_op_fail;
+ u64 sha1_hmac_digest;
+ u64 sha256_hmac_digest;
+ u64 sha_hmac_op_success;
+ u64 sha_hmac_op_fail;
};
static struct crypto_stat _qcrypto_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
+static bool _qcrypto_init_assign;
struct crypto_priv;
struct crypto_engine {
struct list_head elist;
void *qce; /* qce handle */
struct platform_device *pdev; /* platform device */
struct crypto_async_request *req; /* current active request */
+ struct qcrypto_resp_ctx *arsp; /* rsp associcated with req */
+ int res; /* execution result */
struct crypto_priv *pcp;
struct tasklet_struct done_tasklet;
uint32_t bus_scale_handle;
struct crypto_queue req_queue; /*
* request queue for those requests
- * that have this engine assgined
+ * that have this engine assigned
* waiting to be executed
*/
- u32 total_req;
- u32 err_req;
+ u64 total_req;
+ u64 err_req;
u32 unit;
u32 ce_device;
- int res; /* execution result */
unsigned int signature;
uint32_t high_bw_req_count;
bool high_bw_req;
@@ -140,6 +142,12 @@
int32_t total_units; /* total units of engines */
struct mutex engine_lock;
struct crypto_engine *next_engine; /* next assign engine */
+ struct crypto_queue req_queue; /*
+ * request queue for those requests
+ * that waiting for an available
+ * engine.
+ */
+
};
static struct crypto_priv qcrypto_dev;
static struct crypto_engine *_qcrypto_static_assign_engine(
@@ -261,6 +269,11 @@
#define QCRYPTO_CCM4309_NONCE_LEN 3
struct qcrypto_cipher_ctx {
+ struct list_head rsp_queue; /* response queue */
+ struct crypto_engine *pengine; /* fixed engine assigned to this tfm */
+ struct crypto_priv *cp;
+ unsigned int flags;
+
u8 auth_key[QCRYPTO_MAX_KEY_SIZE];
u8 iv[QCRYPTO_MAX_IV_LENGTH];
@@ -270,13 +283,18 @@
unsigned int authsize;
unsigned int auth_key_len;
- struct crypto_priv *cp;
- unsigned int flags;
- struct crypto_engine *pengine; /* fixed engine assigned */
u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN];
};
+struct qcrypto_resp_ctx {
+ struct list_head list;
+ struct crypto_async_request *async_req; /* async req */
+ int res; /* execution result */
+};
+
struct qcrypto_cipher_req_ctx {
+ struct qcrypto_resp_ctx rsp_entry;/* rsp entry. */
+ struct crypto_engine *pengine; /* engine assigned to this request */
u8 *iv;
u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
unsigned int ivsize;
@@ -301,6 +319,8 @@
#define SHA_MAX_STATE_SIZE (SHA256_DIGEST_SIZE / sizeof(u32))
#define SHA_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
+#define MSM_QCRYPTO_REQ_QUEUE_LENGTH 50
+
static uint8_t _std_init_vector_sha1_uint8[] = {
0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89,
0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x32, 0x54, 0x76,
@@ -316,18 +336,21 @@
};
struct qcrypto_sha_ctx {
+ struct list_head rsp_queue; /* response queue */
+ struct crypto_engine *pengine; /* fixed engine assigned to this tfm */
+ struct crypto_priv *cp;
+ unsigned int flags;
enum qce_hash_alg_enum alg;
uint32_t diglen;
uint32_t authkey_in_len;
uint8_t authkey[SHA_MAX_BLOCK_SIZE];
struct ahash_request *ahash_req;
struct completion ahash_req_complete;
- struct crypto_priv *cp;
- unsigned int flags;
- struct crypto_engine *pengine; /* fixed engine assigned */
};
struct qcrypto_sha_req_ctx {
+ struct qcrypto_resp_ctx rsp_entry;/* rsp entry. */
+ struct crypto_engine *pengine; /* engine assigned to this request */
struct scatterlist *src;
uint32_t nbytes;
@@ -411,11 +434,10 @@
int ret = 0;
if (high_bw_req && pengine->high_bw_req == false) {
- pm_stay_awake(&pengine->pdev->dev);
ret = qce_enable_clk(pengine->qce);
if (ret) {
pr_err("%s Unable enable clk\n", __func__);
- goto clk_err;
+ return;
}
ret = msm_bus_scale_client_update_request(
pengine->bus_scale_handle, 1);
@@ -423,7 +445,7 @@
pr_err("%s Unable to set to high bandwidth\n",
__func__);
qce_disable_clk(pengine->qce);
- goto clk_err;
+ return;
}
pengine->high_bw_req = true;
} else if (high_bw_req == false && pengine->high_bw_req == true) {
@@ -432,7 +454,7 @@
if (ret) {
pr_err("%s Unable to set to low bandwidth\n",
__func__);
- goto clk_err;
+ return;
}
ret = qce_disable_clk(pengine->qce);
if (ret) {
@@ -442,16 +464,10 @@
if (ret)
pr_err("%s Unable to set to high bandwidth\n",
__func__);
- goto clk_err;
+ return;
}
pengine->high_bw_req = false;
- pm_relax(&pengine->pdev->dev);
}
- return;
-clk_err:
- pm_relax(&pengine->pdev->dev);
- return;
-
}
static void qcrypto_bw_scale_down_timer_callback(unsigned long data)
@@ -473,20 +489,26 @@
add_timer(&(pengine->bw_scale_down_timer));
}
-static void qcrypto_ce_bw_scaling_req(struct crypto_engine *pengine,
+static void qcrypto_ce_bw_scaling_req(struct crypto_priv *cp,
bool high_bw_req)
{
- mutex_lock(&pengine->pcp->engine_lock);
- if (high_bw_req) {
- if (pengine->high_bw_req_count == 0)
- qcrypto_ce_set_bus(pengine, true);
- pengine->high_bw_req_count++;
- } else {
- pengine->high_bw_req_count--;
- if (pengine->high_bw_req_count == 0)
- qcrypto_bw_set_timeout(pengine);
+ struct crypto_engine *pengine;
+
+ if (cp->platform_support.bus_scale_table == NULL)
+ return;
+ mutex_lock(&cp->engine_lock);
+ list_for_each_entry(pengine, &cp->engine_list, elist) {
+ if (high_bw_req) {
+ if (pengine->high_bw_req_count == 0)
+ qcrypto_ce_set_bus(pengine, true);
+ pengine->high_bw_req_count++;
+ } else {
+ pengine->high_bw_req_count--;
+ if (pengine->high_bw_req_count == 0)
+ qcrypto_bw_set_timeout(pengine);
+ }
}
- mutex_unlock(&pengine->pcp->engine_lock);
+ mutex_unlock(&cp->engine_lock);
}
static void qcrypto_low_bw_req_work(struct work_struct *work)
@@ -597,11 +619,14 @@
/* random first IV */
get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
- ctx->pengine = _qcrypto_static_assign_engine(ctx->cp);
- if (ctx->pengine == NULL)
- return -ENODEV;
- if (ctx->cp->platform_support.bus_scale_table != NULL)
- qcrypto_ce_bw_scaling_req(ctx->pengine, true);
+ if (_qcrypto_init_assign) {
+ ctx->pengine = _qcrypto_static_assign_engine(ctx->cp);
+ if (ctx->pengine == NULL)
+ return -ENODEV;
+ } else
+ ctx->pengine = NULL;
+ qcrypto_ce_bw_scaling_req(ctx->cp, true);
+ INIT_LIST_HEAD(&ctx->rsp_queue);
return 0;
};
@@ -619,11 +644,14 @@
sha_ctx->cp = q_alg->cp;
sha_ctx->flags = 0;
sha_ctx->ahash_req = NULL;
- sha_ctx->pengine = _qcrypto_static_assign_engine(sha_ctx->cp);
- if (sha_ctx->pengine == NULL)
- return -ENODEV;
- if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
- qcrypto_ce_bw_scaling_req(sha_ctx->pengine, true);
+ if (_qcrypto_init_assign) {
+ sha_ctx->pengine = _qcrypto_static_assign_engine(sha_ctx->cp);
+ if (sha_ctx->pengine == NULL)
+ return -ENODEV;
+ } else
+ sha_ctx->pengine = NULL;
+ qcrypto_ce_bw_scaling_req(sha_ctx->cp, true);
+ INIT_LIST_HEAD(&sha_ctx->rsp_queue);
return 0;
};
@@ -631,13 +659,13 @@
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(tfm);
+ if (!list_empty(&sha_ctx->rsp_queue))
+ pr_err("_qcrypto_ahash_cra_exit: requests still outstanding");
if (sha_ctx->ahash_req != NULL) {
ahash_request_free(sha_ctx->ahash_req);
sha_ctx->ahash_req = NULL;
}
- if (sha_ctx->pengine &&
- sha_ctx->cp->platform_support.bus_scale_table != NULL)
- qcrypto_ce_bw_scaling_req(sha_ctx->pengine, false);
+ qcrypto_ce_bw_scaling_req(sha_ctx->cp, false);
};
@@ -686,16 +714,18 @@
{
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->pengine && ctx->cp->platform_support.bus_scale_table != NULL)
- qcrypto_ce_bw_scaling_req(ctx->pengine, false);
+ if (!list_empty(&ctx->rsp_queue))
+ pr_err("_qcrypto__cra_ablkcipher_exit: requests still outstanding");
+ qcrypto_ce_bw_scaling_req(ctx->cp, false);
};
static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm)
{
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->pengine && ctx->cp->platform_support.bus_scale_table != NULL)
- qcrypto_ce_bw_scaling_req(ctx->pengine, false);
+ if (!list_empty(&ctx->rsp_queue))
+ pr_err("_qcrypto__cra_aead_exit: requests still outstanding");
+ qcrypto_ce_bw_scaling_req(ctx->cp, false);
};
static int _disp_stats(int id)
@@ -708,117 +738,117 @@
pstat = &_qcrypto_stat;
len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "\nQualcomm crypto accelerator %d Statistics:\n",
+ "\nQualcomm crypto accelerator %d Statistics\n",
id + 1);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK AES CIPHER encryption : %d\n",
+ " ABLK AES CIPHER encryption : %llu\n",
pstat->ablk_cipher_aes_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK AES CIPHER decryption : %d\n",
+ " ABLK AES CIPHER decryption : %llu\n",
pstat->ablk_cipher_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK DES CIPHER encryption : %d\n",
+ " ABLK DES CIPHER encryption : %llu\n",
pstat->ablk_cipher_des_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK DES CIPHER decryption : %d\n",
+ " ABLK DES CIPHER decryption : %llu\n",
pstat->ablk_cipher_des_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK 3DES CIPHER encryption : %d\n",
+ " ABLK 3DES CIPHER encryption : %llu\n",
pstat->ablk_cipher_3des_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK 3DES CIPHER decryption : %d\n",
+ " ABLK 3DES CIPHER decryption : %llu\n",
pstat->ablk_cipher_3des_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK CIPHER operation success: %d\n",
+ " ABLK CIPHER operation success : %llu\n",
pstat->ablk_cipher_op_success);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " ABLK CIPHER operation fail : %d\n",
+ " ABLK CIPHER operation fail : %llu\n",
pstat->ablk_cipher_op_fail);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-AES encryption : %d\n",
+ " AEAD SHA1-AES encryption : %llu\n",
pstat->aead_sha1_aes_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-AES decryption : %d\n",
+ " AEAD SHA1-AES decryption : %llu\n",
pstat->aead_sha1_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-DES encryption : %d\n",
+ " AEAD SHA1-DES encryption : %llu\n",
pstat->aead_sha1_des_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-DES decryption : %d\n",
+ " AEAD SHA1-DES decryption : %llu\n",
pstat->aead_sha1_des_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-3DES encryption : %d\n",
+ " AEAD SHA1-3DES encryption : %llu\n",
pstat->aead_sha1_3des_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD SHA1-3DES decryption : %d\n",
+ " AEAD SHA1-3DES decryption : %llu\n",
pstat->aead_sha1_3des_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD CCM-AES encryption : %d\n",
+ " AEAD CCM-AES encryption : %llu\n",
pstat->aead_ccm_aes_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD CCM-AES decryption : %d\n",
+ " AEAD CCM-AES decryption : %llu\n",
pstat->aead_ccm_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD RFC4309-CCM-AES encryption : %d\n",
+ " AEAD RFC4309-CCM-AES encryption : %llu\n",
pstat->aead_rfc4309_ccm_aes_enc);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD RFC4309-CCM-AES decryption : %d\n",
+ " AEAD RFC4309-CCM-AES decryption : %llu\n",
pstat->aead_rfc4309_ccm_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD operation success : %d\n",
+ " AEAD operation success : %llu\n",
pstat->aead_op_success);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD operation fail : %d\n",
+ " AEAD operation fail : %llu\n",
pstat->aead_op_fail);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " AEAD bad message : %d\n",
+ " AEAD bad message : %llu\n",
pstat->aead_bad_msg);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA1 digest : %d\n",
+ " SHA1 digest : %llu\n",
pstat->sha1_digest);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA256 digest : %d\n",
+ " SHA256 digest : %llu\n",
pstat->sha256_digest);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA operation fail : %d\n",
+ " SHA operation fail : %llu\n",
pstat->sha_op_fail);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA operation success : %d\n",
+ " SHA operation success : %llu\n",
pstat->sha_op_success);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA1 HMAC digest : %d\n",
+ " SHA1 HMAC digest : %llu\n",
pstat->sha1_hmac_digest);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA256 HMAC digest : %d\n",
+ " SHA256 HMAC digest : %llu\n",
pstat->sha256_hmac_digest);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA HMAC operation fail : %d\n",
+ " SHA HMAC operation fail : %llu\n",
pstat->sha_hmac_op_fail);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
- " SHA HMAC operation success : %d\n",
+ " SHA HMAC operation success : %llu\n",
pstat->sha_hmac_op_success);
spin_lock_irqsave(&cp->lock, flags);
list_for_each_entry(pe, &cp->engine_list, elist) {
len += snprintf(
_debug_read_buf + len,
DEBUG_MAX_RW_BUF - len - 1,
- " Engine %d Req : %d\n",
+ " Engine %4d Req : %llu\n",
pe->unit,
pe->total_req
);
len += snprintf(
_debug_read_buf + len,
DEBUG_MAX_RW_BUF - len - 1,
- " Engine %d Req Error : %d\n",
+ " Engine %4d Req Error : %llu\n",
pe->unit,
pe->err_req
);
@@ -847,7 +877,6 @@
tasklet_kill(&pengine->done_tasklet);
cancel_work_sync(&pengine->low_bw_req_ws);
del_timer_sync(&pengine->bw_scale_down_timer);
- device_init_wakeup(&pengine->pdev->dev, false);
if (pengine->bus_scale_handle != 0)
msm_bus_scale_unregister_client(pengine->bus_scale_handle);
@@ -1020,27 +1049,73 @@
return 0;
};
+static void _qcrypto_tfm_complete(struct crypto_priv *cp, u32 type,
+ void *tfm_ctx)
+{
+ unsigned long flags;
+ struct qcrypto_resp_ctx *arsp;
+ struct list_head *plist;
+ struct crypto_async_request *areq;
+
+ switch (type) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ plist = &((struct qcrypto_sha_ctx *) tfm_ctx)->rsp_queue;
+ break;
+ case CRYPTO_ALG_TYPE_ABLKCIPHER:
+ case CRYPTO_ALG_TYPE_AEAD:
+ default:
+ plist = &((struct qcrypto_cipher_ctx *) tfm_ctx)->rsp_queue;
+ break;
+ }
+again:
+ spin_lock_irqsave(&cp->lock, flags);
+ if (list_empty(plist)) {
+ arsp = NULL; /* nothing to do */
+ } else {
+ arsp = list_first_entry(plist,
+ struct qcrypto_resp_ctx, list);
+ if (arsp->res == -EINPROGRESS)
+ arsp = NULL; /* still in progress */
+ else
+ list_del(&arsp->list); /* request is complete */
+ }
+ spin_unlock_irqrestore(&cp->lock, flags);
+ if (arsp) {
+ areq = arsp->async_req;
+ areq->complete(areq, arsp->res);
+ goto again;
+ }
+}
+
static void req_done(unsigned long data)
{
struct crypto_async_request *areq;
struct crypto_engine *pengine = (struct crypto_engine *)data;
struct crypto_priv *cp;
unsigned long flags;
+ struct qcrypto_resp_ctx *arsp;
int res;
+ u32 type = 0;
+ void *tfm_ctx = NULL;
cp = pengine->pcp;
spin_lock_irqsave(&cp->lock, flags);
areq = pengine->req;
- pengine->req = NULL;
- res = pengine->res;
- spin_unlock_irqrestore(&cp->lock, flags);
- if (areq)
- areq->complete(areq, res);
- if (res)
- pengine->err_req++;
- _start_qcrypto_process(cp, pengine);
-};
+ arsp = pengine->arsp;
+ res = pengine->res;
+ pengine->req = NULL;
+ pengine->arsp = NULL;
+ if (areq) {
+ type = crypto_tfm_alg_type(areq->tfm);
+ tfm_ctx = crypto_tfm_ctx(areq->tfm);
+ arsp->res = res;
+ }
+ spin_unlock_irqrestore(&cp->lock, flags);
+ _start_qcrypto_process(cp, pengine);
+ if (areq)
+ _qcrypto_tfm_complete(cp, type, tfm_ctx);
+}
static void _qce_ahash_complete(void *cookie, unsigned char *digest,
unsigned char *authdata, int ret)
@@ -1057,7 +1132,7 @@
pstat = &_qcrypto_stat;
- pengine = sha_ctx->pengine;
+ pengine = rctx->pengine;
#ifdef QCRYPTO_DEBUG
dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
areq, ret);
@@ -1103,10 +1178,12 @@
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(areq->base.tfm);
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
+ struct qcrypto_cipher_req_ctx *rctx;
struct crypto_engine *pengine;
pstat = &_qcrypto_stat;
- pengine = ctx->pengine;
+ rctx = ablkcipher_request_ctx(areq);
+ pengine = rctx->pengine;
#ifdef QCRYPTO_DEBUG
dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
areq, ret);
@@ -1158,8 +1235,8 @@
struct crypto_engine *pengine;
pstat = &_qcrypto_stat;
- pengine = ctx->pengine;
rctx = aead_request_ctx(areq);
+ pengine = rctx->pengine;
if (rctx->mode == QCE_MODE_CCM) {
if (cp->ce_support.aligned_only) {
@@ -1363,6 +1440,7 @@
req = container_of(async_req, struct ablkcipher_request, base);
cipher_ctx = crypto_tfm_ctx(async_req->tfm);
rctx = ablkcipher_request_ctx(req);
+ rctx->pengine = pengine;
tfm = crypto_ablkcipher_reqtfm(req);
if (pengine->pcp->ce_support.aligned_only) {
uint32_t bytes = 0;
@@ -1426,6 +1504,7 @@
struct ahash_request, base);
rctx = ahash_request_ctx(req);
sha_ctx = crypto_tfm_ctx(async_req->tfm);
+ rctx->pengine = pengine;
sreq.qce_cb = _qce_ahash_complete;
sreq.digest = &rctx->digest[0];
@@ -1481,6 +1560,7 @@
struct crypto_aead *aead = crypto_aead_reqtfm(req);
rctx = aead_request_ctx(req);
+ rctx->pengine = pengine;
cipher_ctx = crypto_tfm_ctx(async_req->tfm);
qreq.op = QCE_REQ_AEAD;
@@ -1695,28 +1775,93 @@
struct crypto_engine *pengine)
{
struct crypto_async_request *async_req = NULL;
- struct crypto_async_request *backlog = NULL;
+ struct crypto_async_request *backlog_eng = NULL;
+ struct crypto_async_request *backlog_cp = NULL;
unsigned long flags;
u32 type;
int ret = 0;
struct crypto_stat *pstat;
+ void *tfm_ctx;
+ struct qcrypto_cipher_req_ctx *cipher_rctx;
+ struct qcrypto_sha_req_ctx *ahash_rctx;
+ struct ablkcipher_request *ablkcipher_req;
+ struct ahash_request *ahash_req;
+ struct aead_request *aead_req;
+ struct qcrypto_resp_ctx *arsp;
pstat = &_qcrypto_stat;
again:
spin_lock_irqsave(&cp->lock, flags);
- if (pengine->req == NULL) {
- backlog = crypto_get_backlog(&pengine->req_queue);
- async_req = crypto_dequeue_request(&pengine->req_queue);
- pengine->req = async_req;
+ if (pengine->req) {
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return 0;
}
- spin_unlock_irqrestore(&cp->lock, flags);
- if (!async_req)
- return ret;
- if (backlog)
- backlog->complete(backlog, -EINPROGRESS);
- type = crypto_tfm_alg_type(async_req->tfm);
+ backlog_eng = crypto_get_backlog(&pengine->req_queue);
+
+ /* try to get request from request queue of the engine first */
+ async_req = crypto_dequeue_request(&pengine->req_queue);
+ if (!async_req) {
+ /*
+ * if no request from the engine,
+ * try to get from request queue of driver
+ */
+ backlog_cp = crypto_get_backlog(&cp->req_queue);
+ async_req = crypto_dequeue_request(&cp->req_queue);
+ if (!async_req) {
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return 0;
+ }
+ }
+
+ /* add associated rsp entry to tfm response queue */
+ type = crypto_tfm_alg_type(async_req->tfm);
+ tfm_ctx = crypto_tfm_ctx(async_req->tfm);
+ switch (type) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ ahash_req = container_of(async_req,
+ struct ahash_request, base);
+ ahash_rctx = ahash_request_ctx(ahash_req);
+ arsp = &ahash_rctx->rsp_entry;
+ list_add_tail(
+ &arsp->list,
+ &((struct qcrypto_sha_ctx *)tfm_ctx)
+ ->rsp_queue);
+ break;
+ case CRYPTO_ALG_TYPE_ABLKCIPHER:
+ ablkcipher_req = container_of(async_req,
+ struct ablkcipher_request, base);
+ cipher_rctx = ablkcipher_request_ctx(ablkcipher_req);
+ arsp = &cipher_rctx->rsp_entry;
+ list_add_tail(
+ &arsp->list,
+ &((struct qcrypto_sha_ctx *)tfm_ctx)
+ ->rsp_queue);
+ break;
+ case CRYPTO_ALG_TYPE_AEAD:
+ default:
+ aead_req = container_of(async_req,
+ struct aead_request, base);
+ cipher_rctx = aead_request_ctx(aead_req);
+ arsp = &cipher_rctx->rsp_entry;
+ list_add_tail(
+ &arsp->list,
+ &((struct qcrypto_sha_ctx *)tfm_ctx)
+ ->rsp_queue);
+ break;
+ }
+
+ arsp->res = -EINPROGRESS;
+ arsp->async_req = async_req;
+ pengine->req = async_req;
+ pengine->arsp = arsp;
+
+ spin_unlock_irqrestore(&cp->lock, flags);
+ if (backlog_eng)
+ backlog_eng->complete(backlog_eng, -EINPROGRESS);
+ if (backlog_cp)
+ backlog_cp->complete(backlog_cp, -EINPROGRESS);
switch (type) {
case CRYPTO_ALG_TYPE_ABLKCIPHER:
ret = _qcrypto_process_ablkcipher(pengine, async_req);
@@ -1732,9 +1877,11 @@
};
pengine->total_req++;
if (ret) {
+ arsp->res = ret;
pengine->err_req++;
spin_lock_irqsave(&cp->lock, flags);
pengine->req = NULL;
+ pengine->arsp = NULL;
spin_unlock_irqrestore(&cp->lock, flags);
if (type == CRYPTO_ALG_TYPE_ABLKCIPHER)
@@ -1745,11 +1892,22 @@
else
pstat->aead_op_fail++;
- async_req->complete(async_req, ret);
+ _qcrypto_tfm_complete(cp, type, tfm_ctx);
goto again;
};
return ret;
-};
+}
+
+static struct crypto_engine *_avail_eng(struct crypto_priv *cp)
+{
+ struct crypto_engine *pe = NULL;
+
+ list_for_each_entry(pe, &cp->engine_list, elist) {
+ if (pe->req == NULL)
+ return pe;
+ }
+ return NULL;
+}
static int _qcrypto_queue_req(struct crypto_priv *cp,
struct crypto_engine *pengine,
@@ -1765,9 +1923,15 @@
}
spin_lock_irqsave(&cp->lock, flags);
- ret = crypto_enqueue_request(&pengine->req_queue, req);
+ if (pengine) {
+ ret = crypto_enqueue_request(&pengine->req_queue, req);
+ } else {
+ ret = crypto_enqueue_request(&cp->req_queue, req);
+ pengine = _avail_eng(cp);
+ }
spin_unlock_irqrestore(&cp->lock, flags);
- _start_qcrypto_process(cp, pengine);
+ if (pengine)
+ _start_qcrypto_process(cp, pengine);
return ret;
}
@@ -3997,6 +4161,7 @@
pengine->pcp = cp;
pengine->pdev = pdev;
pengine->req = NULL;
+ pengine->signature = 0xdeadbeef;
pengine->high_bw_req_count = 0;
pengine->high_bw_req = false;
@@ -4004,11 +4169,8 @@
INIT_WORK(&pengine->low_bw_req_ws, qcrypto_low_bw_req_work);
pengine->bw_scale_down_timer.function =
qcrypto_bw_scale_down_timer_callback;
-
- device_init_wakeup(&pengine->pdev->dev, true);
-
tasklet_init(&pengine->done_tasklet, req_done, (unsigned long)pengine);
- crypto_init_queue(&pengine->req_queue, 50);
+ crypto_init_queue(&pengine->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
mutex_lock(&cp->engine_lock);
cp->total_units++;
@@ -4083,6 +4245,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4116,6 +4279,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4152,6 +4316,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->sha_alg.halg.base.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4188,6 +4353,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4226,6 +4392,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->sha_alg.halg.base.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4262,6 +4429,7 @@
dev_err(&pdev->dev,
"The algorithm name %s is too long.\n",
q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
goto err;
}
}
@@ -4523,6 +4691,7 @@
pcp->ce_lock_count = 0;
pcp->platform_support.bus_scale_table = NULL;
pcp->next_engine = NULL;
+ crypto_init_queue(&pcp->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
return platform_driver_register(&_qualcomm_crypto);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 9d7bb96..f230033 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1137,9 +1137,7 @@
uint32_t flags)
{
phys_addr_t pt_val;
- unsigned int link[230];
- unsigned int *cmds = &link[0];
- int sizedwords = 0;
+ unsigned int *link = NULL, *cmds;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int num_iommu_units;
struct kgsl_context *context;
@@ -1160,6 +1158,14 @@
}
adreno_ctx = ADRENO_CONTEXT(context);
+ link = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (link == NULL) {
+ result = -ENOMEM;
+ goto done;
+ }
+
+ cmds = link;
+
result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
if (result)
@@ -1179,17 +1185,11 @@
cmds += _adreno_iommu_setstate_v1(device, cmds, pt_val,
num_iommu_units, flags);
- sizedwords += (cmds - &link[0]);
- if (sizedwords == 0) {
- KGSL_DRV_ERR(device, "no commands generated\n");
- BUG();
- }
/* invalidate all base pointers */
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
*cmds++ = 0x7fff;
- sizedwords += 2;
- if (sizedwords > (ARRAY_SIZE(link))) {
+ if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) {
KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
BUG();
}
@@ -1198,7 +1198,8 @@
* use the global timestamp for iommu clock disablement
*/
result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
- KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+ KGSL_CMD_FLAGS_PMODE, link,
+ (unsigned int)(cmds - link));
/*
* On error disable the IOMMU clock right away otherwise turn it off
@@ -1212,6 +1213,7 @@
KGSL_IOMMU_CONTEXT_USER);
done:
+ kfree(link);
kgsl_context_put(context);
return result;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index cf577fd..3d9206b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -724,6 +724,11 @@
*cmds++ = val;
*cmds++ = 0xFFFFFFFF;
*cmds++ = 0xFFFFFFFF;
+
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
return cmds - start;
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a535a97..2025d73 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4150,6 +4150,7 @@
/* CP registers */
adreno_set_protected_registers(device, &index, 0x1C0, 5);
+ adreno_set_protected_registers(device, &index, 0x1EC, 1);
adreno_set_protected_registers(device, &index, 0x1F6, 1);
adreno_set_protected_registers(device, &index, 0x1F8, 2);
adreno_set_protected_registers(device, &index, 0x45E, 2);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index cef2805..488e5a8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1048,6 +1048,10 @@
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
*cmds++ = lock_vars->turn;
*cmds++ = 0;
@@ -1062,11 +1066,19 @@
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
*cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
*cmds++ = lock_vars->flag[PROC_APPS];
*cmds++ = lock_vars->turn;
*cmds++ = 0;
+ /* TEST_TWO_MEMS turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += adreno_add_idle_cmds(adreno_dev, cmds);
return cmds - start;
@@ -1104,6 +1116,10 @@
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += adreno_add_idle_cmds(adreno_dev, cmds);
return cmds - start;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index d64d0d3..65e607b 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -401,6 +401,10 @@
status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
if (status)
return status;
+
+ /* Mark the setstate memory as read only */
+ mmu->setstate_memory.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index eba5ca8..0659b77 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -484,6 +484,7 @@
};
static int num_kpbl_leds_on;
+static DEFINE_MUTEX(flash_lock);
static int
qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
@@ -1408,7 +1409,10 @@
{
int rc;
- mutex_lock(&led->lock);
+ if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1)
+ mutex_lock(&flash_lock);
+ else
+ mutex_lock(&led->lock);
switch (led->id) {
case QPNP_ID_WLED:
@@ -1448,7 +1452,10 @@
dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
break;
}
- mutex_unlock(&led->lock);
+ if (led->id == QPNP_ID_FLASH1_LED0 || led->id == QPNP_ID_FLASH1_LED1)
+ mutex_unlock(&flash_lock);
+ else
+ mutex_unlock(&led->lock);
}
@@ -3314,7 +3321,9 @@
goto fail_id_check;
}
- mutex_init(&led->lock);
+ if (led->id != QPNP_ID_FLASH1_LED0 &&
+ led->id != QPNP_ID_FLASH1_LED1)
+ mutex_init(&led->lock);
INIT_WORK(&led->work, qpnp_led_work);
rc = qpnp_led_initialize(led);
@@ -3409,7 +3418,9 @@
fail_id_check:
for (i = 0; i < parsed_leds; i++) {
- mutex_destroy(&led_array[i].lock);
+ if (led_array[i].id != QPNP_ID_FLASH1_LED0 &&
+ led_array[i].id != QPNP_ID_FLASH1_LED1)
+ mutex_destroy(&led_array[i].lock);
led_classdev_unregister(&led_array[i].cdev);
}
@@ -3423,7 +3434,10 @@
for (i = 0; i < parsed_leds; i++) {
cancel_work_sync(&led_array[i].work);
- mutex_destroy(&led_array[i].lock);
+ if (led_array[i].id != QPNP_ID_FLASH1_LED0 &&
+ led_array[i].id != QPNP_ID_FLASH1_LED1)
+ mutex_destroy(&led_array[i].lock);
+
led_classdev_unregister(&led_array[i].cdev);
switch (led_array[i].id) {
case QPNP_ID_WLED:
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index ab21404..87a4ab9 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -45,6 +45,7 @@
#define AES_XTS_IV_LEN 16
#define DM_REQ_CRYPT_ERROR -1
+#define DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC -2
struct req_crypt_result {
struct completion completion;
@@ -105,9 +106,10 @@
atomic_dec(&io->pending);
- if (error < 0)
+ if (error < 0) {
dm_kill_unmapped_request(clone, error);
- else
+ mempool_free(io, req_io_pool);
+ } else
dm_dispatch_request(clone);
}
@@ -158,8 +160,6 @@
struct req_crypt_result result;
struct scatterlist *req_sg_read = NULL;
int err = 0;
- struct req_iterator iter2;
- struct bio_vec *bvec = NULL;
u8 IV[AES_XTS_IV_LEN];
if (io) {
@@ -217,11 +217,12 @@
goto ablkcipher_req_alloc_failure;
}
-
- /* total bytes to copy */
- bvec = NULL;
- rq_for_each_segment(bvec, clone, iter2) {
- total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ total_bytes_in_req = clone->__data_len;
+ if (total_bytes_in_req > REQ_DM_512_KB) {
+ DMERR("%s total_bytes_in_req > 512 MB %d",
+ __func__, total_bytes_in_req);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
}
memset(IV, 0, AES_XTS_IV_LEN);
@@ -263,7 +264,8 @@
kfree(req_sg_read);
submit_request:
- io->error = err;
+ if (io)
+ io->error = err;
req_crypt_dec_pending_decrypt(io);
}
@@ -277,7 +279,8 @@
struct bio *bio_src = NULL;
unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0,
total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0;
- struct req_iterator iter;
+ struct req_iterator iter = {0, NULL};
+ struct req_iterator iter1 = {0, NULL};
struct ablkcipher_request *req = NULL;
struct req_crypt_result result;
struct bio_vec *bvec = NULL;
@@ -350,20 +353,28 @@
goto ablkcipher_req_alloc_failure;
}
+ total_bytes_in_req = clone->__data_len;
+ if (total_bytes_in_req > REQ_DM_512_KB) {
+ DMERR("%s total_bytes_in_req > 512 MB %d",
+ __func__, total_bytes_in_req);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
rq_for_each_segment(bvec, clone, iter) {
-try_again:
if (bvec->bv_len > remaining_size) {
page = NULL;
- page = mempool_alloc(req_page_pool, gfp_mask);
- if (!page) {
- DMERR("%s Crypt page alloc failed", __func__);
- congestion_wait(BLK_RW_ASYNC, HZ/100);
- goto try_again;
+ while (page == NULL) {
+ page = mempool_alloc(req_page_pool, gfp_mask);
+ if (!page) {
+ DMERR("%s Crypt page alloc failed",
+ __func__);
+ congestion_wait(BLK_RW_ASYNC, HZ/100);
+ }
}
+
bvec->bv_page = page;
bvec->bv_offset = 0;
- total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
remaining_size = PAGE_SIZE - bvec->bv_len;
if (remaining_size < 0)
BUG();
@@ -371,7 +382,6 @@
bvec->bv_page = page;
bvec->bv_offset = PAGE_SIZE - remaining_size;
remaining_size = remaining_size - bvec->bv_len;
- total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
}
}
@@ -379,7 +389,7 @@
if ((total_sg_len_req_out <= 0) ||
(total_sg_len_req_out > MAX_SG_LIST)) {
DMERR("%s Request Error %d", __func__, total_sg_len_req_out);
- error = DM_REQ_CRYPT_ERROR;
+ error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
goto ablkcipher_req_alloc_failure;
}
@@ -405,13 +415,13 @@
if (result.err) {
DMERR("%s error = %d encrypting the request\n",
__func__, result.err);
- error = DM_REQ_CRYPT_ERROR;
+ error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
goto ablkcipher_req_alloc_failure;
}
break;
default:
- error = DM_REQ_CRYPT_ERROR;
+ error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
goto ablkcipher_req_alloc_failure;
}
@@ -428,13 +438,25 @@
if (req)
ablkcipher_request_free(req);
+ if (error == DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC) {
+ bvec = NULL;
+ rq_for_each_segment(bvec, clone, iter1) {
+ if (bvec->bv_offset == 0) {
+ mempool_free(bvec->bv_page, req_page_pool);
+ bvec->bv_page = NULL;
+ } else
+ bvec->bv_page = NULL;
+ }
+ }
+
kfree(req_sg_in);
kfree(req_sg_out);
submit_request:
- io->error = error;
+ if (io)
+ io->error = error;
req_crypt_dec_pending_encrypt(io);
}
@@ -449,7 +471,7 @@
else if (rq_data_dir(io->cloned_request) == READ)
req_cryptd_crypt_read_convert(io);
else
- DMERR("%s received non-write request for Clone %u\n",
+ DMERR("%s received non-read/write request for Clone %u\n",
__func__, (unsigned int)io->cloned_request);
}
@@ -484,6 +506,11 @@
if (bio_sectors(bio) && bdev != bdev->bd_contains) {
struct hd_struct *p = bdev->bd_part;
+ /*
+ * Check for integer overflow, should never happen.
+ */
+ if (p->start_sect > (UINT_MAX - bio->bi_sector))
+ BUG();
bio->bi_sector += p->start_sect;
bio->bi_bdev = bdev->bd_contains;
@@ -543,9 +570,16 @@
union map_info *map_context)
{
struct req_dm_crypt_io *req_io = NULL;
- int error = DM_MAPIO_REMAPPED, copy_bio_sector_to_req = 0;
+ int error = DM_REQ_CRYPT_ERROR, copy_bio_sector_to_req = 0;
struct bio *bio_src = NULL;
+ if ((rq_data_dir(clone) != READ) &&
+ (rq_data_dir(clone) != WRITE)) {
+ error = DM_REQ_CRYPT_ERROR;
+ DMERR("%s Unknown request\n", __func__);
+ goto submit_request;
+ }
+
req_io = mempool_alloc(req_io_pool, GFP_NOWAIT);
if (!req_io) {
DMERR("%s req_io allocation failed\n", __func__);
@@ -598,9 +632,6 @@
req_cryptd_queue_crypt(req_io);
error = DM_MAPIO_SUBMITTED;
goto submit_request;
- } else {
- error = DM_REQ_CRYPT_ERROR;
- DMERR("%s Unknown request\n", __func__);
}
submit_request:
@@ -608,22 +639,24 @@
}
-static int req_crypt_status(struct dm_target *ti, status_type_t type,
- char *result, unsigned maxlen)
-{
- return 0;
-}
-
static void req_crypt_dtr(struct dm_target *ti)
{
- if (req_crypt_queue)
+ if (req_crypt_queue) {
destroy_workqueue(req_crypt_queue);
- if (req_io_pool)
+ req_crypt_queue = NULL;
+ }
+ if (req_io_pool) {
mempool_destroy(req_io_pool);
- if (req_page_pool)
+ req_io_pool = NULL;
+ }
+ if (req_page_pool) {
mempool_destroy(req_page_pool);
- if (tfm)
+ req_page_pool = NULL;
+ }
+ if (tfm) {
crypto_free_ablkcipher(tfm);
+ tfm = NULL;
+ }
}
@@ -635,71 +668,96 @@
{
unsigned long long tmpll;
char dummy;
+ int err = DM_REQ_CRYPT_ERROR;
- if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &dev)) {
- DMERR(" %s Device Lookup failed\n", __func__);
- return DM_REQ_CRYPT_ERROR;
+ if (argc < 5) {
+ DMERR(" %s Not enough args\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
- if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
- DMERR("%s Invalid device sector\n", __func__);
- return DM_REQ_CRYPT_ERROR;
+ if (argv[3]) {
+ if (dm_get_device(ti, argv[3],
+ dm_table_get_mode(ti->table), &dev)) {
+ DMERR(" %s Device Lookup failed\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
+ }
+ } else {
+ DMERR(" %s Arg[3] invalid\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
+
+ if (argv[4]) {
+ if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
+ DMERR("%s Invalid device sector\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
+ }
+ } else {
+ DMERR(" %s Arg[4]invalid\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
+ }
+
start_sector_orig = tmpll;
req_crypt_queue = alloc_workqueue("req_cryptd",
- WQ_HIGHPRI |
- WQ_CPU_INTENSIVE|
- WQ_MEM_RECLAIM,
- 1);
+ WQ_NON_REENTRANT |
+ WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE|
+ WQ_MEM_RECLAIM,
+ 1);
if (!req_crypt_queue) {
DMERR("%s req_crypt_queue not allocated\n", __func__);
- return DM_REQ_CRYPT_ERROR;
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
/* Allocate the crypto alloc blk cipher and keep the handle */
tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0);
if (IS_ERR(tfm)) {
- DMERR("%s ablkcipher tfm allocation failed : error = %lu\n",
- __func__, PTR_ERR(tfm));
- return DM_REQ_CRYPT_ERROR;
+ DMERR("%s ablkcipher tfm allocation failed : error\n",
+ __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
if (!req_io_pool) {
DMERR("%s req_io_pool not allocated\n", __func__);
- return DM_REQ_CRYPT_ERROR;
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!req_page_pool) {
DMERR("%s req_page_pool not allocated\n", __func__);
- return DM_REQ_CRYPT_ERROR;
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
}
-
- return 0;
-}
-
-static void req_crypt_postsuspend(struct dm_target *ti)
-{
-}
-
-static int req_crypt_preresume(struct dm_target *ti)
-{
- return 0;
-}
-
-static void req_crypt_resume(struct dm_target *ti)
-{
-}
-
-/* Message interface
- * key set <key>
- * key wipe
- */
-static int req_crypt_message(struct dm_target *ti, unsigned argc, char **argv)
-{
- return 0;
+ err = 0;
+ctr_exit:
+ if (err != 0) {
+ if (req_crypt_queue) {
+ destroy_workqueue(req_crypt_queue);
+ req_crypt_queue = NULL;
+ }
+ if (req_io_pool) {
+ mempool_destroy(req_io_pool);
+ req_io_pool = NULL;
+ }
+ if (req_page_pool) {
+ mempool_destroy(req_page_pool);
+ req_page_pool = NULL;
+ }
+ if (tfm) {
+ crypto_free_ablkcipher(tfm);
+ tfm = NULL;
+ }
+ }
+ return err;
}
static int req_crypt_iterate_devices(struct dm_target *ti,
@@ -716,11 +774,6 @@
.dtr = req_crypt_dtr,
.map_rq = req_crypt_map,
.rq_end_io = req_crypt_endio,
- .status = req_crypt_status,
- .postsuspend = req_crypt_postsuspend,
- .preresume = req_crypt_preresume,
- .resume = req_crypt_resume,
- .message = req_crypt_message,
.iterate_devices = req_crypt_iterate_devices,
};
@@ -733,8 +786,10 @@
return -ENOMEM;
r = dm_register_target(&req_crypt_target);
- if (r < 0)
+ if (r < 0) {
DMERR("register failed %d", r);
+ kmem_cache_destroy(_req_crypt_io_pool);
+ }
return r;
}
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 262fb38..9fff025 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -101,24 +101,6 @@
of any CID of MSM_CSI22_HEADER can be routed to of pixel
or raw data interface in VFE.
-config S5K3L1YX
- bool "Sensor S5K3L1YX (BAYER 12M)"
- depends on MSMB_CAMERA
- ---help---
- Samsung 12 MP Bayer Sensor with auto focus, uses
- 4 mipi lanes, preview config = 1984 * 1508 at 30 fps,
- snapshot config = 4000 * 3000 at 20 fps,
- hfr video at 60, 90 and 120 fps.
-
-config IMX135
- bool "Sensor IMX135 (BAYER 12M)"
- depends on MSMB_CAMERA
- ---help---
- Sony 12 MP Bayer Sensor with auto focus, uses
- 4 mipi lanes, preview config = 2104 x 1560 at 49 fps,
- snapshot config = 4208 x 3120 at 24 fps,
- Video HDR support.
-
config IMX134
bool "Sensor IMX134 (BAYER 8M)"
depends on MSMB_CAMERA
@@ -128,15 +110,6 @@
HFR @60fps and @120fps
Video HDR support.
-config OV2720
- bool "Sensor OV2720 (BAYER 2M)"
- depends on MSMB_CAMERA
- ---help---
- OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes,
- preview and snapshot config at 1932 * 1092 at 30 fps,
- hfr video at 60, 90 and 120 fps. This sensor driver does
- not support auto focus.
-
config OV9724
bool "Sensor OV9724 (BAYER 2M)"
depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 43cdcbb..170efa8 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -345,20 +345,17 @@
rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
if (rc < 0)
- goto set_fmt_fail;
+ return rc;
rc = camera_check_event_status(&event);
if (rc < 0)
- goto set_fmt_fail;
+ return rc;
+
sp->is_vb2_valid = 1;
}
return rc;
-set_fmt_fail:
- kzfree(sp->vb2_q.drv_priv);
- sp->vb2_q.drv_priv = NULL;
- return rc;
}
static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh,
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 de67fa0..4beb3c3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,8 @@
(~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
#define VFE32_CLK_IDX 0
+#define MSM_ISP32_TOTAL_WM_UB 792
+
static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = {
/*vfe32 clock info for B-family: 8610 */
{"vfe_clk_src", 266670000},
@@ -787,7 +789,43 @@
msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm));
}
-static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
+static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev)
+{
+ int i;
+ uint32_t ub_offset = 0;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ uint32_t total_image_size = 0;
+ uint32_t num_used_wms = 0;
+ uint32_t prop_size = 0;
+ uint32_t wm_ub_size;
+ uint64_t delta;
+ for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+ if (axi_data->free_wm[i] > 0) {
+ num_used_wms++;
+ total_image_size += axi_data->wm_image_size[i];
+ }
+ }
+ prop_size = MSM_ISP32_TOTAL_WM_UB -
+ axi_data->hw_info->min_wm_ub * num_used_wms;
+ for (i = 0; i < axi_data->hw_info->num_wm; i++) {
+ if (axi_data->free_wm[i]) {
+ delta =
+ (uint64_t)(axi_data->wm_image_size[i] *
+ prop_size);
+ do_div(delta, total_image_size);
+ wm_ub_size = axi_data->hw_info->min_wm_ub +
+ (uint32_t)delta;
+ msm_camera_io_w(ub_offset << 16 |
+ (wm_ub_size - 1), vfe_dev->vfe_base +
+ VFE32_WM_BASE(i) + 0xC);
+ ub_offset += wm_ub_size;
+ } else
+ msm_camera_io_w(0,
+ vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC);
+ }
+}
+
+static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev)
{
int i;
uint32_t ub_offset = 0;
@@ -809,6 +847,16 @@
}
}
+static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev)
+{
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
+ if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
+ msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev);
+ else
+ msm_vfe32_cfg_axi_ub_equal_default(vfe_dev);
+}
+
static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint32_t pingpong_status, unsigned long paddr)
{
@@ -1069,6 +1117,7 @@
.num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
+ .min_wm_ub = 64,
};
static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 2d083f9..e708d37 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -704,6 +704,9 @@
return -EIO;
}
+ /*re-init wait_complete */
+ INIT_COMPLETION(cmd_ack->wait_complete);
+
v4l2_event_queue(vdev, event);
if (timeout < 0) {
@@ -713,11 +716,9 @@
return rc;
}
- if (list_empty_careful(&cmd_ack->command_q.list)) {
/* should wait on session based condition */
rc = wait_for_completion_timeout(&cmd_ack->wait_complete,
msecs_to_jiffies(timeout));
- }
if (list_empty_careful(&cmd_ack->command_q.list)) {
if (!rc) {
@@ -731,8 +732,6 @@
}
}
- /*re-init wait_complete */
- INIT_COMPLETION(cmd_ack->wait_complete);
cmd = msm_dequeue(&cmd_ack->command_q,
struct msm_command, list);
if (!cmd) {
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 0fbaeca..6e9336a 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -20,6 +20,10 @@
int i;
struct msm_v4l2_format_data *data = q->drv_priv;
+ if (!data) {
+ pr_err("%s: drv_priv NULL\n", __func__);
+ return -EINVAL;
+ }
if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES))
return -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index d1ec5d8e..a33cf62 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -5,14 +5,11 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o
-obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
-obj-$(CONFIG_IMX135) += imx135.o
obj-$(CONFIG_IMX134) += imx134.o
obj-$(CONFIG_OV8825) += ov8825.o
obj-$(CONFIG_OV8865) += ov8865.o
obj-$(CONFIG_s5k4e1) += s5k4e1.o
obj-$(CONFIG_OV12830) += ov12830.o
-obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_OV9724) += ov9724.o
obj-$(CONFIG_HI256) += hi256.o
obj-$(CONFIG_OV5648) += ov5648.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index cb63d12..bf66442 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -181,7 +181,7 @@
uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
int32_t rc = 0;
uint32_t cmd = 0, delay = 0;
- uint8_t data[10];
+ uint8_t data[11];
uint16_t reg_addr = 0;
struct msm_camera_i2c_reg_setting *i2c_msg =
&c_ctrl->cfg.cci_i2c_write_cfg;
@@ -618,7 +618,7 @@
msm_cci_flush_queue(cci_dev, master);
goto ERROR;
} else {
- rc = 0;
+ rc = cci_dev->cci_master_info[master].status;
}
CDBG("%s:%d X wait_for_completion_interruptible\n", __func__,
__LINE__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 8662657..3596a12 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -95,7 +95,7 @@
static void msm_csid_reset(struct csid_device *csid_dev)
{
msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
- wait_for_completion_interruptible(&csid_dev->reset_complete);
+ wait_for_completion(&csid_dev->reset_complete);
return;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index d5b89b7..6f9aeec 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -69,7 +69,7 @@
rc = i2c_transfer(dev_client->client->adapter, msg, 1);
if (rc < 0)
S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr);
- return 0;
+ return rc;
}
int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 772ed0e..d8b90dd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -793,7 +793,6 @@
if (rc < 0) {
pr_err("%s:%d Invalid sensor position\n", __func__, __LINE__);
sensordata->sensor_info->position = INVALID_CAMERA_B;
- rc = 0;
}
rc = of_property_read_u32(of_node, "qcom,sensor-mode",
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index b3aad09..8a0dfc2 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -802,6 +802,26 @@
f->fmt.pix_mp.plane_fmt[0].reserved[0] =
(__u16)inst->prop.height[CAPTURE_PORT];
}
+
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ f->fmt.pix_mp.height =
+ inst->prop.height[CAPTURE_PORT];
+ f->fmt.pix_mp.width =
+ inst->prop.width[CAPTURE_PORT];
+ } else if (f->type ==
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ f->fmt.pix_mp.height =
+ inst->prop.height[OUTPUT_PORT];
+ f->fmt.pix_mp.width =
+ inst->prop.width[OUTPUT_PORT];
+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
+ (__u16)inst->prop.width[OUTPUT_PORT];
+ f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+ (__u16)inst->prop.height[OUTPUT_PORT];
+ }
+ }
} else {
dprintk(VIDC_ERR,
"Buf type not recognized, type = %d\n",
@@ -1171,70 +1191,6 @@
return rc;
}
-static int msm_vdec_queue_output_buffers(struct msm_vidc_inst *inst)
-{
- struct internal_buf *binfo;
- struct hfi_device *hdev;
- struct msm_smem *handle;
- struct vidc_frame_data frame_data = {0};
- struct hal_buffer_requirements *output_buf, *extradata_buf;
- int rc = 0;
-
- if (!inst || !inst->core || !inst->core->device) {
- dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- hdev = inst->core->device;
-
- output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
- if (!output_buf) {
- dprintk(VIDC_DBG,
- "This output buffer not required, buffer_type: %x\n",
- HAL_BUFFER_OUTPUT);
- return 0;
- }
- dprintk(VIDC_DBG,
- "output: num = %d, size = %d\n",
- output_buf->buffer_count_actual,
- output_buf->buffer_size);
-
- extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
- if (!extradata_buf) {
- dprintk(VIDC_DBG,
- "This extradata buffer not required, buffer_type: %x\n",
- HAL_BUFFER_EXTRADATA_OUTPUT);
- return 0;
- }
-
- hdev = inst->core->device;
-
- mutex_lock(&inst->lock);
- if (!list_empty(&inst->outputbufs)) {
- list_for_each_entry(binfo, &inst->outputbufs, list) {
- if (!binfo) {
- dprintk(VIDC_ERR, "Invalid parameter\n");
- mutex_unlock(&inst->lock);
- return -EINVAL;
- }
- handle = binfo->handle;
- frame_data.alloc_len = output_buf->buffer_size;
- frame_data.filled_len = 0;
- frame_data.offset = 0;
- frame_data.device_addr = handle->device_addr;
- frame_data.flags = 0;
- frame_data.extradata_addr = handle->device_addr +
- output_buf->buffer_size;
- frame_data.buffer_type = HAL_BUFFER_OUTPUT;
- rc = call_hfi_op(hdev, session_ftb,
- (void *) inst->session, &frame_data);
- binfo->buffer_ownership = FIRMWARE;
- }
- }
- mutex_unlock(&inst->lock);
- return 0;
-}
-
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -1285,7 +1241,7 @@
}
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
- rc = msm_vdec_queue_output_buffers(inst);
+ rc = msm_comm_queue_output_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to queue output buffers: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 96a13ab..d6cfbb3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -14,6 +14,7 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <asm/div64.h>
#include <mach/subsystem_restart.h>
@@ -587,10 +588,16 @@
} else {
dprintk(VIDC_DBG,
"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
- inst->prop.height[CAPTURE_PORT] = event_notify->height;
- inst->prop.width[CAPTURE_PORT] = event_notify->width;
- if (!msm_comm_get_stream_output_mode(inst) ==
+ if (msm_comm_get_stream_output_mode(inst) !=
HAL_VIDEO_DECODER_SECONDARY) {
+ dprintk(VIDC_DBG,
+ "event_notify->height = %d event_notify->width = %d\n",
+ event_notify->height,
+ event_notify->width);
+ inst->prop.height[CAPTURE_PORT] =
+ event_notify->height;
+ inst->prop.width[CAPTURE_PORT] =
+ event_notify->width;
inst->prop.height[OUTPUT_PORT] =
event_notify->height;
inst->prop.width[OUTPUT_PORT] =
@@ -711,8 +718,8 @@
return;
}
if (binfo->buffer_ownership != DRIVER) {
- dprintk(VIDC_ERR,
- "Failed : This buffer is with FW 0x%lx\n",
+ dprintk(VIDC_DBG,
+ "This buffer is with FW 0x%lx\n",
binfo->handle->device_addr);
return;
}
@@ -726,16 +733,71 @@
return;
}
+
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+ struct internal_buf *binfo;
+ struct hfi_device *hdev;
+ struct msm_smem *handle;
+ struct vidc_frame_data frame_data = {0};
+ struct hal_buffer_requirements *output_buf;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+ output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ if (!output_buf) {
+ dprintk(VIDC_DBG,
+ "This output buffer not required, buffer_type: %x\n",
+ HAL_BUFFER_OUTPUT);
+ return 0;
+ }
+ dprintk(VIDC_DBG,
+ "output: num = %d, size = %d\n",
+ output_buf->buffer_count_actual,
+ output_buf->buffer_size);
+
+ list_for_each_entry(binfo, &inst->outputbufs, list) {
+ if (binfo->buffer_ownership != DRIVER)
+ continue;
+ handle = binfo->handle;
+ frame_data.alloc_len = output_buf->buffer_size;
+ frame_data.filled_len = 0;
+ frame_data.offset = 0;
+ frame_data.device_addr = handle->device_addr;
+ frame_data.flags = 0;
+ frame_data.extradata_addr = handle->device_addr +
+ output_buf->buffer_size;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ rc = call_hfi_op(hdev, session_ftb,
+ (void *) inst->session, &frame_data);
+ binfo->buffer_ownership = FIRMWARE;
+ }
+ return 0;
+}
+
static void handle_session_flush(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
+ int rc;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
mutex_lock(&inst->lock);
validate_output_buffers(inst);
+ if (!inst->in_reconfig) {
+ rc = msm_comm_queue_output_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to queue output buffers: %d\n",
+ rc);
+ }
+ }
mutex_unlock(&inst->lock);
}
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
@@ -764,95 +826,131 @@
"Failed to get valid response for session error\n");
}
}
+
+struct sys_err_handler_data {
+ struct msm_vidc_core *core;
+ struct delayed_work work;
+};
+
+
+void hw_sys_error_handler(struct work_struct *work)
+{
+ struct msm_vidc_core *core = NULL;
+ struct hfi_device *hdev = NULL;
+ struct sys_err_handler_data *handler = NULL;
+ int rc = 0;
+
+ handler = container_of(work, struct sys_err_handler_data, work.work);
+ if (!handler || !handler->core || !handler->core->device) {
+ dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+ __func__);
+ goto exit;
+ }
+
+ core = handler->core;
+ hdev = core->device;
+
+ mutex_lock(&core->sync_lock);
+ /*
+ * Restart the firmware to bring out of bad state.
+ */
+ if ((core->state == VIDC_CORE_INVALID) &&
+ hdev->resurrect_fw) {
+ mutex_lock(&core->lock);
+ rc = call_hfi_op(hdev, resurrect_fw,
+ hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s - resurrect_fw failed: %d\n",
+ __func__, rc);
+ }
+ core->state = VIDC_CORE_LOADED;
+ mutex_unlock(&core->lock);
+ } else {
+ dprintk(VIDC_DBG,
+ "fw unloaded after sys error, no need to resurrect\n");
+ }
+ mutex_unlock(&core->sync_lock);
+
+exit:
+ /* free sys error handler, allocated in handle_sys_err */
+ kfree(handler);
+}
+
static void handle_sys_error(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
- struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
+ struct sys_err_handler_data *handler = NULL;
struct hfi_device *hdev = NULL;
+ struct msm_vidc_inst *inst = NULL;
int rc = 0;
subsystem_crashed("venus");
- if (response) {
- core = get_vidc_core(response->device_id);
- dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
- if (core) {
- mutex_lock(&core->lock);
- core->state = VIDC_CORE_INVALID;
- mutex_unlock(&core->lock);
- mutex_lock(&core->sync_lock);
- list_for_each_entry(inst, &core->instances,
- list) {
- mutex_lock(&inst->lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- if (inst->core)
- hdev = inst->core->device;
- if (hdev && inst->session) {
- dprintk(VIDC_DBG,
- "cleaning up inst: 0x%p", inst);
- rc = call_hfi_op(hdev, session_clean,
- (void *) inst->session);
- if (rc)
- dprintk(VIDC_ERR,
- "Sess clean failed :%p",
- inst);
- }
- inst->session = NULL;
- mutex_unlock(&inst->lock);
- msm_vidc_queue_v4l2_event(inst,
- V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- }
- mutex_unlock(&core->sync_lock);
- } else {
- dprintk(VIDC_ERR,
- "Got SYS_ERR but unable to identify core");
- }
- } else {
+ if (!response) {
dprintk(VIDC_ERR,
"Failed to get valid response for sys error\n");
- }
-}
-
-static void handle_sys_watchdog_timeout(enum command_response cmd, void *data)
-{
- struct msm_vidc_cb_cmd_done *response = data;
- struct msm_vidc_inst *inst;
- struct msm_vidc_core *core = NULL;
- struct hfi_device *hdev = NULL;
- int rc = 0;
- dprintk(VIDC_ERR, "Venus Subsystem crashed\n");
- core = get_vidc_core(response->device_id);
- if (!core) {
- dprintk(VIDC_ERR, "Wrong device_id received\n");
return;
}
- subsystem_crashed("venus");
+
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "Got SYS_ERR but unable to identify core\n");
+ return;
+ }
+
+ dprintk(VIDC_WARN, "SYS_ERROR %d received for core %p\n", cmd, core);
mutex_lock(&core->lock);
core->state = VIDC_CORE_INVALID;
mutex_unlock(&core->lock);
- mutex_lock(&core->sync_lock);
- list_for_each_entry(inst, &core->instances, list) {
- if (inst) {
- msm_vidc_queue_v4l2_event(inst,
- V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- mutex_lock(&inst->lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- if (inst->core)
- hdev = inst->core->device;
- if (hdev && inst->session) {
- rc = call_hfi_op(hdev, session_clean,
- (void *) inst->session);
- if (rc)
- dprintk(VIDC_ERR,
- "Sess clean failed :%p",
- inst);
- }
- inst->session = NULL;
- mutex_unlock(&inst->lock);
+ /*
+ * 1. Delete each instance session from hfi list
+ * 2. Notify all clients about hardware error.
+ */
+ mutex_lock(&core->sync_lock);
+ list_for_each_entry(inst, &core->instances,
+ list) {
+ mutex_lock(&inst->lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ if (inst->core)
+ hdev = inst->core->device;
+ if (hdev && inst->session) {
+ dprintk(VIDC_DBG,
+ "cleaning up inst: 0x%p\n", inst);
+ rc = call_hfi_op(hdev, session_clean,
+ (void *) inst->session);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Sess clean failed :%p\n",
+ inst);
}
+ inst->session = NULL;
+ mutex_unlock(&inst->lock);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
mutex_unlock(&core->sync_lock);
+
+
+ handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+ if (!handler) {
+ dprintk(VIDC_ERR,
+ "%s - failed to allocate sys error handler\n",
+ __func__);
+ return;
+ }
+ handler->core = core;
+ INIT_DELAYED_WORK(&handler->work, hw_sys_error_handler);
+
+ /*
+ * Sleep for 5 sec to ensure venus has completed any
+ * pending cache operations. Without this sleep, we see
+ * device reset when firmware is unloaded after a sys
+ * error.
+ */
+ schedule_delayed_work(&handler->work, msecs_to_jiffies(5000));
}
static void handle_session_close(enum command_response cmd, void *data)
@@ -1359,7 +1457,7 @@
handle_seq_hdr_done(cmd, data);
break;
case SYS_WATCHDOG_TIMEOUT:
- handle_sys_watchdog_timeout(cmd, data);
+ handle_sys_error(cmd, data);
break;
case SYS_ERROR:
handle_sys_error(cmd, data);
@@ -1539,11 +1637,14 @@
goto fail_scale_bus;
}
- rc = call_hfi_op(hdev, load_fw, hdev->hfi_device_data);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to load video firmware\n");
- goto fail_load_fw;
+ if (core->state < VIDC_CORE_LOADED) {
+ rc = call_hfi_op(hdev, load_fw, hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to load video firmware\n");
+ goto fail_load_fw;
+ }
}
+
rc = msm_comm_scale_clocks(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
@@ -1592,19 +1693,25 @@
core->id, core->state);
goto core_already_uninited;
}
+
msm_comm_scale_clocks_and_bus(inst);
if (list_empty(&core->instances)) {
- if (core->resources.has_ocmem) {
- if (inst->state != MSM_VIDC_CORE_INVALID)
- msm_comm_unset_ocmem(core);
- call_hfi_op(hdev, free_ocmem, hdev->hfi_device_data);
- }
- dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
- rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to release core, id = %d\n",
- core->id);
- goto exit;
+ if (core->state > VIDC_CORE_INIT) {
+ if (core->resources.has_ocmem) {
+ if (inst->state != MSM_VIDC_CORE_INVALID)
+ msm_comm_unset_ocmem(core);
+ call_hfi_op(hdev, free_ocmem,
+ hdev->hfi_device_data);
+ }
+ dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
+ rc = call_hfi_op(hdev, core_release,
+ hdev->hfi_device_data);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to release core, id = %d\n",
+ core->id);
+ goto exit;
+ }
}
mutex_lock(&core->lock);
core->state = VIDC_CORE_UNINIT;
@@ -1615,6 +1722,7 @@
else
msm_comm_unvote_buses(core, DDR_MEM);
}
+
core_already_uninited:
change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
exit:
@@ -3339,19 +3447,25 @@
capability->height.min);
rc = -ENOTSUPP;
}
- if (!rc) {
- rc = call_hfi_op(hdev, capability_check,
- inst->fmts[OUTPUT_PORT]->fourcc,
+ if (msm_vp8_low_tier &&
+ inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
+ capability->width.max = DEFAULT_WIDTH;
+ capability->width.max = DEFAULT_HEIGHT;
+ }
+ if (!rc && (inst->prop.width[CAPTURE_PORT] >
+ capability->width.max)) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %u supported max width = %u\n",
inst->prop.width[CAPTURE_PORT],
- &capability->width.max,
- &capability->height.max);
+ capability->width.max);
+ rc = -ENOTSUPP;
}
if (!rc && (inst->prop.height[CAPTURE_PORT]
* inst->prop.width[CAPTURE_PORT] >
capability->width.max * capability->height.max)) {
dprintk(VIDC_ERR,
- "Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
+ "Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)\n",
inst->prop.width[CAPTURE_PORT],
inst->prop.height[CAPTURE_PORT],
capability->width.max, capability->height.max);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 07dae8c..da71424 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -32,6 +32,7 @@
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 867b894..e9bf91d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -68,6 +68,7 @@
enum vidc_core_state {
VIDC_CORE_UNINIT = 0,
+ VIDC_CORE_LOADED,
VIDC_CORE_INIT,
VIDC_CORE_INIT_DONE,
VIDC_CORE_INVALID
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 2266fd4..f68a027 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -80,11 +80,28 @@
u32 spare; /*reserved for future, should be zero*/
};
+#define VENUS_SET_STATE(__device, __state) {\
+ mutex_lock(&(__device)->write_lock); \
+ mutex_lock(&(__device)->read_lock); \
+ (__device)->state = __state; \
+ mutex_unlock(&(__device)->write_lock); \
+ mutex_unlock(&(__device)->read_lock); }
+
+#define IS_VENUS_IN_VALID_STATE(__device) (\
+ (__device)->state != VENUS_STATE_DEINIT)
+
+static int venus_hfi_power_enable(void *dev);
static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device);
static int venus_hfi_power_enable(void *dev);
+static inline int venus_hfi_prepare_enable_clks(
+ struct venus_hfi_device *device);
+
+static inline void venus_hfi_disable_unprepare_clks(
+ struct venus_hfi_device *device);
+
static unsigned long venus_hfi_get_clock_rate(struct venus_core_clock *clock,
int num_mbs_per_sec);
@@ -477,7 +494,7 @@
}
base_addr = device->hal_data->register_base_addr;
- if (!device->clocks_enabled) {
+ if (device->clk_state != ENABLED_PREPARED) {
dprintk(VIDC_WARN,
"HFI Write register failed : Clocks are OFF\n");
return;
@@ -517,7 +534,7 @@
}
base_addr = device->hal_data->register_base_addr;
- if (!device->clocks_enabled) {
+ if (device->clk_state != ENABLED_PREPARED) {
dprintk(VIDC_WARN,
"HFI Read register failed : Clocks are OFF\n");
return -EINVAL;
@@ -1051,7 +1068,7 @@
}
WARN(!mutex_is_locked(&device->clk_pwr_lock),
"Clock/power lock must be acquired");
- if (device->clocks_enabled) {
+ if (device->clk_state == ENABLED_PREPARED) {
dprintk(VIDC_DBG, "Clocks already enabled");
return 0;
}
@@ -1066,7 +1083,7 @@
dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
}
}
- device->clocks_enabled = 1;
+ device->clk_state = ENABLED_PREPARED;
++device->clk_cnt;
return 0;
fail_clk_enable:
@@ -1075,6 +1092,7 @@
usleep(100);
clk_disable(cl->clk);
}
+ device->clk_state = DISABLED_PREPARED;
return rc;
}
@@ -1089,7 +1107,7 @@
}
WARN(!mutex_is_locked(&device->clk_pwr_lock),
"Clock/power lock must be acquired");
- if (!device->clocks_enabled) {
+ if (device->clk_state != ENABLED_PREPARED) {
dprintk(VIDC_DBG, "Clocks already disabled");
return;
}
@@ -1107,7 +1125,7 @@
usleep(100);
clk_disable(cl->clk);
}
- device->clocks_enabled = 0;
+ device->clk_state = DISABLED_PREPARED;
--device->clk_cnt;
}
@@ -1122,9 +1140,11 @@
dprintk(VIDC_ERR, "Invalid input: %p\n", device);
return -EINVAL;
}
+ mutex_lock(&device->clk_pwr_lock);
if (venus_hfi_clk_gating_off(device)) {
dprintk(VIDC_ERR, "Failed to turn off clk gating\n");
- return -EIO;
+ rc = -EIO;
+ goto err_clk_gating_off;
}
/* Halt AXI and AXI OCMEM VBIF Access */
reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
@@ -1139,6 +1159,8 @@
VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
if (rc)
dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+err_clk_gating_off:
+ mutex_unlock(&device->clk_pwr_lock);
return rc;
}
@@ -1166,7 +1188,7 @@
venus_hfi_clk_disable(device);
return rc;
}
- venus_hfi_clk_disable(device);
+ venus_hfi_disable_unprepare_clks(device);
venus_hfi_iommu_detach(device);
rc = regulator_disable(device->gdsc);
if (rc) {
@@ -1178,7 +1200,7 @@
else
venus_hfi_unvote_buses(device, DDR_MEM);
- device->power_enabled = 0;
+ device->power_enabled = false;
--device->pwr_cnt;
dprintk(VIDC_INFO, "entering power collapse\n");
already_disabled:
@@ -1214,7 +1236,11 @@
goto err_iommu_attach;
}
- rc = venus_hfi_clk_enable(device);
+ if (device->clk_state == DISABLED_UNPREPARED)
+ rc = venus_hfi_prepare_enable_clks(device);
+ else if (device->clk_state == DISABLED_PREPARED)
+ rc = venus_hfi_clk_enable(device);
+
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks");
goto err_enable_clk;
@@ -1266,7 +1292,7 @@
dprintk(VIDC_ERR, "Failed to allocate OCMEM");
goto err_alloc_ocmem;
}
- device->power_enabled = 1;
+ device->power_enabled = true;
++device->pwr_cnt;
dprintk(VIDC_INFO, "resuming from power collapse\n");
return rc;
@@ -1314,7 +1340,7 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return -EINVAL;
}
- if (device->clocks_enabled) {
+ if (device->clk_state == ENABLED_PREPARED) {
dprintk(VIDC_DBG, "Clocks are already enabled");
goto already_enabled;
}
@@ -1336,7 +1362,7 @@
VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
}
already_enabled:
- device->clocks_enabled = 1;
+ device->clk_state = ENABLED_PREPARED;
fail_clk_power_on:
return rc;
}
@@ -1387,11 +1413,24 @@
}
WARN(!mutex_is_locked(&device->write_lock),
"Cmd queue write lock must be acquired");
+ if (!IS_VENUS_IN_VALID_STATE(device)) {
+ dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+ result = -EINVAL;
+ goto err_q_null;
+ }
+
q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
if (!q_info) {
dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_null;
}
+
+ if (!q_info->q_array.align_virtual_addr) {
+ dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
+ result = -ENODATA;
+ goto err_q_null;
+ }
+
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
WARN(!mutex_is_locked(&device->clk_pwr_lock),
"Clock/power lock must be acquired");
@@ -1431,12 +1470,19 @@
return -EINVAL;
}
mutex_lock(&device->read_lock);
+ if (!IS_VENUS_IN_VALID_STATE(device)) {
+ dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+ rc = -EINVAL;
+ goto read_error_null;
+ }
+
if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
q_array.align_virtual_addr == 0) {
dprintk(VIDC_ERR, "cannot read from shared MSG Q's");
rc = -ENODATA;
goto read_error_null;
}
+
q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
mutex_lock(&device->clk_pwr_lock);
@@ -1475,6 +1521,11 @@
return -EINVAL;
}
mutex_lock(&device->read_lock);
+ if (!IS_VENUS_IN_VALID_STATE(device)) {
+ dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__);
+ rc = -EINVAL;
+ goto dbg_error_null;
+ }
if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
q_array.align_virtual_addr == 0) {
dprintk(VIDC_ERR, "cannot read from shared DBG Q's");
@@ -1560,15 +1611,19 @@
device->iface_queues[i].q_array.align_virtual_addr = NULL;
device->iface_queues[i].q_array.align_device_addr = NULL;
}
+ device->iface_q_table.mem_data = NULL;
device->iface_q_table.align_virtual_addr = NULL;
device->iface_q_table.align_device_addr = NULL;
+ device->qdss.mem_data = NULL;
device->qdss.align_virtual_addr = NULL;
device->qdss.align_device_addr = NULL;
+ device->sfr.mem_data = NULL;
device->sfr.align_virtual_addr = NULL;
device->sfr.align_device_addr = NULL;
+ device->mem_addr.mem_data = NULL;
device->mem_addr.align_virtual_addr = NULL;
device->mem_addr.align_device_addr = NULL;
@@ -1795,6 +1850,8 @@
return -ENODEV;
}
+ VENUS_SET_STATE(dev, VENUS_STATE_INIT);
+
dev->intr_status = 0;
INIT_LIST_HEAD(&dev->sess_head);
venus_hfi_set_registers(dev);
@@ -1847,6 +1904,7 @@
return rc;
err_core_init:
+ VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
disable_irq_nosync(dev->hal_data->irq);
return rc;
}
@@ -1861,6 +1919,7 @@
dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
+
if (dev->hal_client) {
mutex_lock(&dev->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
@@ -1877,6 +1936,8 @@
dev->intr_status = 0;
mutex_unlock(&dev->clk_pwr_lock);
}
+ VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
+
dprintk(VIDC_INFO, "HAL exited\n");
return 0;
}
@@ -1917,7 +1978,7 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
- if (!device->clocks_enabled) {
+ if (device->clk_state != ENABLED_PREPARED) {
dprintk(VIDC_DBG, "Clocks are already disabled");
goto already_disabled;
}
@@ -1934,7 +1995,7 @@
msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
dprintk(VIDC_DBG, "PM work already scheduled\n");
already_disabled:
- device->clocks_enabled = 0;
+ device->clk_state = DISABLED_PREPARED;
}
static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
@@ -2735,10 +2796,10 @@
struct venus_hfi_device *device = list_first_entry(
&hal_ctxt.dev_head, struct venus_hfi_device, list);
mutex_lock(&device->clk_pwr_lock);
- if (device->clocks_enabled || !device->power_enabled) {
+ if (device->clk_state == ENABLED_PREPARED || !device->power_enabled) {
dprintk(VIDC_DBG,
"Clocks status: %d, Power status: %d, ignore power off\n",
- device->clocks_enabled, device->power_enabled);
+ device->clk_state, device->power_enabled);
goto clks_enabled;
}
mutex_unlock(&device->clk_pwr_lock);
@@ -2759,7 +2820,7 @@
}
mutex_lock(&device->clk_pwr_lock);
- if (device->clocks_enabled) {
+ if (device->clk_state == ENABLED_PREPARED) {
dprintk(VIDC_ERR,
"Clocks are still enabled after PC_PREP_DONE, ignore power off");
goto clks_enabled;
@@ -3045,7 +3106,9 @@
clk_put(device->resources.clock[i].clk);
}
}
-static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
+
+static inline void venus_hfi_disable_unprepare_clks(
+ struct venus_hfi_device *device)
{
int i;
struct venus_core_clock *cl;
@@ -3053,8 +3116,9 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
- mutex_lock(&device->clk_pwr_lock);
- if (device->clocks_enabled) {
+
+ WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
+ if (device->clk_state == ENABLED_PREPARED) {
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
continue;
@@ -3076,11 +3140,11 @@
cl = &device->resources.clock[i];
clk_unprepare(cl->clk);
}
- device->clocks_enabled = 0;
+ device->clk_state = DISABLED_UNPREPARED;
--device->clk_cnt;
- mutex_unlock(&device->clk_pwr_lock);
}
-static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
+
+static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device)
{
int i = 0;
struct venus_core_clock *cl;
@@ -3089,7 +3153,12 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return -EINVAL;
}
- mutex_lock(&device->clk_pwr_lock);
+ WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
+
+ if (device->clk_state == ENABLED_PREPARED) {
+ dprintk(VIDC_DBG, "Clocks already prepared and enabled\n");
+ return 0;
+ }
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
continue;
@@ -3102,9 +3171,8 @@
dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
}
}
- device->clocks_enabled = 1;
+ device->clk_state = ENABLED_PREPARED;
++device->clk_cnt;
- mutex_unlock(&device->clk_pwr_lock);
return rc;
fail_clk_enable:
for (; i >= 0; i--) {
@@ -3112,9 +3180,10 @@
usleep(100);
clk_disable_unprepare(cl->clk);
}
- mutex_unlock(&device->clk_pwr_lock);
+ device->clk_state = DISABLED_UNPREPARED;
return rc;
}
+
static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
struct msm_vidc_platform_resources *res)
{
@@ -3473,17 +3542,16 @@
mutex_unlock(&device->clk_pwr_lock);
goto fail_load_fw;
}
- device->power_enabled = 1;
+ device->power_enabled = true;
++device->pwr_cnt;
- mutex_unlock(&device->clk_pwr_lock);
/*Clocks can be enabled only after pil_get since
* gdsc is turned-on in pil_get*/
- rc = venus_hfi_enable_clks(device);
+ rc = venus_hfi_prepare_enable_clks(device);
+ mutex_unlock(&device->clk_pwr_lock);
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
goto fail_enable_clks;
}
-
rc = protect_cp_mem(device);
if (rc) {
dprintk(VIDC_ERR, "Failed to protect memory\n");
@@ -3492,14 +3560,16 @@
return rc;
fail_protect_mem:
- venus_hfi_disable_clks(device);
+ mutex_lock(&device->clk_pwr_lock);
+ venus_hfi_disable_unprepare_clks(device);
+ mutex_unlock(&device->clk_pwr_lock);
fail_enable_clks:
subsystem_put(device->resources.fw.cookie);
fail_load_fw:
mutex_lock(&device->clk_pwr_lock);
device->resources.fw.cookie = NULL;
regulator_disable(device->gdsc);
- device->power_enabled = 0;
+ device->power_enabled = false;
--device->pwr_cnt;
mutex_unlock(&device->clk_pwr_lock);
fail_enable_gdsc:
@@ -3528,16 +3598,60 @@
*/
if(venus_hfi_halt_axi(device))
dprintk(VIDC_WARN, "Failed to halt AXI\n");
- venus_hfi_disable_clks(device);
mutex_lock(&device->clk_pwr_lock);
+ venus_hfi_disable_unprepare_clks(device);
regulator_disable(device->gdsc);
- device->power_enabled = 0;
+ device->power_enabled = false;
--device->pwr_cnt;
mutex_unlock(&device->clk_pwr_lock);
device->resources.fw.cookie = NULL;
}
}
+static int venus_hfi_resurrect_fw(void *dev)
+{
+ struct venus_hfi_device *device = dev;
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ rc = venus_hfi_free_ocmem(device);
+ if (rc)
+ dprintk(VIDC_WARN, "%s - failed to free ocmem\n", __func__);
+
+ rc = venus_hfi_core_release(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to release venus core rc = %d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ dprintk(VIDC_ERR, "praying for firmware resurrection\n");
+
+ venus_hfi_unload_fw(device);
+
+ rc = venus_hfi_scale_buses(device, DDR_MEM);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale buses");
+ goto exit;
+ }
+
+ rc = venus_hfi_load_fw(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s - failed to load venus fw rc = %d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ dprintk(VIDC_ERR, "Hurray!! firmware has restarted\n");
+exit:
+ return rc;
+}
+
static int venus_hfi_get_fw_info(void *dev, enum fw_info info)
{
int rc = 0;
@@ -3588,7 +3702,10 @@
rc = device->clk_cnt;
break;
case DEV_CLOCK_ENABLED:
- rc = device->clocks_enabled;
+ if (device->clk_state == ENABLED_PREPARED)
+ rc = 1;
+ else
+ rc = 0;
break;
case DEV_PWR_COUNT:
rc = device->pwr_cnt;
@@ -3654,28 +3771,6 @@
return rc;
}
-int venus_hfi_capability_check(u32 fourcc, u32 width,
- u32 *max_width, u32 *max_height)
-{
- int rc = 0;
- if (!max_width || !max_height) {
- dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
- return -EINVAL;
- }
-
- if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
- *max_width = DEFAULT_WIDTH;
- *max_height = DEFAULT_HEIGHT;
- }
- if (width > *max_width) {
- dprintk(VIDC_ERR,
- "Unsupported width = %u supported max width = %u",
- width, *max_width);
- rc = -ENOTSUPP;
- }
- return rc;
-}
-
static void *venus_hfi_add_device(u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
@@ -3703,9 +3798,9 @@
hdevice->device_id = device_id;
hdevice->callback = callback;
- hdevice->clocks_enabled = 0;
+ hdevice->clk_state = DISABLED_UNPREPARED;
hdevice->clk_cnt = 0;
- hdevice->power_enabled = 0;
+ hdevice->power_enabled = false;
hdevice->pwr_cnt = 0;
hdevice->vidc_workq = create_singlethread_workqueue(
@@ -3833,10 +3928,10 @@
hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
+ hdev->resurrect_fw = venus_hfi_resurrect_fw;
hdev->get_fw_info = venus_hfi_get_fw_info;
hdev->get_info = venus_hfi_get_info;
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
- hdev->capability_check = venus_hfi_capability_check;
hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
hdev->power_enable = venus_hfi_power_enable;
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index d816df0..23a51ba 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -124,6 +124,12 @@
BUS_IDX_MAX
};
+enum clock_state {
+ DISABLED_UNPREPARED,
+ ENABLED_PREPARED,
+ DISABLED_PREPARED
+};
+
struct vidc_mem_addr {
u8 *align_device_addr;
u8 *align_virtual_addr;
@@ -177,6 +183,11 @@
struct on_chip_mem ocmem;
};
+enum venus_hfi_state {
+ VENUS_STATE_DEINIT = 1,
+ VENUS_STATE_INIT,
+};
+
struct venus_hfi_device {
struct list_head list;
struct list_head sess_head;
@@ -185,8 +196,8 @@
u32 clk_load;
u32 bus_load[MSM_VIDC_MAX_DEVICES];
unsigned long ocmem_size;
- u32 clocks_enabled;
- u32 power_enabled;
+ enum clock_state clk_state;
+ bool power_enabled;
enum vidc_clocks clk_gating_level;
struct mutex read_lock;
struct mutex write_lock;
@@ -213,6 +224,7 @@
struct venus_resources resources;
struct msm_vidc_platform_resources *res;
struct regulator *gdsc;
+ enum venus_hfi_state state;
};
void venus_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 614c78f..f0c57f1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1164,12 +1164,11 @@
int *domain_num, int *partition_num);
int (*load_fw)(void *dev);
void (*unload_fw)(void *dev);
+ int (*resurrect_fw)(void *dev);
int (*get_fw_info)(void *dev, enum fw_info info);
int (*get_info) (void *dev, enum dev_info info);
int (*get_stride_scanline)(int color_fmt, int width,
int height, int *stride, int *scanlines);
- int (*capability_check)(u32 fourcc, u32 width,
- u32 *max_width, u32 *max_height);
int (*session_clean)(void *sess);
int (*get_core_capabilities)(void);
int (*power_enable)(void *dev);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c24f8fb..23edc8a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -157,6 +157,7 @@
uint32_t qsee_version;
struct device *pdev;
bool commonlib_loaded;
+ struct ion_handle *cmnlib_ion_handle;
struct ce_hw_usage_info ce_info;
int qsee_bw_count;
@@ -311,7 +312,11 @@
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
-
+ if (ret) {
+ pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+ ret);
+ return ret;
+ }
/* Populate the structure for sending scm call to load image */
svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
svc->sb_phys = pa;
@@ -636,7 +641,8 @@
mutex_lock(&qsee_bw_mutex);
qseecom.bw_scale_down_timer.expires = jiffies +
msecs_to_jiffies(duration);
- add_timer(&(qseecom.bw_scale_down_timer));
+ mod_timer(&(qseecom.bw_scale_down_timer),
+ qseecom.bw_scale_down_timer.expires);
qseecom.timer_running = true;
mutex_unlock(&qsee_bw_mutex);
}
@@ -697,6 +703,12 @@
}
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+ if (ret) {
+
+ pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+ ret);
+ return ret;
+ }
/* Populate the structure for sending scm call to load image */
data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
data->client.ihandle);
@@ -869,19 +881,27 @@
pr_err("copy_from_user failed\n");
return -EFAULT;
}
+
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+ mutex_unlock(&qsee_bw_mutex);
+ if (ret)
+ return ret;
+ }
+
/* Vote for the SFPB clock */
ret = __qseecom_enable_clk_scale_up(data);
if (ret)
- return ret;
+ goto enable_clk_err;
+
req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
- if (ret < 0) {
- __qseecom_disable_clk_scale_down(data);
- return ret;
- }
+ if (ret < 0)
+ goto loadapp_err;
app_id = ret;
if (app_id) {
@@ -905,12 +925,17 @@
load_img_req.ifd_data_fd);
if (IS_ERR_OR_NULL(ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
- __qseecom_disable_clk_scale_down(data);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto loadapp_err;
}
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+ if (ret) {
+ pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+ ret);
+ goto loadapp_err;
+ }
/* Populate the structure for sending scm call to load image */
memcpy(load_req.app_name, load_img_req.img_name,
@@ -930,16 +955,16 @@
pr_err("scm_call to load app failed\n");
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- __qseecom_disable_clk_scale_down(data);
- return -EINVAL;
+ ret = -EINVAL;
+ goto loadapp_err;
}
if (resp.result == QSEOS_RESULT_FAILURE) {
pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- __qseecom_disable_clk_scale_down(data);
- return -EFAULT;
+ ret = -EFAULT;
+ goto loadapp_err;
}
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -949,8 +974,8 @@
ret);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- __qseecom_disable_clk_scale_down(data);
- return ret;
+ ret = -EFAULT;
+ goto loadapp_err;
}
}
@@ -959,8 +984,8 @@
resp.result);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- __qseecom_disable_clk_scale_down(data);
- return -EFAULT;
+ ret = -EFAULT;
+ goto loadapp_err;
}
app_id = resp.data;
@@ -968,8 +993,8 @@
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
pr_err("kmalloc failed\n");
- __qseecom_disable_clk_scale_down(data);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto loadapp_err;
}
entry->app_id = app_id;
entry->ref_cnt = 1;
@@ -991,11 +1016,18 @@
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
pr_err("copy_to_user failed\n");
kzfree(entry);
- __qseecom_disable_clk_scale_down(data);
- return -EFAULT;
+ ret = -EFAULT;
}
+
+loadapp_err:
__qseecom_disable_clk_scale_down(data);
- return 0;
+enable_clk_err:
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ return ret;
}
static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
@@ -1760,10 +1792,22 @@
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
+
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+ mutex_unlock(&qsee_bw_mutex);
+ if (ret) {
+ kzfree(img_data);
+ return ret;
+ }
+ }
+
ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
kzfree(img_data);
- return -EIO;
+ ret = -EIO;
+ goto loadfw_err;
}
__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1774,8 +1818,8 @@
kzfree(img_data);
if (ret) {
pr_err("scm_call to load failed : ret %d\n", ret);
- __qseecom_disable_clk_scale_down(data);
- return -EIO;
+ ret = -EIO;
+ goto loadfw_err;
}
switch (resp.result) {
@@ -1797,39 +1841,76 @@
ret = -EINVAL;
break;
}
- __qseecom_disable_clk_scale_down(data);
+loadfw_err:
+ __qseecom_disable_clk_scale_down(data);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
+ }
return ret;
}
static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
{
- int32_t ret = 0;
+ int ret = 0;
+ int len = 0;
uint32_t fw_size = 0;
struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
struct qseecom_command_scm_resp resp;
u8 *img_data = NULL;
+ ion_phys_addr_t pa;
if (__qseecom_get_fw_size("cmnlib", &fw_size))
return -EIO;
- img_data = kzalloc(fw_size, GFP_KERNEL);
- if (!img_data) {
- pr_err("Mem allocation for lib image data failed\n");
+ qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
+ SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
+ pr_err("ION alloc failed\n");
return -ENOMEM;
}
+
+ img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
+ qseecom.cmnlib_ion_handle);
+ if (IS_ERR_OR_NULL(img_data)) {
+ pr_err("ION memory mapping for cmnlib failed\n");
+ ret = -ENOMEM;
+ goto exit_ion_free;
+ }
ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
if (ret) {
- kzfree(img_data);
- return -EIO;
+ ret = -EIO;
+ goto exit_ion_unmap_kernel;
+ }
+ /* Get the physical address of the ION BUF */
+ ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
+ &pa, &len);
+ load_req.phy_addr = (s32)pa;
+ if (ret) {
+ pr_err("physical memory retrieval failure\n");
+ ret = -EIO;
+ goto exit_ion_unmap_kernel;
}
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
+
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+ mutex_unlock(&qsee_bw_mutex);
+ if (ret) {
+ ret = -EIO;
+ goto exit_ion_unmap_kernel;
+ }
+ }
+
/* Vote for the SFPB clock */
ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
- kzfree(img_data);
- return -EIO;
+ ret = -EIO;
+ goto exit_unregister_bus_bw_need;
}
__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1840,30 +1921,52 @@
if (ret) {
pr_err("scm_call to load failed : ret %d\n", ret);
ret = -EIO;
- } else {
- switch (resp.result) {
- case QSEOS_RESULT_SUCCESS:
- break;
- case QSEOS_RESULT_FAILURE:
- pr_err("scm call failed w/response result%d\n",
- resp.result);
- ret = -EINVAL;
- break;
- case QSEOS_RESULT_INCOMPLETE:
- ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret)
- pr_err("process_incomplete_cmd failed err: %d\n",
- ret);
- break;
- default:
- pr_err("scm call return unknown response %d\n",
- resp.result);
- ret = -EINVAL;
- break;
- }
+ goto exit_disable_clk_vote;
}
- kzfree(img_data);
+
+ switch (resp.result) {
+ case QSEOS_RESULT_SUCCESS:
+ break;
+ case QSEOS_RESULT_FAILURE:
+ pr_err("scm call failed w/response result%d\n", resp.result);
+ ret = -EINVAL;
+ goto exit_disable_clk_vote;
+ case QSEOS_RESULT_INCOMPLETE:
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd failed err: %d\n", ret);
+ goto exit_disable_clk_vote;
+ }
+ break;
+ default:
+ pr_err("scm call return unknown response %d\n", resp.result);
+ ret = -EINVAL;
+ goto exit_disable_clk_vote;
+ }
__qseecom_disable_clk_scale_down(data);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ return ret;
+
+exit_disable_clk_vote:
+ __qseecom_disable_clk_scale_down(data);
+
+exit_unregister_bus_bw_need:
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+
+exit_ion_unmap_kernel:
+ ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+
+exit_ion_free:
+ ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+ qseecom.cmnlib_ion_handle = NULL;
return ret;
}
@@ -1896,6 +1999,11 @@
break;
}
}
+
+ ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+ ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
+ qseecom.cmnlib_ion_handle = NULL;
+
return ret;
}
@@ -2011,6 +2119,12 @@
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+ if (ret) {
+ pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+ ret);
+ goto err;
+ }
+
/* Populate the structure for sending scm call to load image */
data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
data->client.ihandle);
@@ -2178,6 +2292,10 @@
if (!qseecom.support_bus_scaling) {
qsee_disable_clock_vote(handle->dev, CLK_DFAB);
qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+ } else {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(handle->dev);
+ mutex_unlock(&qsee_bw_mutex);
}
}
return ret;
@@ -2525,7 +2643,11 @@
/* Get the physical address of the ION BUF */
ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
-
+ if (ret) {
+ pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
+ ret);
+ return ret;
+ }
/* Populate the structure for sending scm call to load image */
load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
load_req.mdt_len = load_img_req.mdt_len;
@@ -2542,11 +2664,21 @@
goto exit_ion_free;
}
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
+ mutex_unlock(&qsee_bw_mutex);
+ if (ret) {
+ ret = -EIO;
+ goto exit_cpu_restore;
+ }
+ }
+
/* Vote for the SFPB clock */
ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
ret = -EIO;
- goto exit_cpu_restore;
+ goto exit_register_bus_bandwidth_needs;
}
msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
@@ -2583,6 +2715,14 @@
exit_disable_clock:
__qseecom_disable_clk_scale_down(data);
+
+exit_register_bus_bandwidth_needs:
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+
exit_cpu_restore:
/* Restore the CPU mask */
mask = CPU_MASK_ALL;
@@ -3268,6 +3408,13 @@
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
if (qseecom.support_bus_scaling) {
+ /* register bus bw in case the client doesn't do it */
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
if (ret) {
pr_err("Failed to set bw.\n");
@@ -3300,6 +3447,12 @@
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
if (qseecom.support_bus_scaling) {
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
if (ret) {
pr_err("Failed to set bw.\n");
@@ -3472,6 +3625,10 @@
if (!qseecom.support_bus_scaling) {
qsee_disable_clock_vote(data, CLK_DFAB);
qsee_disable_clock_vote(data, CLK_SFPB);
+ } else {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom_unregister_bus_bandwidth_needs(data);
+ mutex_unlock(&qsee_bw_mutex);
}
atomic_dec(&data->ioctl_count);
break;
@@ -4203,13 +4360,19 @@
struct qseecom_clk *qclk;
qclk = &qseecom.qsee;
- if (qseecom.cumulative_mode != INACTIVE) {
+ mutex_lock(&qsee_bw_mutex);
+ mutex_lock(&clk_access_lock);
+
+ if (qseecom.cumulative_mode != INACTIVE &&
+ qseecom.current_mode != INACTIVE) {
ret = msm_bus_scale_client_update_request(
qseecom.qsee_perf_client, INACTIVE);
if (ret)
pr_err("Fail to scale down bus\n");
+ else
+ qseecom.current_mode = INACTIVE;
}
- mutex_lock(&clk_access_lock);
+
if (qclk->clk_access_cnt) {
if (qclk->ce_clk != NULL)
clk_disable_unprepare(qclk->ce_clk);
@@ -4217,12 +4380,14 @@
clk_disable_unprepare(qclk->ce_core_clk);
if (qclk->ce_bus_clk != NULL)
clk_disable_unprepare(qclk->ce_bus_clk);
- if (qseecom.timer_running) {
- del_timer_sync(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = false;
- }
}
+
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = false;
+
mutex_unlock(&clk_access_lock);
+ mutex_unlock(&qsee_bw_mutex);
+
return 0;
}
@@ -4233,6 +4398,8 @@
struct qseecom_clk *qclk;
qclk = &qseecom.qsee;
+ mutex_lock(&qsee_bw_mutex);
+ mutex_lock(&clk_access_lock);
if (qseecom.cumulative_mode >= HIGH)
mode = HIGH;
else
@@ -4243,9 +4410,10 @@
qseecom.qsee_perf_client, mode);
if (ret)
pr_err("Fail to scale up bus to %d\n", mode);
+ else
+ qseecom.current_mode = mode;
}
- mutex_lock(&clk_access_lock);
if (qclk->clk_access_cnt) {
ret = clk_prepare_enable(qclk->ce_core_clk);
@@ -4268,13 +4436,20 @@
qclk->clk_access_cnt = 0;
goto ce_bus_clk_err;
}
+ }
+
+ if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
qseecom.bw_scale_down_timer.expires = jiffies +
msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
+ mod_timer(&(qseecom.bw_scale_down_timer),
+ qseecom.bw_scale_down_timer.expires);
qseecom.timer_running = true;
-
}
+
mutex_unlock(&clk_access_lock);
+ mutex_unlock(&qsee_bw_mutex);
+
+
return 0;
ce_bus_clk_err:
@@ -4283,6 +4458,7 @@
clk_disable_unprepare(qclk->ce_core_clk);
err:
mutex_unlock(&clk_access_lock);
+ mutex_unlock(&qsee_bw_mutex);
return -EIO;
}
static struct of_device_id qseecom_match[] = {
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9d07631..0c70746 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2524,8 +2524,20 @@
break;
case MMC_BLK_CMD_ERR:
ret = mmc_blk_cmd_err(md, card, brq, req, ret);
- if (!mmc_blk_reset(md, card->host, type))
+ if (!mmc_blk_reset(md, card->host, type)) {
+ if (!ret) {
+ /*
+ * We have successfully completed block
+ * request and notified to upper layers.
+ * As the reset is successful, assume
+ * h/w is in clean state and proceed
+ * with new request.
+ */
+ BUG_ON(card->host->areq);
+ goto start_new_req;
+ }
break;
+ }
goto cmd_abort;
case MMC_BLK_RETRY:
if (retry++ < 5)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1feb26b..dbc7d5c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -169,9 +169,35 @@
#endif /* CONFIG_FAIL_MMC_REQUEST */
+static inline void
+mmc_clk_scaling_update_state(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (mrq) {
+ switch (mrq->cmd->opcode) {
+ case MMC_READ_SINGLE_BLOCK:
+ case MMC_READ_MULTIPLE_BLOCK:
+ case MMC_WRITE_BLOCK:
+ case MMC_WRITE_MULTIPLE_BLOCK:
+ host->clk_scaling.invalid_state = false;
+ break;
+ default:
+ host->clk_scaling.invalid_state = true;
+ break;
+ }
+ } else {
+ /*
+ * force clock scaling transitions,
+ * if other conditions are met
+ */
+ host->clk_scaling.invalid_state = false;
+ }
+
+ return;
+}
+
static inline void mmc_update_clk_scaling(struct mmc_host *host)
{
- if (host->clk_scaling.enable) {
+ if (host->clk_scaling.enable && !host->clk_scaling.invalid_state) {
host->clk_scaling.busy_time_us +=
ktime_to_us(ktime_sub(ktime_get(),
host->clk_scaling.start_busy));
@@ -333,8 +359,11 @@
* frequency will be done after current thread
* releases host.
*/
- mmc_clk_scaling(host, false);
- host->clk_scaling.start_busy = ktime_get();
+ mmc_clk_scaling_update_state(host, mrq);
+ if (!host->clk_scaling.invalid_state) {
+ mmc_clk_scaling(host, false);
+ host->clk_scaling.start_busy = ktime_get();
+ }
}
host->ops->request(host, mrq);
@@ -2826,7 +2855,8 @@
* this mode.
*/
if (!card || (mmc_card_mmc(card) &&
- card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB))
+ card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ || host->clk_scaling.invalid_state)
goto out;
if (mmc_send_status(card, &status)) {
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9b41807..074b6a8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2854,7 +2854,7 @@
* max. 1ms for reset completion.
*/
ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
- pwr, !(pwr & CORE_SW_RST), 100, 10);
+ pwr, !(pwr & CORE_SW_RST), 10, 1000);
if (ret) {
dev_err(&pdev->dev, "reset failed (%d)\n", ret);
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 462bd3b..1a3baf5 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1150,6 +1150,7 @@
return rc;
}
+ boot_reason = ffs(pon_sts);
index = ffs(pon_sts) - 1;
cold_boot = !qpnp_pon_is_warm_reset();
if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0)
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index 1e13ce1..b621547 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -49,6 +49,7 @@
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
static int alarm_opened;
+static DEFINE_MUTEX(alarm_mutex);
static DEFINE_SPINLOCK(alarm_slock);
static struct wake_lock alarm_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
@@ -89,6 +90,7 @@
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_CLEAR(0):
+ mutex_lock(&alarm_mutex);
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d clear\n", alarm_type);
alarm_try_to_cancel(&alarms[alarm_type]);
@@ -98,11 +100,12 @@
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
+ spin_unlock_irqrestore(&alarm_slock, flags);
if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
if (!copy_from_user(&new_alarm_time,
(void __user *)arg, sizeof(new_alarm_time)))
set_power_on_alarm(new_alarm_time.tv_sec, 0);
- spin_unlock_irqrestore(&alarm_slock, flags);
+ mutex_unlock(&alarm_mutex);
break;
case ANDROID_ALARM_SET_OLD:
@@ -122,6 +125,7 @@
goto err1;
}
from_old_alarm_set:
+ mutex_lock(&alarm_mutex);
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
@@ -129,11 +133,12 @@
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
+ spin_unlock_irqrestore(&alarm_slock, flags);
if ((alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP) &&
(ANDROID_ALARM_BASE_CMD(cmd) ==
ANDROID_ALARM_SET(0)))
set_power_on_alarm(new_alarm_time.tv_sec, 1);
- spin_unlock_irqrestore(&alarm_slock, flags);
+ mutex_unlock(&alarm_mutex);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
break;
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 2cf1158..8531de9 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -65,15 +65,18 @@
static struct rtc_device *alarm_rtc_dev;
static DEFINE_SPINLOCK(alarm_slock);
static DEFINE_MUTEX(alarm_setrtc_mutex);
+static DEFINE_MUTEX(power_on_alarm_mutex);
static struct wake_lock alarm_rtc_wake_lock;
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
static long power_on_alarm;
-static void alarm_shutdown(struct platform_device *dev);
+static int set_alarm_time_to_rtc(const long);
+
void set_power_on_alarm(long secs, bool enable)
{
+ mutex_lock(&power_on_alarm_mutex);
if (enable) {
power_on_alarm = secs;
} else {
@@ -85,7 +88,9 @@
else
power_on_alarm = 0;
}
- alarm_shutdown(NULL);
+
+ set_alarm_time_to_rtc(power_on_alarm);
+ mutex_unlock(&power_on_alarm_mutex);
}
@@ -521,28 +526,23 @@
return 0;
}
-static void alarm_shutdown(struct platform_device *dev)
+static int set_alarm_time_to_rtc(const long power_on_time)
{
struct timespec wall_time;
struct rtc_time rtc_time;
struct rtc_wkalrm alarm;
- unsigned long flags;
long rtc_secs, alarm_delta, alarm_time;
- int rc;
+ int rc = -EINVAL;
- spin_lock_irqsave(&alarm_slock, flags);
-
- if (!power_on_alarm) {
- spin_unlock_irqrestore(&alarm_slock, flags);
+ if (power_on_time <= 0) {
goto disable_alarm;
}
- spin_unlock_irqrestore(&alarm_slock, flags);
rtc_read_time(alarm_rtc_dev, &rtc_time);
getnstimeofday(&wall_time);
rtc_tm_to_time(&rtc_time, &rtc_secs);
alarm_delta = wall_time.tv_sec - rtc_secs;
- alarm_time = power_on_alarm - alarm_delta;
+ alarm_time = power_on_time - alarm_delta;
/*
* Substract ALARM_DELTA from actual alarm time
@@ -558,16 +558,19 @@
rtc_time_to_tm(alarm_time, &alarm.time);
alarm.enabled = 1;
rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
- if (rc)
+ if (rc){
pr_alarm(ERROR, "Unable to set power-on alarm\n");
+ goto disable_alarm;
+ }
else
pr_alarm(FLOW, "Power-on alarm set to %lu\n",
alarm_time);
- return;
+ return 0;
disable_alarm:
rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+ return rc;
}
static struct rtc_task alarm_rtc_task = {
@@ -629,7 +632,6 @@
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
- .shutdown = alarm_shutdown,
.driver = {
.name = "alarm"
}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 1247808..0035349 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -82,7 +82,7 @@
};
static int ngd_slim_runtime_resume(struct device *device);
-static int ngd_slim_power_up(struct msm_slim_ctrl *dev);
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart);
static irqreturn_t ngd_slim_interrupt(int irq, void *d)
{
@@ -97,7 +97,7 @@
writel_relaxed(stat, ngd + NGD_INT_CLR);
dev->err = -EIO;
- dev_err(dev->dev, "NGD interrupt error:0x%x, err:%d", stat,
+ SLIM_WARN(dev, "NGD interrupt error:0x%x, err:%d\n", stat,
dev->err);
/* Guarantee that error interrupts are cleared */
mb();
@@ -119,7 +119,7 @@
for (i = 1; i < ((len + 3) >> 2); i++) {
rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
(4 * i));
- dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
+ SLIM_DBG(dev, "REG-RX data: %x\n", rx_buf[i]);
}
msm_slim_rx_enqueue(dev, rx_buf, len);
writel_relaxed(NGD_INT_RX_MSG_RCVD,
@@ -130,8 +130,7 @@
*/
mb();
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
- dev_err(dev->dev,
- "direct message received even with RX MSGQs");
+ SLIM_WARN(dev, "direct msg rcvd with RX MSGQs\n");
else
complete(&dev->rx_msgq_notify);
}
@@ -140,13 +139,13 @@
/* Guarantee RECONFIG DONE interrupt is cleared */
mb();
/* In satellite mode, just log the reconfig done IRQ */
- dev_dbg(dev->dev, "reconfig done IRQ for NGD");
+ SLIM_DBG(dev, "reconfig done IRQ for NGD\n");
}
if (stat & NGD_INT_IE_VE_CHG) {
writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
/* Guarantee IE VE change interrupt is cleared */
mb();
- dev_err(dev->dev, "NGD IE VE change");
+ SLIM_DBG(dev, "NGD IE VE change\n");
}
pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
@@ -161,7 +160,7 @@
struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
struct msm_slim_ctrl *dev =
container_of(qmi, struct msm_slim_ctrl, qmi);
- pr_info("Slimbus QMI NGD CB received event:%ld", code);
+ SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code);
switch (code) {
case QMI_SERVER_ARRIVE:
schedule_work(&qmi->ssr_up);
@@ -183,32 +182,54 @@
static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
void *_cmd)
{
+ void __iomem *ngd;
struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
mdm);
- int ret;
+ struct slim_controller *ctrl = &dev->ctrl;
+ u32 laddr;
+ struct slim_device *sbdev;
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
- /* make sure runtime-pm doesn't suspend during modem SSR */
- pm_runtime_get_noresume(dev->dev);
+ SLIM_INFO(dev, "SLIM %lu external_modem SSR notify cb\n", code);
+ /* vote for runtime-pm so that ADSP doesn't go down */
+ msm_slim_get_ctrl(dev);
+ /*
+ * checking framer here will wake-up ADSP and may avoid framer
+ * handover later
+ */
+ msm_slim_qmi_check_framer_request(dev);
+ dev->mdm.state = MSM_CTRL_DOWN;
+ msm_slim_put_ctrl(dev);
break;
case SUBSYS_AFTER_POWERUP:
- ret = msm_slim_qmi_check_framer_request(dev);
- dev_err(dev->dev,
- "%s:SLIM %lu external_modem SSR notify cb, ret %d",
- __func__, code, ret);
- /*
- * Next codec transaction will reinit the HW
- * if it was suspended
- */
- if (pm_runtime_suspended(dev->dev) ||
- dev->state >= MSM_CTRL_ASLEEP) {
- break;
- } else {
- ngd_slim_power_up(dev);
- msm_slim_put_ctrl(dev);
+ if (dev->mdm.state != MSM_CTRL_DOWN)
+ return NOTIFY_DONE;
+ SLIM_INFO(dev,
+ "SLIM %lu external_modem SSR notify cb\n", code);
+ /* vote for runtime-pm so that ADSP doesn't go down */
+ msm_slim_get_ctrl(dev);
+ msm_slim_qmi_check_framer_request(dev);
+ /* If NGD enumeration is lost, we will need to power us up */
+ ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+ laddr = readl_relaxed(ngd + NGD_STATUS);
+ if (!(laddr & NGD_LADDR)) {
+ /* runtime-pm state should be consistent with HW */
+ pm_runtime_disable(dev->dev);
+ pm_runtime_set_suspended(dev->dev);
+ dev->state = MSM_CTRL_DOWN;
+ SLIM_INFO(dev,
+ "SLIM MDM SSR (active framer on MDM) dev-down\n");
+ list_for_each_entry(sbdev, &ctrl->devs, dev_list)
+ slim_report_absent(sbdev);
+ ngd_slim_power_up(dev, true);
+ pm_runtime_set_active(dev->dev);
+ pm_runtime_enable(dev->dev);
}
+ dev->mdm.state = MSM_CTRL_AWAKE;
+ msm_slim_put_ctrl(dev);
+ break;
default:
break;
}
@@ -302,7 +323,7 @@
if (dev->state == MSM_CTRL_DOWN) {
u8 mc = (u8)txn->mc;
int timeout;
- dev_err(dev->dev, "ADSP slimbus not up yet");
+ SLIM_INFO(dev, "ADSP slimbus not up yet\n");
/*
* Messages related to data channel management can't
* wait since they are holding reconfiguration lock.
@@ -362,7 +383,7 @@
mutex_lock(&dev->tx_lock);
if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
- dev_err(dev->dev, "controller not ready");
+ SLIM_ERR(dev, "controller not ready\n");
mutex_unlock(&dev->tx_lock);
msm_slim_put_ctrl(dev);
return -EREMOTEIO;
@@ -372,6 +393,14 @@
txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
int i = 0;
+ if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
+ SLIM_INFO(dev,
+ "Connect port: laddr 0x%x port_num %d chan_num %d\n",
+ txn->la, txn->wbuf[0], txn->wbuf[1]);
+ else
+ SLIM_INFO(dev,
+ "Disconnect port: laddr 0x%x port_num %d\n",
+ txn->la, txn->wbuf[0]);
txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
txn->mc = SLIM_USR_MC_CONNECT_SRC;
@@ -388,10 +417,11 @@
mutex_unlock(&dev->tx_lock);
ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
&dev->pgdla);
- pr_debug("SLIM PGD LA:0x%x, ret:%d", dev->pgdla,
- ret);
+ SLIM_DBG(dev, "SLIM PGD LA:0x%x, ret:%d\n",
+ dev->pgdla, ret);
if (ret) {
- pr_err("Incorrect SLIM-PGD EAPC:0x%x",
+ SLIM_ERR(dev,
+ "Incorrect SLIM-PGD EAPC:0x%x\n",
dev->pdata.eapc);
return ret;
}
@@ -406,7 +436,8 @@
wbuf[i++] = txn->wbuf[1];
ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
if (ret) {
- pr_err("TID for connect/disconnect fail:%d", ret);
+ SLIM_ERR(dev, "TID for connect/disconnect fail:%d\n",
+ ret);
goto ngd_xfer_err;
}
txn->len = i;
@@ -416,7 +447,7 @@
txn->rl--;
pbuf = msm_get_msg_buf(dev, txn->rl);
if (!pbuf) {
- dev_err(dev->dev, "Message buffer unavailable");
+ SLIM_ERR(dev, "Message buffer unavailable\n");
ret = -ENOMEM;
goto ngd_xfer_err;
}
@@ -470,7 +501,7 @@
return 0;
}
if (dev->err) {
- dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
+ SLIM_ERR(dev, "pipe-port connect err:%d\n", dev->err);
goto ngd_xfer_err;
}
/* Add port-base to port number if this is manager side port */
@@ -509,7 +540,7 @@
u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
dev->ver);
- dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
+ SLIM_WARN(dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d\n",
txn_mc, txn_mt, ret, dev->ver);
conf = readl_relaxed(ngd);
stat = readl_relaxed(ngd + NGD_STATUS);
@@ -518,9 +549,10 @@
int_en = readl_relaxed(ngd + NGD_INT_EN);
int_clr = readl_relaxed(ngd + NGD_INT_CLR);
- pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
- pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
- int_en, int_clr);
+ SLIM_WARN(dev, "conf:0x%x,stat:0x%x,rxmsgq:0x%x\n",
+ conf, stat, rx_msgq);
+ SLIM_WARN(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
+ int_stat, int_en, int_clr);
} else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
(txn_mc == SLIM_USR_MC_CONNECT_SRC ||
txn_mc == SLIM_USR_MC_CONNECT_SINK ||
@@ -534,8 +566,9 @@
else
ret = txn->ec;
if (ret) {
- pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
- txn->tid, ret);
+ SLIM_INFO(dev,
+ "connect/disconnect:0x%x,tid:%d err:%d\n",
+ txn->mc, txn->tid, ret);
mutex_lock(&ctrl->m_ctrl);
ctrl->txnt[txn->tid] = NULL;
mutex_unlock(&ctrl->m_ctrl);
@@ -590,6 +623,7 @@
static int ngd_xferandwait_ack(struct slim_controller *ctrl,
struct slim_msg_txn *txn)
{
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
int ret = ngd_xfer_msg(ctrl, txn);
if (!ret) {
int timeout;
@@ -602,8 +636,8 @@
if (ret) {
if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
- pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
- txn->tid, ret);
+ SLIM_ERR(dev, "master msg:0x%x,tid:%d ret:%d\n",
+ txn->mc, txn->tid, ret);
mutex_lock(&ctrl->m_ctrl);
ctrl->txnt[txn->tid] = NULL;
mutex_unlock(&ctrl->m_ctrl);
@@ -614,12 +648,13 @@
static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
{
- int ret;
+ int ret = 0, num_chan = 0;
struct slim_pending_ch *pch;
struct slim_msg_txn txn;
struct slim_controller *ctrl = sb->ctrl;
DECLARE_COMPLETION_ONSTACK(done);
u8 wbuf[SLIM_MSGQ_BUF_LEN];
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
*clkgear = ctrl->clkgear;
*subfrmc = 0;
@@ -632,7 +667,7 @@
txn.rbuf = NULL;
if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
- pr_debug("slim reserve BW for messaging: req: %d",
+ SLIM_DBG(dev, "slim reserve BW for messaging: req: %d\n",
ctrl->sched.pending_msgsl);
txn.mc = SLIM_USR_MC_REQ_BW;
wbuf[txn.len++] = ((sb->laddr & 0x1f) |
@@ -663,7 +698,7 @@
struct slim_ich *slc;
slc = &ctrl->chans[pch->chan];
if (!slc) {
- pr_err("no channel in define?");
+ SLIM_WARN(dev, "no channel in define?\n");
return -ENXIO;
}
if (txn.len == 0) {
@@ -678,12 +713,14 @@
wbuf[txn.len++] = slc->prrate;
ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
if (ret) {
- pr_err("no tid for channel define?");
+ SLIM_WARN(dev, "no tid for channel define?\n");
return -ENXIO;
}
}
+ num_chan++;
wbuf[txn.len++] = slc->chan;
- pr_debug("slim define chan:%d, tid:0x%x", slc->chan, txn.tid);
+ SLIM_INFO(dev, "slim activate chan:%d, laddr: 0x%x\n",
+ slc->chan, sb->laddr);
}
if (txn.len) {
txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
@@ -708,7 +745,7 @@
struct slim_ich *slc;
slc = &ctrl->chans[pch->chan];
if (!slc) {
- pr_err("no channel in removal?");
+ SLIM_WARN(dev, "no channel in removal?\n");
return -ENXIO;
}
if (txn.len == 0) {
@@ -717,12 +754,13 @@
(sb->laddr & 0x1f);
ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
if (ret) {
- pr_err("no tid for channel define?");
+ SLIM_WARN(dev, "no tid for channel define?\n");
return -ENXIO;
}
}
wbuf[txn.len++] = slc->chan;
- pr_debug("slim remove chan:%d, tid:0x%x", slc->chan, txn.tid);
+ SLIM_INFO(dev, "slim remove chan:%d, laddr: 0x%x\n",
+ slc->chan, sb->laddr);
}
if (txn.len) {
txn.mc = SLIM_USR_MC_CHAN_CTRL;
@@ -830,7 +868,7 @@
wbuf[3] = SAT_MSG_PROT;
txn.wbuf = wbuf;
txn.len = 4;
- pr_info("SLIM SAT: Received master capability");
+ SLIM_INFO(dev, "SLIM SAT: Rcvd master capability\n");
if (dev->state >= MSM_CTRL_ASLEEP) {
ngd_slim_setup_msg_path(dev);
if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
@@ -847,18 +885,20 @@
ret = ngd_xfer_msg(&dev->ctrl, &txn);
if (!ret) {
enum msm_ctrl_state prev_state = dev->state;
- pr_info("SLIM SAT: capability exchange successful");
+ SLIM_INFO(dev,
+ "SLIM SAT: capability exchange successful\n");
dev->state = MSM_CTRL_AWAKE;
if (prev_state >= MSM_CTRL_ASLEEP)
complete(&dev->reconf);
else
- pr_err("SLIM: unexpected capability, state:%d",
- prev_state);
+ SLIM_ERR(dev,
+ "SLIM: unexpected capability, state:%d\n",
+ prev_state);
/* ADSP SSR, send device_up notifications */
if (prev_state == MSM_CTRL_DOWN)
complete(&dev->qmi.slave_notify);
} else if (ret == -EIO) {
- pr_info("capability message NACKed, retrying");
+ SLIM_WARN(dev, "capability message NACKed, retrying\n");
if (retries < INIT_MX_RETRIES) {
msleep(DEF_RETRY_MS);
retries++;
@@ -881,8 +921,9 @@
mutex_lock(&dev->ctrl.m_ctrl);
txn = dev->ctrl.txnt[buf[3]];
if (!txn) {
- pr_err("LADDR response after timeout, tid:0x%x",
- buf[3]);
+ SLIM_WARN(dev,
+ "LADDR response after timeout, tid:0x%x\n",
+ buf[3]);
mutex_unlock(&dev->ctrl.m_ctrl);
return;
}
@@ -898,7 +939,7 @@
mutex_lock(&dev->ctrl.m_ctrl);
txn = dev->ctrl.txnt[buf[3]];
if (!txn) {
- pr_err("ACK received after timeout, tid:0x%x",
+ SLIM_WARN(dev, "ACK received after timeout, tid:0x%x\n",
buf[3]);
mutex_unlock(&dev->ctrl.m_ctrl);
return;
@@ -906,7 +947,7 @@
dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
(int)buf[3], buf[4]);
if (!(buf[4] & MSM_SAT_SUCCSS)) {
- dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
+ SLIM_WARN(dev, "TID:%d, NACK code:0x%x\n", (int)buf[3],
buf[4]);
txn->ec = -EIO;
}
@@ -916,7 +957,7 @@
}
}
-static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart)
{
void __iomem *ngd;
int timeout, ret = 0;
@@ -927,18 +968,20 @@
NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
- if (cur_state == MSM_CTRL_DOWN) {
+ if (!mdm_restart && cur_state == MSM_CTRL_DOWN) {
int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
HZ);
if (!timeout)
- pr_err("slimbus QMI init timed out");
+ SLIM_ERR(dev, "slimbus QMI init timed out\n");
}
/* No need to vote if contorller is not in low power mode */
- if (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP) {
+ if (!mdm_restart &&
+ (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP)) {
ret = msm_slim_qmi_power_request(dev, true);
if (ret) {
- pr_err("SLIM QMI power request failed:%d", ret);
+ SLIM_ERR(dev, "SLIM QMI power request failed:%d\n",
+ ret);
return ret;
}
}
@@ -955,7 +998,7 @@
* For example, modem restarted when playback was active
*/
if (cur_state == MSM_CTRL_AWAKE) {
- pr_err("SLIM MDM restart: ADSP active framer:NO OP");
+ SLIM_INFO(dev, "Subsys restart: ADSP active framer\n");
return 0;
}
/*
@@ -964,24 +1007,27 @@
*/
ngd_slim_setup_msg_path(dev);
return 0;
- } else if (cur_state == MSM_CTRL_ASLEEP) {
- pr_debug("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
- dev->state, laddr);
- } else if (cur_state == MSM_CTRL_IDLE || cur_state == MSM_CTRL_AWAKE) {
+ }
+
+ if (mdm_restart) {
/*
- * external MDM SSR when only voice call is in progress.
+ * external MDM SSR when MDM is active framer
* ADSP will reset slimbus HW. disconnect BAM pipes so that
* they can be connected after capability message is received.
* Set device state to ASLEEP to be synchronous with the HW
*/
- pr_err("SLIM MDM restart: MDM active framer: reinit HW");
- dev->state = MSM_CTRL_ASLEEP;
- msm_slim_disconnect_endp(dev, &dev->rx_msgq,
- &dev->use_rx_msgqs);
- msm_slim_disconnect_endp(dev, &dev->tx_msgq,
- &dev->use_tx_msgqs);
+ /* make current state as DOWN */
+ cur_state = MSM_CTRL_DOWN;
+ SLIM_INFO(dev,
+ "SLIM MDM restart: MDM active framer: reinit HW\n");
+ /* disconnect BAM pipes */
+ if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
+ dev->use_rx_msgqs = MSM_MSGQ_DOWN;
+ if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
+ dev->use_tx_msgqs = MSM_MSGQ_DOWN;
+ dev->state = MSM_CTRL_DOWN;
}
- /* ADSP SSR scenario, need to disconnect pipe before connecting */
+ /* SSR scenario, need to disconnect pipe before connecting */
if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
struct msm_slim_endp *endpoint = &dev->rx_msgq;
sps_disconnect(endpoint->sps);
@@ -1010,11 +1056,14 @@
timeout = wait_for_completion_timeout(&dev->reconf, HZ);
if (!timeout) {
- pr_err("Failed to receive master capability");
+ SLIM_ERR(dev, "Failed to receive master capability\n");
return -ETIMEDOUT;
}
- if (cur_state == MSM_CTRL_DOWN)
+ if (cur_state == MSM_CTRL_DOWN) {
complete(&dev->ctrl_up);
+ /* Resetting the log level */
+ SLIM_RST_LOGLVL(dev);
+ }
return 0;
}
@@ -1038,7 +1087,7 @@
* framework state
*/
if (ret)
- ngd_slim_power_up(dev);
+ ngd_slim_power_up(dev, false);
if (!pm_runtime_enabled(dev->dev) ||
!pm_runtime_suspended(dev->dev))
ngd_slim_runtime_resume(dev->dev);
@@ -1047,7 +1096,7 @@
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put(dev->dev);
} else
- dev_err(dev->dev, "qmi init fail, ret:%d, state:%d",
+ SLIM_ERR(dev, "qmi init fail, ret:%d, state:%d\n",
ret, dev->state);
} else {
msm_slim_qmi_exit(dev);
@@ -1059,7 +1108,7 @@
static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
- return ngd_slim_power_up(dev);
+ return ngd_slim_power_up(dev, false);
}
static int ngd_slim_rx_msgq_thread(void *data)
@@ -1083,7 +1132,7 @@
}
ret = msm_slim_rx_msgq_get(dev, buffer, index);
if (ret) {
- dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
+ SLIM_ERR(dev, "rx_msgq_get() failed 0x%x\n", ret);
continue;
}
@@ -1168,7 +1217,7 @@
/* device up should be called again after SSR */
list_for_each_entry(sbdev, &ctrl->devs, dev_list)
slim_report_absent(sbdev);
- pr_info("SLIM ADSP SSR (DOWN) done");
+ SLIM_INFO(dev, "SLIM ADSP SSR (DOWN) done\n");
}
static void ngd_adsp_up(struct work_struct *work)
@@ -1180,6 +1229,28 @@
ngd_slim_enable(dev, true);
}
+static ssize_t show_mask(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ return snprintf(buf, sizeof(int), "%u\n", dev->ipc_log_mask);
+}
+
+static ssize_t set_mask(struct device *device, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+
+ dev->ipc_log_mask = buf[0] - '0';
+ if (dev->ipc_log_mask > DBG_LEV)
+ dev->ipc_log_mask = DBG_LEV;
+ return count;
+}
+
+static DEVICE_ATTR(debug_mask, S_IRUGO | S_IWUSR, show_mask, set_mask);
+
static int __devinit ngd_slim_probe(struct platform_device *pdev)
{
struct msm_slim_ctrl *dev;
@@ -1189,6 +1260,7 @@
struct resource *irq, *bam_irq;
bool rxreg_access = false;
bool slim_mdm = false;
+ const char *ext_modem_id = NULL;
slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"slimbus_physical");
@@ -1223,6 +1295,26 @@
dev->dev = &pdev->dev;
platform_set_drvdata(pdev, dev);
slim_set_ctrldata(&dev->ctrl, dev);
+
+ /* Create IPC log context */
+ dev->ipc_slimbus_log = ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES,
+ dev_name(dev->dev));
+ if (!dev->ipc_slimbus_log)
+ dev_err(&pdev->dev, "error creating ipc_logging context\n");
+ else {
+ /* Initialize the log mask */
+ dev->ipc_log_mask = INFO_LEV;
+ dev->default_ipc_log_mask = INFO_LEV;
+ SLIM_INFO(dev, "start logging for slim dev %s\n",
+ dev_name(dev->dev));
+ }
+ ret = sysfs_create_file(&dev->dev->kobj, &dev_attr_debug_mask.attr);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create dev. attr\n");
+ dev->sysfs_created = false;
+ } else
+ dev->sysfs_created = true;
+
dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
if (!dev->base) {
dev_err(&pdev->dev, "IOremap failed\n");
@@ -1249,8 +1341,10 @@
&dev->pdata.apps_pipes);
of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
&dev->pdata.eapc);
- slim_mdm = of_property_read_bool(pdev->dev.of_node,
- "qcom,slim-mdm");
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,slim-mdm", &ext_modem_id);
+ if (!ret)
+ slim_mdm = true;
} else {
dev->ctrl.nr = pdev->id;
}
@@ -1325,7 +1419,7 @@
if (slim_mdm) {
dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
- dev->mdm.ssr = subsys_notif_register_notifier("external_modem",
+ dev->mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
&dev->mdm.nb);
if (IS_ERR_OR_NULL(dev->mdm.ssr))
dev_err(dev->dev,
@@ -1363,7 +1457,7 @@
dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
goto err_notify_thread_create_failed;
}
- dev_dbg(dev->dev, "NGD SB controller is up!\n");
+ SLIM_INFO(dev, "NGD SB controller is up!\n");
return 0;
err_notify_thread_create_failed:
@@ -1381,6 +1475,9 @@
err_ioremap_bam_failed:
iounmap(dev->base);
err_ioremap_failed:
+ if (dev->sysfs_created)
+ sysfs_remove_file(&dev->dev->kobj,
+ &dev_attr_debug_mask.attr);
kfree(dev);
return ret;
}
@@ -1389,6 +1486,9 @@
{
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
ngd_slim_enable(dev, false);
+ if (dev->sysfs_created)
+ sysfs_remove_file(&dev->dev->kobj,
+ &dev_attr_debug_mask.attr);
qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
@@ -1434,10 +1534,11 @@
if (dev->state != MSM_CTRL_DOWN)
dev->state = MSM_CTRL_ASLEEP;
else
- dev_err(device, "HW wakeup attempt during SSR");
+ SLIM_WARN(dev, "HW wakeup attempt during SSR\n");
} else {
dev->state = MSM_CTRL_AWAKE;
}
+ SLIM_INFO(dev, "Slim runtime resume: ret %d\n", ret);
return ret;
}
@@ -1450,11 +1551,12 @@
ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
if (ret) {
if (ret != -EBUSY)
- dev_err(device, "clk pause not entered:%d", ret);
+ SLIM_INFO(dev, "clk pause not entered:%d\n", ret);
dev->state = MSM_CTRL_AWAKE;
} else {
dev->state = MSM_CTRL_ASLEEP;
}
+ SLIM_INFO(dev, "Slim runtime suspend: ret %d\n", ret);
return ret;
}
@@ -1466,7 +1568,6 @@
if (!pm_runtime_enabled(dev) ||
(!pm_runtime_suspended(dev) &&
cdev->state == MSM_CTRL_IDLE)) {
- dev_dbg(dev, "system suspend");
ret = ngd_slim_runtime_suspend(dev);
/*
* If runtime-PM still thinks it's active, then make sure its
@@ -1493,16 +1594,20 @@
*/
ret = 0;
}
+ SLIM_INFO(cdev, "system suspend\n");
return ret;
}
static int ngd_slim_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
/*
* Rely on runtime-PM to call resume in case it is enabled.
* Even if it's not enabled, rely on 1st client transaction to do
* clock/power on
*/
+ SLIM_INFO(cdev, "system resume\n");
return 0;
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 8589b9f..915bf88 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -51,7 +51,7 @@
if (ret >= 0) {
ref = atomic_read(&dev->dev->power.usage_count);
if (ref <= 0) {
- dev_err(dev->dev, "reference count -ve:%d", ref);
+ SLIM_WARN(dev, "reference count -ve:%d", ref);
ret = -ENODEV;
}
}
@@ -67,7 +67,7 @@
pm_runtime_mark_last_busy(dev->dev);
ref = atomic_read(&dev->dev->power.usage_count);
if (ref <= 0)
- dev_err(dev->dev, "reference count mismatch:%d", ref);
+ SLIM_WARN(dev, "reference count mismatch:%d", ref);
else
pm_runtime_put_sync(dev->dev);
#endif
@@ -109,7 +109,7 @@
/* clear port interrupts */
writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
dev->ver));
- pr_info("disabled overflow/underflow for port 0x%x", pstat);
+ SLIM_INFO(dev, "disabled overflow/underflow for port 0x%x", pstat);
/*
* Guarantee that port interrupt bit(s) clearing writes go
@@ -1133,13 +1133,13 @@
rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
&resp_desc, &resp, sizeof(resp), 5000);
if (rc < 0) {
- pr_err("%s: QMI send req failed %d\n", __func__, rc);
+ SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
return rc;
}
/* Check the response */
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
- pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+ SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n", __func__,
resp.resp.result, get_qmi_error(&resp.resp));
return -EREMOTEIO;
}
@@ -1165,13 +1165,13 @@
rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
&resp_desc, &resp, sizeof(resp), 5000);
if (rc < 0) {
- pr_err("%s: QMI send req failed %d\n", __func__, rc);
+ SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
return rc;
}
/* Check the response */
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
- pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+ SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n", __func__,
resp.resp.result, get_qmi_error(&resp.resp));
return -EREMOTEIO;
}
@@ -1208,7 +1208,7 @@
SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID);
if (rc < 0) {
- pr_err("%s: QMI server not found\n", __func__);
+ SLIM_ERR(dev, "%s: QMI server not found\n", __func__);
goto qmi_connect_to_service_failed;
}
@@ -1281,12 +1281,12 @@
rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, NULL, 0,
&resp_desc, &resp, sizeof(resp), 5000);
if (rc < 0) {
- dev_err(dev->dev, "%s: QMI send req failed %d\n", __func__, rc);
+ SLIM_ERR(dev, "%s: QMI send req failed %d\n", __func__, rc);
return rc;
}
/* Check the response */
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
- dev_err(dev->dev, "%s: QMI request failed 0x%x (%s)\n",
+ SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n",
__func__, resp.resp.result, get_qmi_error(&resp.resp));
return -EREMOTEIO;
}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 63178cc..9673208 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -17,6 +17,7 @@
#include <linux/kthread.h>
#include <mach/msm_qmi_interface.h>
#include <mach/subsystem_notif.h>
+#include <mach/msm_ipc_logging.h>
/* Per spec.max 40 bytes per received message */
#define SLIM_MSGQ_BUF_LEN 40
@@ -216,6 +217,7 @@
struct msm_slim_mdm {
struct notifier_block nb;
void *ssr;
+ enum msm_ctrl_state state;
};
struct msm_slim_pdata {
@@ -266,6 +268,10 @@
struct msm_slim_qmi qmi;
struct msm_slim_pdata pdata;
struct msm_slim_mdm mdm;
+ int default_ipc_log_mask;
+ int ipc_log_mask;
+ bool sysfs_created;
+ void *ipc_slimbus_log;
};
struct msm_sat_chan {
@@ -299,6 +305,57 @@
};
+/* IPC logging stuff */
+#define IPC_SLIMBUS_LOG_PAGES 5
+
+/* Log levels */
+enum {
+ FATAL_LEV = 0U,
+ ERR_LEV = 1U,
+ WARN_LEV = 2U,
+ INFO_LEV = 3U,
+ DBG_LEV = 4U,
+};
+
+/* Default IPC log level INFO */
+#define SLIM_DBG(dev, x...) do { \
+ pr_debug(x); \
+ if (dev->ipc_slimbus_log && dev->ipc_log_mask >= DBG_LEV) { \
+ ipc_log_string(dev->ipc_slimbus_log, x); \
+ } \
+} while (0)
+
+#define SLIM_INFO(dev, x...) do { \
+ pr_debug(x); \
+ if (dev->ipc_slimbus_log && dev->ipc_log_mask >= INFO_LEV) {\
+ ipc_log_string(dev->ipc_slimbus_log, x); \
+ } \
+} while (0)
+
+/* warnings and errors show up on console always */
+#define SLIM_WARN(dev, x...) do { \
+ pr_warn(x); \
+ if (dev->ipc_slimbus_log && dev->ipc_log_mask >= WARN_LEV) \
+ ipc_log_string(dev->ipc_slimbus_log, x); \
+} while (0)
+
+/* ERROR condition in the driver sets the hs_serial_debug_mask
+ * to ERR_FATAL level, so that this message can be seen
+ * in IPC logging. Further errors continue to log on the console
+ */
+#define SLIM_ERR(dev, x...) do { \
+ pr_err(x); \
+ if (dev->ipc_slimbus_log && dev->ipc_log_mask >= ERR_LEV) { \
+ ipc_log_string(dev->ipc_slimbus_log, x); \
+ dev->default_ipc_log_mask = dev->ipc_log_mask; \
+ dev->ipc_log_mask = FATAL_LEV; \
+ } \
+} while (0)
+
+#define SLIM_RST_LOGLVL(dev) { \
+ dev->ipc_log_mask = dev->default_ipc_log_mask; \
+}
+
int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len);
int msm_slim_rx_dequeue(struct msm_slim_ctrl *dev, u8 *buf);
int msm_slim_get_ctrl(struct msm_slim_ctrl *dev);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index d3e4612..d670f8b 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1957,15 +1957,40 @@
}
}
-/* workqueue - pull messages from queue & process */
-static void msm_spi_workq(struct work_struct *work)
+/**
+ * msm_spi_transfer_one_message: To process one spi message at a time
+ * @master: spi master controller reference
+ * @msg: one multi-segment SPI transaction
+ * @return zero on success or negative error value
+ *
+ */
+static int msm_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct msm_spi *dd =
- container_of(work, struct msm_spi, work_data);
+ struct msm_spi *dd;
+ struct spi_transfer *tr;
unsigned long flags;
- u32 status_error = 0;
+ u32 status_error = 0;
- pm_runtime_get_sync(dd->dev);
+ dd = spi_master_get_devdata(master);
+
+ if (list_empty(&msg->transfers) || !msg->complete)
+ return -EINVAL;
+
+ list_for_each_entry(tr, &msg->transfers, transfer_list) {
+ /* Check message parameters */
+ if (tr->speed_hz > dd->pdata->max_clock_speed ||
+ (tr->bits_per_word &&
+ (tr->bits_per_word < 4 || tr->bits_per_word > 32)) ||
+ (tr->tx_buf == NULL && tr->rx_buf == NULL)) {
+ dev_err(dd->dev,
+ "Invalid transfer: %d Hz, %d bpw tx=%p, rx=%p\n",
+ tr->speed_hz, tr->bits_per_word,
+ tr->tx_buf, tr->rx_buf);
+ status_error = -EINVAL;
+ goto out;
+ }
+ }
mutex_lock(&dd->core_lock);
@@ -1990,20 +2015,16 @@
status_error = 1;
}
spin_lock_irqsave(&dd->queue_lock, flags);
+ dd->transfer_pending = 1;
+ dd->cur_msg = msg;
+ spin_unlock_irqrestore(&dd->queue_lock, flags);
- while (!list_empty(&dd->queue)) {
- dd->cur_msg = list_entry(dd->queue.next,
- struct spi_message, queue);
- list_del_init(&dd->cur_msg->queue);
- spin_unlock_irqrestore(&dd->queue_lock, flags);
- if (status_error)
+ if (status_error)
dd->cur_msg->status = -EIO;
- else
- msm_spi_process_message(dd);
- if (dd->cur_msg->complete)
- dd->cur_msg->complete(dd->cur_msg->context);
- spin_lock_irqsave(&dd->queue_lock, flags);
- }
+ else
+ msm_spi_process_message(dd);
+
+ spin_lock_irqsave(&dd->queue_lock, flags);
dd->transfer_pending = 0;
spin_unlock_irqrestore(&dd->queue_lock, flags);
@@ -2012,44 +2033,33 @@
mutex_unlock(&dd->core_lock);
- pm_runtime_mark_last_busy(dd->dev);
- pm_runtime_put_autosuspend(dd->dev);
-
- /* If needed, this can be done after the current message is complete,
- and work can be continued upon resume. No motivation for now. */
+ /*
+ * If needed, this can be done after the current message is complete,
+ * and work can be continued upon resume. No motivation for now.
+ */
if (dd->suspended)
wake_up_interruptible(&dd->continue_suspend);
+
+out:
+ dd->cur_msg->status = status_error;
+ spi_finalize_current_message(master);
+ return 0;
}
-static int msm_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+static int msm_spi_prepare_transfer_hardware(struct spi_master *master)
{
- struct msm_spi *dd;
- unsigned long flags;
- struct spi_transfer *tr;
+ struct msm_spi *dd = spi_master_get_devdata(master);
- dd = spi_master_get_devdata(spi->master);
+ pm_runtime_get_sync(dd->dev);
+ return 0;
+}
- if (list_empty(&msg->transfers) || !msg->complete)
- return -EINVAL;
+static int msm_spi_unprepare_transfer_hardware(struct spi_master *master)
+{
+ struct msm_spi *dd = spi_master_get_devdata(master);
- list_for_each_entry(tr, &msg->transfers, transfer_list) {
- /* Check message parameters */
- if (tr->speed_hz > dd->pdata->max_clock_speed ||
- (tr->bits_per_word &&
- (tr->bits_per_word < 4 || tr->bits_per_word > 32)) ||
- (tr->tx_buf == NULL && tr->rx_buf == NULL)) {
- dev_err(&spi->dev, "Invalid transfer: %d Hz, %d bpw"
- "tx=%p, rx=%p\n",
- tr->speed_hz, tr->bits_per_word,
- tr->tx_buf, tr->rx_buf);
- return -EINVAL;
- }
- }
-
- spin_lock_irqsave(&dd->queue_lock, flags);
- list_add_tail(&msg->queue, &dd->queue);
- spin_unlock_irqrestore(&dd->queue_lock, flags);
- queue_work(dd->workqueue, &dd->work_data);
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
return 0;
}
@@ -2701,6 +2711,8 @@
&dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1},
{"qcom,gpio-cs3",
&dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1},
+ {"qcom,rt-priority",
+ &pdata->rt_priority, DT_OPT, DT_BOOL, 0},
{NULL, NULL, 0, 0, 0},
};
@@ -2794,7 +2806,11 @@
master->mode_bits = SPI_SUPPORTED_MODES;
master->num_chipselect = SPI_NUM_CHIPSELECTS;
master->setup = msm_spi_setup;
- master->transfer = msm_spi_transfer;
+ master->prepare_transfer_hardware = msm_spi_prepare_transfer_hardware;
+ master->transfer_one_message = msm_spi_transfer_one_message;
+ master->unprepare_transfer_hardware
+ = msm_spi_unprepare_transfer_hardware;
+
platform_set_drvdata(pdev, master);
dd = spi_master_get_devdata(master);
@@ -2834,6 +2850,7 @@
for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
dd->cs_gpios[i].valid = 0;
+ master->rt = pdata->rt_priority;
dd->pdata = pdata;
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!resource) {
@@ -2895,13 +2912,6 @@
spin_lock_init(&dd->queue_lock);
mutex_init(&dd->core_lock);
- INIT_LIST_HEAD(&dd->queue);
- INIT_WORK(&dd->work_data, msm_spi_workq);
- init_waitqueue_head(&dd->continue_suspend);
- dd->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (!dd->workqueue)
- goto err_probe_workq;
if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr,
dd->mem_size, SPI_DRV_NAME)) {
@@ -3078,8 +3088,6 @@
}
err_probe_rlock_init:
err_probe_reqmem:
- destroy_workqueue(dd->workqueue);
-err_probe_workq:
err_probe_res:
spi_master_put(master);
err_probe_exit:
@@ -3242,7 +3250,6 @@
clk_put(dd->clk);
clk_put(dd->pclk);
msm_spi_clk_path_teardown(dd);
- destroy_workqueue(dd->workqueue);
platform_set_drvdata(pdev, 0);
spi_unregister_master(master);
spi_master_put(master);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 2a67a61..d538076 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -300,9 +300,6 @@
struct device *dev;
spinlock_t queue_lock;
struct mutex core_lock;
- struct list_head queue;
- struct workqueue_struct *workqueue;
- struct work_struct work_data;
struct spi_message *cur_msg;
struct spi_transfer *cur_transfer;
struct completion transfer_complete;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 4eacb73..7d4ecd6 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2743,6 +2743,18 @@
else
pr_debug("%s:voltage request failed\n", __func__);
break;
+ case MSM_USB_EXT_CHG_TYPE:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (val)
+ pr_debug("%s:charger is external charger\n", __func__);
+ else
+ pr_debug("%s:charger is not ext charger\n", __func__);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 350fd41..486d99d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2573,8 +2573,10 @@
bool work = 0, srp_reqd, dcp;
pm_runtime_resume(otg->phy->dev);
- if (motg->pm_done)
+ if (motg->pm_done) {
pm_runtime_get_sync(otg->phy->dev);
+ motg->pm_done = 0;
+ }
pr_debug("%s work\n", otg_state_string(otg->phy->state));
switch (otg->phy->state) {
case OTG_STATE_UNDEFINED:
@@ -4095,6 +4097,18 @@
else
pr_debug("%s:voltage request failed\n", __func__);
break;
+ case MSM_USB_EXT_CHG_TYPE:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (val)
+ pr_debug("%s:charger is external charger\n", __func__);
+ else
+ pr_debug("%s:charger is not ext charger\n", __func__);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 669fca9..05292f9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -235,6 +235,15 @@
sdev->use_rpm_auto = 1;
sdev->autosuspend_delay = us->sdev_autosuspend_delay;
}
+
+ /*
+ * This quirk enables sending consecutive TEST_UNIT_READY
+ * commands in WRITE(10) command processing context. Increase
+ * the timeout to 60 seconds.
+ */
+ if (us->fflags & US_FL_TUR_AFTER_WRITE)
+ blk_queue_rq_timeout(sdev->request_queue, (60 * HZ));
+
} else {
/* Non-disk-type devices don't need to blacklist any pages
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c70109e..a710d9f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -859,6 +859,42 @@
srb->result = DID_ERROR << 16;
last_sector_hacks(us, srb);
+
+ /*
+ * TMC UICC cards expect 5 TEST_UNIT_READY commands after
+ * writing some data. The card performs the flash related
+ * house keeping operations after receiving these commands.
+ * Send 5 TEST_UNIT_READY commands for every 8 WRITE_10
+ * commands.
+ */
+ if (unlikely((us->fflags & US_FL_TUR_AFTER_WRITE) &&
+ srb->cmnd[0] == WRITE_10)) {
+ int i;
+ int temp_result;
+ struct scsi_eh_save ses;
+ unsigned char cmd[] = {
+ TEST_UNIT_READY, 0, 0, 0, 0, 0,
+ };
+
+ us->tur_count[srb->device->lun]++;
+
+ if (++us->tur_count[srb->device->lun] == 8) {
+
+ us->tur_count[srb->device->lun] = 0;
+
+ scsi_eh_prep_cmnd(srb, &ses, cmd, 6, 0);
+ for (i = 0; i < 5; i++) {
+ temp_result = us->transport(us->srb, us);
+ if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("TUR failed %d %d\n",
+ i, temp_result);
+ break;
+ }
+ }
+ scsi_eh_restore_cmnd(srb, &ses);
+ }
+ }
+
return;
/* Error and abort processing: try to resynchronize with the device
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 856ad92..901f6fb 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2018,6 +2018,12 @@
"Digital MP3 Audio Player",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+/* Reported by Pavankumar Kondeti <pkondeti@codeaurora.org> */
+UNUSUAL_DEV(0x0925, 0x9011, 0x0100, 0x0100,
+ "TMC",
+ "USB DISK",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_TUR_AFTER_WRITE),
+
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index db75080..b079984 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -162,6 +162,8 @@
int use_last_sector_hacks;
int last_sector_retries;
int sdev_autosuspend_delay;
+ /* consecutive TEST_UNIT_READY commands during write */
+ int tur_count[16];
};
/* Convert between us_data and the corresponding Scsi_Host */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 2fcbeac..ad7cb81 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -47,6 +47,7 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/msm_memtypes.h>
+#include <mach/rpm-regulator-smd.h>
#include "mdp3.h"
#include "mdss_fb.h"
@@ -1204,6 +1205,54 @@
return 0;
}
+void msm_mdp3_cx_ctrl(int enable)
+{
+ int rc;
+
+ if (!mdp3_res->vdd_cx) {
+ mdp3_res->vdd_cx = devm_regulator_get(&mdp3_res->pdev->dev,
+ "vdd-cx");
+ if (IS_ERR_OR_NULL(mdp3_res->vdd_cx)) {
+ pr_debug("unable to get CX reg. rc=%d\n",
+ PTR_RET(mdp3_res->vdd_cx));
+ mdp3_res->vdd_cx = NULL;
+ return;
+ }
+ }
+
+ if (enable) {
+ rc = regulator_set_voltage(
+ mdp3_res->vdd_cx,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ if (rc < 0)
+ goto vreg_set_voltage_fail;
+
+ rc = regulator_enable(mdp3_res->vdd_cx);
+ if (rc) {
+ pr_err("Failed to enable regulator vdd_cx.\n");
+ return;
+ }
+ } else {
+ rc = regulator_disable(mdp3_res->vdd_cx);
+ if (rc) {
+ pr_err("Failed to disable regulator vdd_cx.\n");
+ return;
+ }
+ rc = regulator_set_voltage(
+ mdp3_res->vdd_cx,
+ RPM_REGULATOR_CORNER_NONE,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ if (rc < 0)
+ goto vreg_set_voltage_fail;
+ }
+
+ return;
+vreg_set_voltage_fail:
+ pr_err("Set vltg failed\n");
+ return;
+}
+
void mdp3_batfet_ctrl(int enable)
{
int rc;
@@ -1236,6 +1285,12 @@
pr_err("%s: reg enable/disable failed", __func__);
}
+void mdp3_enable_regulator(int enable)
+{
+ msm_mdp3_cx_ctrl(enable);
+ mdp3_batfet_ctrl(enable);
+}
+
static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
{
unsigned int domain_num;
@@ -1963,7 +2018,7 @@
else
mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
- mdp3_batfet_ctrl(true);
+ mdp3_enable_regulator(true);
mdp3_res->cont_splash_en = 1;
return 0;
@@ -2320,13 +2375,13 @@
static int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
{
- mdp3_batfet_ctrl(false);
+ mdp3_enable_regulator(false);
return 0;
}
static int mdp3_resume_sub(struct mdp3_hw_resource *mdata)
{
- mdp3_batfet_ctrl(true);
+ mdp3_enable_regulator(true);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 6650cf3..15aab59 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -164,6 +164,7 @@
bool batfet_required;
struct regulator *batfet;
+ struct regulator *vdd_cx;
};
struct mdp3_img_data {
@@ -207,6 +208,7 @@
int mdp3_misr_set(struct mdp_misr *misr_req);
int mdp3_misr_get(struct mdp_misr *misr_resp);
+void mdp3_enable_regulator(int enable);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 3ab6270..9cbff71 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -113,6 +113,7 @@
static void mdp3_dispatch_dma_done(struct work_struct *work)
{
struct mdp3_session_data *session;
+ int cnt = 0;
pr_debug("%s\n", __func__);
session = container_of(work, struct mdp3_session_data,
@@ -120,7 +121,13 @@
if (!session)
return;
- mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+ cnt = atomic_read(&session->dma_done_cnt);
+
+ while (cnt > 0) {
+ mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+ atomic_dec(&session->dma_done_cnt);
+ cnt--;
+ }
}
static void mdp3_dispatch_clk_off(struct work_struct *work)
@@ -156,6 +163,7 @@
void dma_done_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+ atomic_inc(&session->dma_done_cnt);
schedule_work(&session->dma_done_work);
complete(&session->dma_completion);
}
@@ -297,7 +305,7 @@
vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
- rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+ rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks);
return rc;
}
@@ -498,6 +506,7 @@
int vbp, vfp, vspw;
int vtotal, vporch;
struct mdp3_notification dma_done_callback;
+ struct mdp3_tear_check te;
vbp = panel_info->lcdc.v_back_porch;
vfp = panel_info->lcdc.v_front_porch;
@@ -529,12 +538,28 @@
(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
MDP3_DMA_OUTPUT_COMP_BITS_8;
+ te.frame_rate = panel_info->mipi.frame_rate;
+ te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode;
+ te.tear_check_en = panel_info->te.tear_check_en;
+ te.sync_cfg_height = panel_info->te.sync_cfg_height;
+ te.vsync_init_val = panel_info->te.vsync_init_val;
+ te.sync_threshold_start = panel_info->te.sync_threshold_start;
+ te.sync_threshold_continue = panel_info->te.sync_threshold_continue;
+ te.start_pos = panel_info->te.start_pos;
+ te.rd_ptr_irq = panel_info->te.rd_ptr_irq;
+ te.refx100 = panel_info->te.refx100;
+
if (dma->dma_config)
rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
else
rc = -EINVAL;
if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+ if (dma->dma_sync_config)
+ rc = dma->dma_sync_config(dma,
+ &sourceConfig, &te);
+ else
+ rc = -EINVAL;
dma_done_callback.handler = dma_done_notify_handler;
dma_done_callback.arg = mfd->mdp.private1;
dma->dma_done_notifier(dma, &dma_done_callback);
@@ -567,7 +592,7 @@
goto on_error;
}
- mdp3_batfet_ctrl(true);
+ mdp3_enable_regulator(true);
mdp3_ctrl_notifier_register(mdp3_session,
&mdp3_session->mfd->mdp_sync_pt_data.notifier);
@@ -638,6 +663,9 @@
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;
@@ -675,9 +703,10 @@
mdp3_ctrl_notifier_unregister(mdp3_session,
&mdp3_session->mfd->mdp_sync_pt_data.notifier);
- mdp3_batfet_ctrl(false);
+ mdp3_enable_regulator(false);
mdp3_session->vsync_enabled = 0;
atomic_set(&mdp3_session->vsync_countdown, 0);
+ atomic_set(&mdp3_session->dma_done_cnt, 0);
mdp3_session->clk_on = 0;
mdp3_session->in_splash_screen = 0;
off_error:
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 20649fc..93356e2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -50,6 +50,7 @@
struct mdp3_buffer_queue bufq_out;
struct work_struct clk_off_work;
struct work_struct dma_done_work;
+ atomic_t dma_done_cnt;
int histo_status;
struct mutex histo_lock;
int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 4135406..2dd66f8 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -24,6 +24,11 @@
#define DMA_CCS_CONFIG_MASK 0xfffffc17
#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
+#define VSYNC_SELECT 0x024
+#define VSYNC_TOTAL_LINES_SHIFT 21
+#define VSYNC_COUNT_MASK 0x7ffff
+#define VSYNC_THRESH_CONT_SHIFT 16
+
static void mdp3_vsync_intr_handler(int type, void *arg)
{
struct mdp3_dma *dma = (struct mdp3_dma *)arg;
@@ -266,32 +271,48 @@
}
}
-static int mdp3_dma_sync_config(struct mdp3_dma *dma,
- struct mdp3_dma_source *source_config)
+
+int mdp3_dma_sync_config(struct mdp3_dma *dma,
+ struct mdp3_dma_source *source_config, struct mdp3_tear_check *te)
{
- u32 sync_config;
+ u32 vsync_clk_speed_hz, vclks_line, cfg;
+ int porch = source_config->vporch;
+ int height = source_config->height;
+ int total_lines = height + porch;
int dma_sel = dma->dma_sel;
- pr_debug("mdp3_dma_sync_config\n");
+ vsync_clk_speed_hz = MDP_VSYNC_CLK_RATE;
- if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- int porch = source_config->vporch;
- int height = source_config->height;
- int vtotal = height + porch;
- sync_config = vtotal << 21;
- sync_config |= source_config->vsync_count;
- sync_config |= BIT(19);
- sync_config |= BIT(20);
+ cfg = total_lines << VSYNC_TOTAL_LINES_SHIFT;
+ total_lines *= te->frame_rate;
- MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
- MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
- height);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
- MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
- MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
+ vclks_line = (total_lines) ? vsync_clk_speed_hz / total_lines : 0;
+
+ cfg |= BIT(19);
+ if (te->hw_vsync_mode)
+ cfg |= BIT(20);
+
+ if (te->refx100) {
+ vclks_line = vclks_line * te->frame_rate *
+ 100 / te->refx100;
+ } else {
+ pr_warn("refx100 cannot be zero! Use 6000 as default\n");
+ vclks_line = vclks_line * te->frame_rate *
+ 100 / 6000;
}
+
+ cfg |= (vclks_line & VSYNC_COUNT_MASK);
+
+ MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, cfg);
+ MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, VSYNC_SELECT);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+ te->vsync_init_val);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, te->rd_ptr_irq);
+ MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel,
+ ((te->sync_threshold_continue << VSYNC_THRESH_CONT_SHIFT) |
+ te->sync_threshold_start));
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, te->start_pos);
+ MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, te->tear_check_en);
return 0;
}
@@ -324,8 +345,6 @@
dma->source_config = *source_config;
dma->output_config = *output_config;
- mdp3_dma_sync_config(dma, source_config);
-
mdp3_irq_enable(MDP3_INTR_LCDC_UNDERFLOW);
mdp3_dma_callback_setup(dma);
return 0;
@@ -378,7 +397,6 @@
dma->source_config = *source_config;
dma->output_config = *output_config;
- mdp3_dma_sync_config(dma, source_config);
mdp3_dma_callback_setup(dma);
return 0;
@@ -925,6 +943,7 @@
switch (dma->dma_sel) {
case MDP3_DMA_P:
dma->dma_config = mdp3_dmap_config;
+ dma->dma_sync_config = mdp3_dma_sync_config;
dma->dma_config_source = mdp3_dmap_config_source;
dma->config_cursor = mdp3_dmap_cursor_config;
dma->config_ccs = mdp3_dmap_ccs_config;
@@ -941,6 +960,7 @@
break;
case MDP3_DMA_S:
dma->dma_config = mdp3_dmas_config;
+ dma->dma_sync_config = mdp3_dma_sync_config;
dma->dma_config_source = mdp3_dmas_config_source;
dma->config_cursor = NULL;
dma->config_ccs = NULL;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index d244735..d07e06d 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -233,6 +233,19 @@
void *arg;
};
+struct mdp3_tear_check {
+ int frame_rate;
+ bool hw_vsync_mode;
+ u32 tear_check_en;
+ u32 sync_cfg_height;
+ u32 vsync_init_val;
+ u32 sync_threshold_start;
+ u32 sync_threshold_continue;
+ u32 start_pos;
+ u32 rd_ptr_irq;
+ u32 refx100;
+};
+
struct mdp3_intf;
struct mdp3_dma {
@@ -265,6 +278,9 @@
struct mdp3_dma_source *source_config,
struct mdp3_dma_output_config *output_config);
+ int (*dma_sync_config)(struct mdp3_dma *dma, struct mdp3_dma_source
+ *source_config, struct mdp3_tear_check *te);
+
void (*dma_config_source)(struct mdp3_dma *dma);
int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 478e704..72cceaa 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -152,6 +152,9 @@
struct mdss_fudge_factor ib_factor_overlap;
struct mdss_fudge_factor clk_factor;
+ u32 *clock_levels;
+ u32 nclk_lvl;
+
struct mdss_hw_settings *hw_settings;
struct mdss_mdp_pipe *vig_pipes;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index f450dec..f58e2a1 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -664,6 +664,41 @@
return 0;
}
+static void mdss_panel_parse_te_params(struct device_node *np,
+ struct mdss_panel_info *panel_info)
+{
+
+ u32 tmp;
+ int rc = 0;
+ /*
+ * TE default: dsi byte clock calculated base on 70 fps;
+ * around 14 ms to complete a kickoff cycle if te disabled;
+ * vclk_line base on 60 fps; write is faster than read;
+ * init == start == rdptr;
+ */
+ panel_info->te.tear_check_en =
+ !of_property_read_bool(np, "qcom,mdss-tear-check-disable");
+ rc = of_property_read_u32
+ (np, "qcom,mdss-tear-check-sync-cfg-height", &tmp);
+ panel_info->te.sync_cfg_height = (!rc ? tmp : 0xfff0);
+ rc = of_property_read_u32
+ (np, "qcom,mdss-tear-check-sync-init-val", &tmp);
+ panel_info->te.vsync_init_val = (!rc ? tmp : panel_info->yres);
+ rc = of_property_read_u32
+ (np, "qcom,mdss-tear-check-sync-threshold-start", &tmp);
+ panel_info->te.sync_threshold_start = (!rc ? tmp : 4);
+ rc = of_property_read_u32
+ (np, "qcom,mdss-tear-check-sync-threshold-continue", &tmp);
+ panel_info->te.sync_threshold_continue = (!rc ? tmp : 4);
+ rc = of_property_read_u32(np, "qcom,mdss-tear-check-start-pos", &tmp);
+ panel_info->te.start_pos = (!rc ? tmp : panel_info->yres);
+ rc = of_property_read_u32
+ (np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp);
+ panel_info->te.rd_ptr_irq = (!rc ? tmp : panel_info->yres + 1);
+ rc = of_property_read_u32(np, "qcom,mdss-tear-check-frame-rate", &tmp);
+ panel_info->te.refx100 = (!rc ? tmp : 6000);
+}
+
static int mdss_dsi_parse_reset_seq(struct device_node *np,
u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len,
@@ -994,6 +1029,7 @@
mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
"qcom,mdss-dsi-reset-sequence");
+ mdss_panel_parse_te_params(np, pinfo);
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index de0bf0d..1927fe2 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -106,6 +106,31 @@
complete(&mfd->no_update.comp);
}
+void mdss_fb_bl_update_notify(struct msm_fb_data_type *mfd)
+{
+ if (!mfd) {
+ pr_err("%s mfd NULL\n", __func__);
+ return;
+ }
+ mutex_lock(&mfd->update.lock);
+ if (mfd->update.ref_count > 0) {
+ mutex_unlock(&mfd->update.lock);
+ mfd->update.value = NOTIFY_TYPE_BL_UPDATE;
+ complete(&mfd->update.comp);
+ mutex_lock(&mfd->update.lock);
+ }
+ mutex_unlock(&mfd->update.lock);
+
+ mutex_lock(&mfd->no_update.lock);
+ if (mfd->no_update.ref_count > 0) {
+ mutex_unlock(&mfd->no_update.lock);
+ mfd->no_update.value = NOTIFY_TYPE_BL_UPDATE;
+ complete(&mfd->no_update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ }
+ mutex_unlock(&mfd->no_update.lock);
+}
+
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
@@ -127,8 +152,14 @@
ret = 1;
} else if (notify == NOTIFY_UPDATE_START) {
INIT_COMPLETION(mfd->update.comp);
+ mutex_lock(&mfd->update.lock);
+ mfd->update.ref_count++;
+ mutex_unlock(&mfd->update.lock);
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
+ mutex_lock(&mfd->update.lock);
+ mfd->update.ref_count--;
+ mutex_unlock(&mfd->update.lock);
to_user = (unsigned int)mfd->update.value;
if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
to_user = (unsigned int)mfd->update.type;
@@ -136,8 +167,14 @@
}
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ mfd->no_update.ref_count++;
+ mutex_unlock(&mfd->no_update.lock);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
+ mutex_lock(&mfd->no_update.lock);
+ mfd->no_update.ref_count--;
+ mutex_unlock(&mfd->no_update.lock);
to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
@@ -810,6 +847,7 @@
mutex_unlock(&mfd->bl_lock);
/* Will trigger ad_setup which will grab bl_lock */
update_ad_input(mfd);
+ mdss_fb_bl_update_notify(mfd);
mutex_lock(&mfd->bl_lock);
}
}
@@ -1250,10 +1288,13 @@
atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
atomic_set(&mfd->commits_pending, 0);
atomic_set(&mfd->ioctl_ref_cnt, 0);
+ atomic_set(&mfd->kickoff_pending, 0);
init_timer(&mfd->no_update.timer);
mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
mfd->no_update.timer.data = (unsigned long)mfd;
+ mfd->update.ref_count = 0;
+ mfd->no_update.ref_count = 0;
init_completion(&mfd->update.comp);
init_completion(&mfd->no_update.comp);
init_completion(&mfd->power_off_comp);
@@ -1261,6 +1302,7 @@
init_waitqueue_head(&mfd->commit_wait_q);
init_waitqueue_head(&mfd->idle_wait_q);
init_waitqueue_head(&mfd->ioctl_q);
+ init_waitqueue_head(&mfd->kickoff_wait_q);
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -1663,6 +1705,25 @@
return 0;
}
+static int mdss_fb_wait_for_kickoff(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(mfd->kickoff_wait_q,
+ (!atomic_read(&mfd->kickoff_pending) ||
+ mfd->shutdown_pending),
+ msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT / 2));
+ if (!ret) {
+ pr_err("wait for kickoff timeout %d pending=%d\n",
+ ret, atomic_read(&mfd->kickoff_pending));
+
+ } else if (mfd->shutdown_pending) {
+ pr_debug("Shutdown signalled\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
static int mdss_fb_pan_display_ex(struct fb_info *info,
struct mdp_display_commit *disp_commit)
@@ -1701,6 +1762,7 @@
atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
atomic_inc(&mfd->commits_pending);
+ atomic_inc(&mfd->kickoff_pending);
wake_up_all(&mfd->commit_wait_q);
mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
if (wait_for_finish)
@@ -1793,6 +1855,8 @@
if (ret)
pr_err("pan display failed %x on fb%d\n", ret,
mfd->index);
+ atomic_set(&mfd->kickoff_pending, 0);
+ wake_up_all(&mfd->kickoff_wait_q);
}
if (!ret)
mdss_fb_update_backlight(mfd);
@@ -1829,6 +1893,7 @@
}
atomic_set(&mfd->commits_pending, 0);
+ atomic_set(&mfd->kickoff_pending, 0);
wake_up_all(&mfd->idle_wait_q);
return ret;
@@ -2288,6 +2353,27 @@
return ret;
}
+static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd)
+{
+ int ret = 0;
+
+ if (mfd->wait_for_kickoff &&
+ ((cmd == MSMFB_OVERLAY_PREPARE) ||
+ (cmd == MSMFB_BUFFER_SYNC) ||
+ (cmd == MSMFB_OVERLAY_SET))) {
+ ret = mdss_fb_wait_for_kickoff(mfd);
+ } else if ((cmd != MSMFB_VSYNC_CTRL) &&
+ (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+ (cmd != MSMFB_ASYNC_BLIT) &&
+ (cmd != MSMFB_BLIT) &&
+ (cmd != MSMFB_NOTIFY_UPDATE)) {
+ ret = mdss_fb_pan_idle(mfd);
+ }
+
+ if (ret)
+ pr_debug("Shutdown pending. Aborting operation %x\n", cmd);
+ return ret;
+}
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
@@ -2313,17 +2399,9 @@
mdss_fb_power_setting_idle(mfd);
- if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
- (cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
- (cmd != MSMFB_NOTIFY_UPDATE) &&
- (cmd != MSMFB_OVERLAY_PREPARE)) {
- ret = mdss_fb_pan_idle(mfd);
- if (ret) {
- pr_debug("Shutdown pending. Aborting operation %x\n",
- cmd);
- goto exit;
- }
- }
+ ret = __ioctl_wait_idle(mfd, cmd);
+ if (ret)
+ goto exit;
switch (cmd) {
case MSMFB_CURSOR:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 2b4c124..febd253 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -86,6 +86,7 @@
struct mutex lock;
int value;
int is_suspend;
+ int ref_count;
};
struct msm_sync_pt_data {
@@ -213,8 +214,10 @@
/* for non-blocking */
struct task_struct *disp_thread;
atomic_t commits_pending;
+ atomic_t kickoff_pending;
wait_queue_head_t commit_wait_q;
wait_queue_head_t idle_wait_q;
+ wait_queue_head_t kickoff_wait_q;
bool shutdown_pending;
struct task_struct *splash_thread;
@@ -229,6 +232,7 @@
u32 dcm_state;
struct list_head proc_list;
+ u32 wait_for_kickoff;
};
static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 9214dcdc..667e4b7 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -2275,6 +2275,23 @@
if (rc)
pr_debug("max bandwidth (high) property not specified\n");
+ mdata->nclk_lvl = mdss_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-clk-levels");
+
+ if (mdata->nclk_lvl) {
+ mdata->clock_levels = kzalloc(sizeof(u32) * mdata->nclk_lvl,
+ GFP_KERNEL);
+ if (!mdata->clock_levels) {
+ pr_err("no mem assigned for mdata clock_levels\n");
+ return -ENOMEM;
+ }
+
+ rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-clk-levels",
+ mdata->clock_levels, mdata->nclk_lvl);
+ if (rc)
+ pr_debug("clock levels not found\n");
+ }
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 1613757..e528219 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -199,6 +199,9 @@
struct mdss_panel_data *panel_data;
struct mdss_mdp_vsync_handler vsync_handler;
+ struct mdss_mdp_vsync_handler recover_underrun_handler;
+ struct work_struct recover_work;
+ struct work_struct remove_underrun_handler;
struct mdss_mdp_img_rect roi;
struct mdss_mdp_img_rect roi_bkup;
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f188072..9cf745e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -49,6 +49,11 @@
writel_relaxed(val, mixer->base + reg);
}
+static inline u32 mdp_mixer_read(struct mdss_mdp_mixer *mixer, u32 reg)
+{
+ return readl_relaxed(mixer->base + reg);
+}
+
static inline u32 mdss_mdp_get_pclk_rate(struct mdss_mdp_ctl *ctl)
{
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
@@ -878,6 +883,29 @@
mutex_unlock(&mdss_mdp_ctl_lock);
}
+static int mdss_mdp_select_clk_lvl(struct mdss_mdp_ctl *ctl,
+ u32 clk_rate)
+{
+ int i;
+ struct mdss_data_type *mdata;
+
+ if (!ctl)
+ return -ENODEV;
+
+ mdata = ctl->mdata;
+
+ for (i = 0; i < mdata->nclk_lvl; i++) {
+ if (clk_rate > mdata->clock_levels[i]) {
+ continue;
+ } else {
+ clk_rate = mdata->clock_levels[i];
+ break;
+ }
+ }
+
+ return clk_rate;
+}
+
static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
int params_changed)
{
@@ -945,6 +973,8 @@
clk_rate = max(ctl->cur_perf.mdp_clk_rate,
clk_rate);
}
+
+ clk_rate = mdss_mdp_select_clk_lvl(ctl, clk_rate);
mdss_mdp_set_clk_rate(clk_rate);
pr_debug("update clk rate = %d HZ\n", clk_rate);
}
@@ -1929,6 +1959,7 @@
int stage, secure = 0;
int screen_state;
int outsize = 0;
+ u32 op_mode;
screen_state = ctl->force_screen_state;
@@ -2062,6 +2093,11 @@
else
ctl->flush_bits |= BIT(6) << mixer->num;
+ op_mode = mdp_mixer_read(mixer, MDSS_MDP_REG_LM_OP_MODE);
+ /* Read GC enable/disable status on LM */
+ op_mode = (op_mode & BIT(0));
+ blend_color_out |= op_mode;
+
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
off = __mdss_mdp_ctl_get_mixer_off(mixer);
mdss_mdp_ctl_write(ctl, off, mixercfg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4b9ea20..c11b438 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -109,7 +109,8 @@
#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
MDSS_MDP_CTL_ADDRESS_OFFSET))
-#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
+#define MDSS_MDP_REG_CTL_LAYER(lm) \
+ ((lm == 5) ? (0x024) : ((lm) * 0x004))
#define MDSS_MDP_REG_CTL_TOP 0x014
#define MDSS_MDP_REG_CTL_FLUSH 0x018
#define MDSS_MDP_REG_CTL_START 0x01C
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 0d1bae8..e2a8d56 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -19,9 +19,6 @@
#define VSYNC_EXPIRE_TICK 4
-#define START_THRESHOLD 4
-#define CONTINUE_THRESHOLD 4
-
#define MAX_SESSIONS 2
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
@@ -105,96 +102,86 @@
return cnt;
}
-/*
- * TE configuration:
- * dsi byte clock calculated base on 70 fps
- * around 14 ms to complete a kickoff cycle if te disabled
- * vclk_line base on 60 fps
- * write is faster than read
- * init == start == rdptr
- */
-static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
- struct mdss_mdp_cmd_ctx *ctx, int enable)
-{
- u32 cfg;
- cfg = BIT(19); /* VSYNC_COUNTER_EN */
- if (ctx->tear_check)
- cfg |= BIT(20); /* VSYNC_IN_EN */
- cfg |= ctx->vclk_line;
+static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_mixer *mixer)
+{
+ struct mdss_mdp_pp_tear_check *te;
+ struct mdss_panel_info *pinfo;
+ u32 vsync_clk_speed_hz, total_lines, vclks_line, cfg;
+
+ if (IS_ERR_OR_NULL(ctl->panel_data)) {
+ pr_err("no panel data\n");
+ return -ENODEV;
+ }
+
+ pinfo = &ctl->panel_data->panel_info;
+ te = &ctl->panel_data->panel_info.te;
+
+ mdss_mdp_vsync_clk_enable(1);
+
+ vsync_clk_speed_hz =
+ mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
+
+ total_lines = mdss_panel_get_vtotal(pinfo);
+
+ total_lines *= pinfo->mipi.frame_rate;
+
+ vclks_line = (total_lines) ? vsync_clk_speed_hz / total_lines : 0;
+
+ cfg = BIT(19);
+ if (pinfo->mipi.hw_vsync_mode)
+ cfg |= BIT(20);
+
+ if (te->refx100)
+ vclks_line = vclks_line * pinfo->mipi.frame_rate *
+ 100 / te->refx100;
+ else {
+ pr_warn("refx100 cannot be zero! Use 6000 as default\n");
+ vclks_line = vclks_line * pinfo->mipi.frame_rate *
+ 100 / 6000;
+ }
+
+ cfg |= vclks_line;
+
+ pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d ",
+ __func__, pinfo->yres, vclks_line, te->sync_cfg_height,
+ te->vsync_init_val, te->rd_ptr_irq, te->start_pos);
+ pr_debug("thrd_start =%d thrd_cont=%d\n",
+ te->sync_threshold_start, te->sync_threshold_continue);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
- 0xfff0); /* set to verh height */
-
+ te->sync_cfg_height);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL,
- ctx->height);
-
+ te->vsync_init_val);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ,
- ctx->height + 1);
-
+ te->rd_ptr_irq);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS,
- ctx->height);
-
+ te->start_pos);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
- (CONTINUE_THRESHOLD << 16) | (ctx->start_threshold));
-
- mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
+ ((te->sync_threshold_continue << 16) |
+ te->sync_threshold_start));
+ mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN,
+ te->tear_check_en);
return 0;
}
-static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, int enable)
+static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl)
{
- struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
- struct mdss_panel_info *pinfo;
struct mdss_mdp_mixer *mixer;
-
- pinfo = &ctl->panel_data->panel_info;
-
- if (pinfo->mipi.vsync_enable && enable) {
- u32 mdp_vsync_clk_speed_hz, total_lines;
-
- mdss_mdp_vsync_clk_enable(1);
-
- mdp_vsync_clk_speed_hz =
- mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
- pr_debug("%s: vsync_clk_rate=%d\n", __func__,
- mdp_vsync_clk_speed_hz);
-
- if (mdp_vsync_clk_speed_hz == 0) {
- pr_err("can't get clk speed\n");
- return -EINVAL;
- }
-
- ctx->tear_check = pinfo->mipi.hw_vsync_mode;
- ctx->height = pinfo->yres;
- ctx->vporch = pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch +
- pinfo->lcdc.v_pulse_width;
-
- ctx->start_threshold = START_THRESHOLD;
-
- total_lines = ctx->height + ctx->vporch;
- total_lines *= pinfo->mipi.frame_rate;
- ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
-
- pr_debug("%s: fr=%d tline=%d vcnt=%d thold=%d vrate=%d\n",
- __func__, pinfo->mipi.frame_rate, total_lines,
- ctx->vclk_line, ctx->start_threshold,
- mdp_vsync_clk_speed_hz);
- } else {
- enable = 0;
- }
-
+ int rc = 0;
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
- if (mixer)
- mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
-
+ if (mixer) {
+ rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer);
+ if (rc)
+ goto err;
+ }
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
if (mixer)
- mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
-
- return 0;
+ rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer);
+ err:
+ return rc;
}
static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
@@ -216,7 +203,7 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctx->ulps) {
- if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
+ if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl))
pr_warn("tearcheck setup failed\n");
mdss_mdp_ctl_intf_event(ctx->ctl,
MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
@@ -774,7 +761,8 @@
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
mdss_mdp_cmd_pingpong_done, ctl);
- ret = mdss_mdp_cmd_tearcheck_setup(ctl, 1);
+ ret = mdss_mdp_cmd_tearcheck_setup(ctl);
+
if (ret) {
pr_err("tearcheck setup failed\n");
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 4c1de32..e41bd49 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -446,8 +446,10 @@
if (ctx->polling_en) {
rc = mdss_mdp_video_pollwait(ctl);
} else {
+ mutex_unlock(&ctl->lock);
rc = wait_for_completion_timeout(&ctx->vsync_comp,
usecs_to_jiffies(VSYNC_TIMEOUT_US));
+ mutex_lock(&ctl->lock);
if (rc == 0) {
pr_warn("vsync wait timeout %d, fallback to poll mode\n",
ctl->num);
@@ -468,6 +470,21 @@
return rc;
}
+static void recover_underrun_work(struct work_struct *work)
+{
+ struct mdss_mdp_ctl *ctl =
+ container_of(work, typeof(*ctl), recover_work);
+
+ if (!ctl || !ctl->add_vsync_handler) {
+ pr_err("ctl or vsync handler is NULL\n");
+ return;
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ ctl->add_vsync_handler(ctl, &ctl->recover_underrun_handler);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
static void mdss_mdp_video_underrun_intr_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
@@ -479,6 +496,9 @@
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
pr_debug("display underrun detected for ctl=%d count=%d\n", ctl->num,
ctl->underrun_cnt);
+
+ if (ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE)
+ schedule_work(&ctl->recover_work);
}
static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_ctl *ctl, int new_fps)
@@ -801,6 +821,7 @@
spin_lock_init(&ctx->vsync_lock);
mutex_init(&ctx->vsync_mtx);
atomic_set(&ctx->vsync_ref, 0);
+ INIT_WORK(&ctl->recover_work, recover_underrun_work);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
mdss_mdp_video_vsync_intr_done, ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c8e4935..677389a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1146,14 +1146,18 @@
else
ret = mdss_mdp_display_commit(mdp5_data->ctl, NULL);
+ atomic_set(&mfd->kickoff_pending, 0);
+ wake_up_all(&mfd->kickoff_wait_q);
mutex_unlock(&mfd->lock);
if (IS_ERR_VALUE(ret))
goto commit_fail;
+ mutex_unlock(&mdp5_data->ov_lock);
mdss_mdp_overlay_update_pm(mdp5_data);
ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
+ mutex_lock(&mdp5_data->ov_lock);
if (ret == 0) {
mutex_lock(&mfd->lock);
@@ -1681,6 +1685,35 @@
mutex_unlock(&mdp5_data->ov_lock);
}
+static void remove_underrun_vsync_handler(struct work_struct *work)
+{
+ int rc;
+ struct mdss_mdp_ctl *ctl =
+ container_of(work, typeof(*ctl), remove_underrun_handler);
+
+ if (!ctl || !ctl->remove_vsync_handler) {
+ pr_err("ctl or vsync handler is NULL\n");
+ return;
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ rc = ctl->remove_vsync_handler(ctl,
+ &ctl->recover_underrun_handler);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
+static void mdss_mdp_recover_underrun_handler(struct mdss_mdp_ctl *ctl,
+ ktime_t t)
+{
+ if (!ctl) {
+ pr_err("ctl is NULL\n");
+ return;
+ }
+
+ mdss_mdp_ctl_reset(ctl);
+ schedule_work(&ctl->remove_underrun_handler);
+}
+
/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
ktime_t t)
@@ -2646,6 +2679,13 @@
mdss_mdp_overlay_handle_vsync;
ctl->vsync_handler.cmd_post_flush = false;
+ ctl->recover_underrun_handler.vsync_handler =
+ mdss_mdp_recover_underrun_handler;
+ ctl->recover_underrun_handler.cmd_post_flush = false;
+
+ INIT_WORK(&ctl->remove_underrun_handler,
+ remove_underrun_vsync_handler);
+
if (mfd->split_display && pdata->next) {
/* enable split display */
rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next);
@@ -3104,6 +3144,7 @@
goto init_fail;
}
mfd->mdp.private1 = mdp5_data;
+ mfd->wait_for_kickoff = true;
rc = mdss_mdp_overlay_fb_parse_dt(mfd);
if (rc)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index d1e5b52..6b497bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -181,6 +181,7 @@
#define MDSS_MDP_GAMUT_SIZE 0x5C
#define MDSS_MDP_IGC_DSPP_SIZE 0x28
#define MDSS_MDP_IGC_SSPP_SIZE 0x88
+#define MDSS_MDP_VIG_QSEED2_SHARP_SIZE 0x0C
#define TOTAL_BLEND_STAGES 0x4
#define PP_FLAGS_DIRTY_PA 0x1
@@ -789,9 +790,15 @@
unsigned long flags = 0;
char __iomem *offset;
struct mdss_data_type *mdata;
+ u32 current_opmode;
+ u32 csc_reset;
+ u32 dcm_state = DCM_UNINIT;
pr_debug("pnum=%x\n", pipe->num);
+ if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+ dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
mdata = mdss_mdp_get_mdata();
if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
(pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
@@ -825,6 +832,16 @@
pp_histogram_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer);
+ /* Update CSC state only if tuning mode is enable */
+ if (dcm_state == DTM_ENTER) {
+ /* Reset bit 16 to 19 for CSC_STATE in VIG_OP_MODE */
+ csc_reset = 0xFFF0FFFF;
+ current_opmode = readl_relaxed(pipe->base +
+ MDSS_MDP_REG_VIG_OP_MODE);
+ *op |= ((current_opmode & csc_reset) | opmode);
+ return 0;
+ }
+
if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) &&
(mdata->mdp_rev < MDSS_MDP_HW_REV_103)) {
@@ -910,10 +927,15 @@
u32 filter_mode;
struct mdss_data_type *mdata;
u32 src_w, src_h;
+ u32 dcm_state = DCM_UNINIT;
pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
pipe->scale.enable_pxl_ext);
mdata = mdss_mdp_get_mdata();
+
+ if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+ dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
filter_mode = MDSS_MDP_SCALE_FILTER_CA;
else
@@ -948,12 +970,13 @@
pipe->pp_cfg.sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
}
- if ((pipe->src_fmt->is_yuv) &&
- !((pipe->dst.w < src_w) || (pipe->dst.h < src_h))) {
- pp_sharp_config(pipe->base +
- MDSS_MDP_REG_VIG_QSEED2_SHARP,
- &pipe->pp_res.pp_sts,
- &pipe->pp_cfg.sharp_cfg);
+ if (dcm_state != DTM_ENTER &&
+ ((pipe->src_fmt->is_yuv) &&
+ !((pipe->dst.w < src_w) || (pipe->dst.h < src_h)))) {
+ pp_sharp_config(pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_SHARP,
+ &pipe->pp_res.pp_sts,
+ &pipe->pp_cfg.sharp_cfg);
}
if ((src_h != pipe->dst.h) ||
@@ -1155,10 +1178,23 @@
char __iomem *pipe_base;
u32 pipe_num;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ u32 current_opmode;
+ u32 dcm_state = DCM_UNINIT;
if (pipe == NULL)
return -EINVAL;
+ if (pipe->mixer && pipe->mixer->ctl && pipe->mixer->ctl->mfd)
+ dcm_state = pipe->mixer->ctl->mfd->dcm_state;
+
+ /* Read IGC state and update the same if tuning mode is enable */
+ if (dcm_state == DTM_ENTER) {
+ current_opmode = readl_relaxed(pipe->base +
+ MDSS_MDP_REG_SSPP_SRC_OP_MODE);
+ *op |= (current_opmode & BIT(16));
+ return ret;
+ }
+
/*
* TODO: should this function be responsible for masking multiple
* pipes to be written in dual pipe case?
@@ -4662,7 +4698,8 @@
break;
}
- for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+ for (stage = 0; stage < (mdss_res->nmixers_intf +
+ mdss_res->nmixers_wb); stage++)
if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
goto End;
@@ -4753,7 +4790,10 @@
} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
break;
- } else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+ /* QSEED2 range */
+ } else if ((ptr >= base + MDSS_MDP_REG_VIG_QSEED2_SHARP) &&
+ (ptr <= base + MDSS_MDP_REG_VIG_QSEED2_SHARP +
+ MDSS_MDP_VIG_QSEED2_SHARP_SIZE)) {
ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
break;
/* PA range */
@@ -4838,7 +4878,8 @@
int stage = 0;
struct mdss_mdp_mixer *mixer;
- for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+ for (counter = 0; counter < (mdss_res->nmixers_intf +
+ mdss_res->nmixers_wb); counter++) {
mixer = mdss_res->mixer_intf + counter;
base = mixer->base;
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
old mode 100644
new mode 100755
index 91e6373..8d6d41d
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -226,7 +226,7 @@
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
- pr_err("unable to mdss_mdp_smp_reserve rot data\n");
+ pr_debug("unable to mdss_mdp_smp_reserve rot data\n");
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 135a00a..c5ac72e 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -274,6 +274,17 @@
u32 lossy_mode_idx;
};
+struct mdss_mdp_pp_tear_check {
+ u32 tear_check_en;
+ u32 sync_cfg_height;
+ u32 vsync_init_val;
+ u32 sync_threshold_start;
+ u32 sync_threshold_continue;
+ u32 start_pos;
+ u32 rd_ptr_irq;
+ u32 refx100;
+};
+
struct mdss_panel_info {
u32 xres;
u32 yres;
@@ -316,6 +327,7 @@
u32 panel_power_on;
uint32_t panel_dead;
+ struct mdss_mdp_pp_tear_check te;
struct lcd_panel_info lcdc;
struct fbc_panel_info fbc;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index e53c350..2ed8a05 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -424,6 +424,8 @@
bool enable;
bool initialized;
bool in_progress;
+ /* freq. transitions are not allowed in invalid state */
+ bool invalid_state;
struct delayed_work work;
enum mmc_load state;
} clk_scaling;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec92e6..00eba66 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -119,6 +119,7 @@
NOTIFY_TYPE_NO_UPDATE,
NOTIFY_TYPE_SUSPEND,
NOTIFY_TYPE_UPDATE,
+ NOTIFY_TYPE_BL_UPDATE,
};
enum {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index d797797..0b95337 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -370,8 +370,18 @@
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
* %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
- * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
- * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ * %NL80211_ATTR_WIPHY_FREQ_HINT.
+ * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
+ * restrictions on BSS selection, i.e., they effectively prevent roaming
+ * within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT
+ * can be included to provide a recommendation of the initial BSS while
+ * allowing the driver to roam to other BSSes within the ESS and also to
+ * ignore this recommendation if the indicated BSS is not ideal. Only one
+ * set of BSSID,frequency parameters is used (i.e., either the enforcing
+ * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
* Background scan period can optionally be
* specified in %NL80211_ATTR_BG_SCAN_PERIOD,
* if not specified default background scan configuration
@@ -637,6 +647,12 @@
* (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
* This may also be sent as an event with the same attributes.
*
+ * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
+ * The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
+ * that attribute is not included, QoS mapping is disabled. Since this
+ * QoS mapping is relevant for IP packets, it is only valid during an
+ * association. This is cleared on disassociation and AP restart.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -807,6 +823,8 @@
NL80211_CMD_VENDOR,
+ NL80211_CMD_SET_QOS_MAP,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1446,6 +1464,23 @@
* @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
* info, containing a nested array of possible events
*
+ * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
+ * data is in the format defined for the payload of the QoS Map Set element
+ * in IEEE Std 802.11-2012, 8.4.2.97.
+ *
+ * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS
+ * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS
+ *
+ * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many
+ * associated stations are supported in AP mode (including P2P GO); u32.
+ * Since drivers may not have a fixed limit on the maximum number (e.g.,
+ * other concurrent operations may affect this), drivers are allowed to
+ * advertise values that cannot always be met. In such cases, an attempt
+ * to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
+ *
+ * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
+ * As specified in the &enum nl80211_tdls_peer_capability.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1773,6 +1808,15 @@
NL80211_ATTR_VENDOR_EVENTS,
+ NL80211_ATTR_QOS_MAP,
+
+ NL80211_ATTR_MAC_HINT,
+ NL80211_ATTR_WIPHY_FREQ_HINT,
+
+ NL80211_ATTR_MAX_AP_ASSOC_STA,
+
+ NL80211_ATTR_TDLS_PEER_CAPABILITY,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3256,4 +3300,20 @@
__u32 subcmd;
};
+/**
+ * enum nl80211_tdls_peer_capability - TDLS peer flags.
+ *
+ * Used by tdls_mgmt() to determine which conditional elements need
+ * to be added to TDLS Setup frames.
+ *
+ * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
+ * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
+ * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
+ */
+enum nl80211_tdls_peer_capability {
+ NL80211_TDLS_PEER_HT = 1<<0,
+ NL80211_TDLS_PEER_VHT = 1<<1,
+ NL80211_TDLS_PEER_WMM = 1<<2,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/usb/msm_ext_chg.h b/include/linux/usb/msm_ext_chg.h
index 596ab49..9dbac1c 100644
--- a/include/linux/usb/msm_ext_chg.h
+++ b/include/linux/usb/msm_ext_chg.h
@@ -36,4 +36,7 @@
/* To tell kernel about voltage request result */
#define MSM_USB_EXT_CHG_RESULT _IOW('M', 3, int)
+/* To tell kernel whether charger connected is external charger or not */
+#define MSM_USB_EXT_CHG_TYPE _IOW('M', 4, int)
+
#endif /* __LINUX_USB_MSM_EXT_CHG_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 195800f..4ecacc7 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -346,7 +346,10 @@
* @chg_check_timer: The timer used to implement the workaround to detect
* very slow plug in of wall charger.
* @ui_enabled: USB Intterupt is enabled or disabled.
- * @pm_done: Indicates whether USB is PM resumed
+ * @pm_done: It is used to increment the pm counter using pm_runtime_get_sync.
+ This handles the race case when PM resume thread returns before
+ the charger detection starts. When USB is disconnected pm_done
+ is set to true.
*/
struct msm_otg {
struct usb_phy phy;
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index 17df360..ff30988 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -64,7 +64,9 @@
US_FLAG(NO_READ_CAPACITY_16, 0x00080000) \
/* cannot handle READ_CAPACITY_16 */ \
US_FLAG(INITIAL_READ10, 0x00100000) \
- /* Initial READ(10) (and others) must be retried */
+ /* Initial READ(10) (and others) must be retried */ \
+ US_FLAG(TUR_AFTER_WRITE, 0x00200000) \
+ /* 5 TEST_UNIT_READY after 8 WRITE(10) */ \
#define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS };
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f0fb34c..8b833dd 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -58,6 +58,8 @@
* structures here describe these capabilities in detail.
*/
+#define TDLS_MGMT_VERSION2 1
+
/*
* wireless hardware capability structures
*/
@@ -1263,8 +1265,14 @@
*
* @channel: The channel to use or %NULL if not specified (auto-select based
* on scan results)
+ * @channel_hint: The channel of the recommended BSS for initial connection or
+ * %NULL if not specified
* @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
* results)
+ * @bssid_hint: The recommended AP BSSID for initial connection to the BSS or
+ * %NULL if not specified. Unlike the @bssid parameter, the driver is
+ * allowed to ignore this @bssid_hint if it has knowledge of a better BSS
+ * to use.
* @ssid: SSID
* @ssid_len: Length of ssid in octets
* @auth_type: Authentication type (algorithm)
@@ -1285,7 +1293,9 @@
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
+ struct ieee80211_channel *channel_hint;
u8 *bssid;
+ const u8 *bssid_hint;
u8 *ssid;
size_t ssid_len;
enum nl80211_auth_type auth_type;
@@ -1407,6 +1417,50 @@
};
/**
+ * struct cfg80211_dscp_exception - DSCP exception
+ *
+ * @dscp: DSCP value that does not adhere to the user priority range definition
+ * @up: user priority value to which the corresponding DSCP value belongs
+ */
+struct cfg80211_dscp_exception {
+ u8 dscp;
+ u8 up;
+};
+
+/**
+ * struct cfg80211_dscp_range - DSCP range definition for user priority
+ *
+ * @low: lowest DSCP value of this user priority range, inclusive
+ * @high: highest DSCP value of this user priority range, inclusive
+ */
+struct cfg80211_dscp_range {
+ u8 low;
+ u8 high;
+};
+
+/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
+#define IEEE80211_QOS_MAP_MAX_EX 21
+#define IEEE80211_QOS_MAP_LEN_MIN 16
+#define IEEE80211_QOS_MAP_LEN_MAX \
+ (IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
+
+/**
+ * struct cfg80211_qos_map - QoS Map Information
+ *
+ * This struct defines the Interworking QoS map setting for DSCP values
+ *
+ * @num_des: number of DSCP exceptions (0..21)
+ * @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
+ * the user priority DSCP range definition
+ * @up: DSCP range definition for a particular user priority
+ */
+struct cfg80211_qos_map {
+ u8 num_des;
+ struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
+ struct cfg80211_dscp_range up[8];
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1597,6 +1651,7 @@
* when number of MAC addresses entries is passed as 0. Drivers which
* advertise the support for MAC based ACL have to implement this callback.
*
+ * @set_qos_map: Set QoS mapping information to the driver
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1781,7 +1836,8 @@
int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len);
+ u16 status_code, u32 peer_capability,
+ const u8 *buf, size_t len);
int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, enum nl80211_tdls_operation oper);
@@ -1798,6 +1854,10 @@
int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
const struct cfg80211_acl_data *params);
+ int (*set_qos_map)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_qos_map *qos_map);
+
};
/*
@@ -2177,6 +2237,11 @@
* @n_vendor_commands: number of vendor commands
* @vendor_events: array of vendor events supported by the hardware
* @n_vendor_events: number of vendor events
+ *
+ * @max_ap_assoc_sta: maximum number of associated stations supported in AP mode
+ * (including P2P GO) or 0 to indicate no such limit is advertised. The
+ * driver is allowed to advertise a theoretical limit that it can reach in
+ * some cases, but may not always reach.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2285,6 +2350,8 @@
const struct nl80211_vendor_cmd_info *vendor_events;
int n_vendor_commands, n_vendor_events;
+ u16 max_ap_assoc_sta;
+
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
@@ -2705,8 +2772,10 @@
/**
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
* @skb: the data frame
+ * @qos_map: Interworking QoS mapping or %NULL if not in use
*/
-unsigned int cfg80211_classify8021d(struct sk_buff *skb);
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+ struct cfg80211_qos_map *qos_map);
/**
* cfg80211_find_ie - find information element in data
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1c6ea04..3b8b1cc 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -2264,6 +2264,7 @@
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
+#define VPM_TX_DM_RFECNS_COPP_TOPOLOGY 0x00010F86
/* Memory map regions command payload used by the
* #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 1635fc3..07199e0 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -180,6 +180,7 @@
int stream_id;
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
+ atomic_t unmap_cb_success;
};
void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
index bc91cba..87dde36 100644
--- a/mm/debug-pagealloc.c
+++ b/mm/debug-pagealloc.c
@@ -6,6 +6,14 @@
#include <linux/poison.h>
#include <linux/ratelimit.h>
+#ifndef mark_addr_rdonly
+#define mark_addr_rdonly(a)
+#endif
+
+#ifndef mark_addr_rdwrite
+#define mark_addr_rdwrite(a)
+#endif
+
static inline void set_page_poison(struct page *page)
{
__set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
@@ -27,6 +35,7 @@
set_page_poison(page);
memset(addr, PAGE_POISON, PAGE_SIZE);
+ mark_addr_rdonly(addr);
kunmap_atomic(addr);
}
@@ -82,6 +91,7 @@
addr = kmap_atomic(page);
check_poison_mem(addr, PAGE_SIZE);
+ mark_addr_rdwrite(addr);
clear_page_poison(page);
kunmap_atomic(addr);
}
diff --git a/net/ipv4/sysfs_net_ipv4.c b/net/ipv4/sysfs_net_ipv4.c
index 0cbbf10..699075a 100644
--- a/net/ipv4/sysfs_net_ipv4.c
+++ b/net/ipv4/sysfs_net_ipv4.c
@@ -53,6 +53,9 @@
CREATE_IPV4_FILE(tcp_rmem_def, sysctl_tcp_rmem[1]);
CREATE_IPV4_FILE(tcp_rmem_max, sysctl_tcp_rmem[2]);
+CREATE_IPV4_FILE(tcp_delack_seg, sysctl_tcp_delack_seg);
+CREATE_IPV4_FILE(tcp_use_userconfig, sysctl_tcp_use_userconfig);
+
static struct attribute *ipv4_attrs[] = {
&tcp_wmem_min_attr.attr,
&tcp_wmem_def_attr.attr,
@@ -60,6 +63,8 @@
&tcp_rmem_min_attr.attr,
&tcp_rmem_def_attr.attr,
&tcp_rmem_max_attr.attr,
+ &tcp_delack_seg_attr.attr,
+ &tcp_use_userconfig_attr.attr,
NULL
};
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 685553b..ff11148 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2440,8 +2440,8 @@
static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *extra_ies,
- size_t extra_ies_len)
+ u16 status_code, u32 peer_capability,
+ const u8 *extra_ies, size_t extra_ies_len)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 89511be..262c305 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -134,7 +134,7 @@
/* use the data classifier to determine what 802.1d tag the
* data frame has */
- skb->priority = cfg80211_classify8021d(skb);
+ skb->priority = cfg80211_classify8021d(skb, NULL);
return ieee80211_downgrade_queue(local, skb);
}
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index f6c74c9..6a77ffc 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -266,6 +266,9 @@
country DZ:
(2402 - 2482 @ 40), (N/A, 20)
+ (5150 - 5250 @ 80), (N/A, 23)
+ (5250 - 5350 @ 80), (N/A,23), DFS
+ (5470 - 5670 @ 80), (N/A, 20), DFS
country EC:
(2402 - 2482 @ 40), (N/A, 20)
@@ -416,8 +419,8 @@
country ID:
# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
- (2402 - 2482 @ 20), (N/A, 20)
- (5735 - 5815 @ 20), (N/A, 23)
+ (2402 - 2482 @ 20), (N/A, 30)
+ (5735 - 5815 @ 20), (N/A, 30)
country IE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 30f20fe..9890342 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -155,6 +155,10 @@
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;
+ if (rdev->ops->set_qos_map) {
+ rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+ }
+
/*
* Delete all the keys ... pairwise keys can't really
* exist any more anyway, but default keys might.
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index ba21ab2..c892cce 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -152,8 +152,12 @@
return -ENOTCONN;
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
- if (!err)
+ if (!err) {
wdev->mesh_id_len = 0;
+ if (rdev->ops->set_qos_map) {
+ rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+ }
+ }
return err;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4a3719b..c3adef8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -237,6 +237,11 @@
[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
+ [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
+ .len = IEEE80211_QOS_MAP_LEN_MAX },
+ [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
+ [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
+ [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -950,6 +955,7 @@
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
}
+ CMD(set_qos_map, SET_QOS_MAP);
#ifdef CONFIG_NL80211_TESTMODE
CMD(testmode_cmd, TESTMODE);
@@ -1088,6 +1094,11 @@
NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
dev->wiphy.max_acl_mac_addrs);
+ if (dev->wiphy.max_ap_assoc_sta &&
+ nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
+ dev->wiphy.max_ap_assoc_sta))
+ goto nla_put_failure;
+
if (dev->wiphy.n_vendor_commands) {
const struct nl80211_vendor_cmd_info *info;
struct nlattr *nested;
@@ -5530,6 +5541,9 @@
if (info->attrs[NL80211_ATTR_MAC])
connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ else if (info->attrs[NL80211_ATTR_MAC_HINT])
+ connect.bssid_hint =
+ nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -5554,6 +5568,14 @@
if (!connect.channel ||
connect.channel->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;
+ } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
+ connect.channel_hint =
+ ieee80211_get_channel(wiphy,
+ nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]));
+ if (!connect.channel_hint ||
+ connect.channel_hint->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
}
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
@@ -5693,6 +5715,7 @@
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
u8 action_code, dialog_token;
+ u32 peer_capability = 0;
u16 status_code;
u8 *peer;
@@ -5711,9 +5734,12 @@
action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+ if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
+ peer_capability =
+ nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
- dialog_token, status_code,
+ dialog_token, status_code, peer_capability,
nla_data(info->attrs[NL80211_ATTR_IE]),
nla_len(info->attrs[NL80211_ATTR_IE]));
}
@@ -6796,6 +6822,57 @@
}
EXPORT_SYMBOL(cfg80211_vendor_cmd_reply);
+static int nl80211_set_qos_map(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct cfg80211_qos_map *qos_map = NULL;
+ struct net_device *dev = info->user_ptr[1];
+ u8 *pos, len, num_des, des_len, des;
+ int ret;
+
+ if (!rdev->ops->set_qos_map)
+ return -EOPNOTSUPP;
+
+ if (info->attrs[NL80211_ATTR_QOS_MAP]) {
+ pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
+ len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
+
+ if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
+ len > IEEE80211_QOS_MAP_LEN_MAX)
+ return -EINVAL;
+
+ qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
+ if (!qos_map)
+ return -ENOMEM;
+
+ num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
+ if (num_des) {
+ des_len = num_des *
+ sizeof(struct cfg80211_dscp_exception);
+ memcpy(qos_map->dscp_exception, pos, des_len);
+ qos_map->num_des = num_des;
+ for (des = 0; des < num_des; des++) {
+ if (qos_map->dscp_exception[des].up > 7) {
+ kfree(qos_map);
+ return -EINVAL;
+ }
+ }
+ pos += des_len;
+ }
+ memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
+ }
+
+ wdev_lock(dev->ieee80211_ptr);
+ ret = nl80211_key_allowed(dev->ieee80211_ptr);
+ if (!ret)
+ ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ kfree(qos_map);
+ return ret;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -7408,6 +7485,14 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_QOS_MAP,
+ .doit = nl80211_set_qos_map,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1924758..1f547f9 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -345,6 +345,9 @@
struct reg_regdb_search_request *request;
const struct ieee80211_regdomain *curdom, *regdom;
int i, r;
+ bool set_reg = false;
+
+ mutex_lock(&cfg80211_mutex);
mutex_lock(®_regdb_search_mutex);
while (!list_empty(®_regdb_search_list)) {
@@ -360,9 +363,7 @@
r = reg_copy_regd(®dom, curdom);
if (r)
break;
- mutex_lock(&cfg80211_mutex);
- set_regdom(regdom);
- mutex_unlock(&cfg80211_mutex);
+ set_reg = true;
break;
}
}
@@ -370,6 +371,11 @@
kfree(request);
}
mutex_unlock(®_regdb_search_mutex);
+
+ if (set_reg)
+ set_regdom(regdom);
+
+ mutex_unlock(&cfg80211_mutex);
}
static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ab91446..87547ca 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -721,6 +721,10 @@
for (i = 0; i < 6; i++)
rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
+ if (rdev->ops->set_qos_map) {
+ rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+ }
+
#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 1284632..b83c5b2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -643,7 +643,8 @@
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
/* Given a data frame determine the 802.1p/1d tag to use. */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+ struct cfg80211_qos_map *qos_map)
{
unsigned int dscp;
@@ -666,6 +667,21 @@
return 0;
}
+ if (qos_map) {
+ unsigned int i, tmp_dscp = dscp >> 2;
+
+ for (i = 0; i < qos_map->num_des; i++) {
+ if (tmp_dscp == qos_map->dscp_exception[i].dscp)
+ return qos_map->dscp_exception[i].up;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (tmp_dscp >= qos_map->up[i].low &&
+ tmp_dscp <= qos_map->up[i].high)
+ return i;
+ }
+ }
+
return dscp >> 5;
}
EXPORT_SYMBOL(cfg80211_classify8021d);
@@ -819,6 +835,9 @@
dev->ieee80211_ptr->use_4addr = false;
dev->ieee80211_ptr->mesh_id_up_len = 0;
+ if (rdev->ops->set_qos_map) {
+ rdev->ops->set_qos_map(&rdev->wiphy, dev, NULL);
+ }
switch (otype) {
case NL80211_IFTYPE_ADHOC:
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index f59456e..61a0682 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -2519,6 +2519,29 @@
return 0;
}
+static int tapan_codec_rx_dem_select(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d %s\n", __func__, event, w->name);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (codec_ver == WCD9306)
+ snd_soc_update_bits(codec, TAPAN_A_CDC_RX2_B6_CTL,
+ 1 << 5, 1 << 5);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (codec_ver == WCD9306)
+ snd_soc_update_bits(codec, TAPAN_A_CDC_RX2_B6_CTL,
+ 1 << 5, 0);
+ break;
+ }
+
+ return 0;
+}
+
static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -4557,8 +4580,10 @@
SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
- NULL, 0),
+
+ SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, 0, 0, NULL,
+ 0, tapan_codec_rx_dem_select, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
&class_h_dsm_mux, tapan_codec_dsm_mux_event,
@@ -5064,7 +5089,7 @@
/* RX1 and RX2 defaults */
TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
- TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
+ TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0x80),
/* Heaset set Right from RX2 */
TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
@@ -5786,7 +5811,17 @@
const char *name)
{
int i;
- struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct wcd9xxx *core = NULL;
+
+ if (codec == NULL) {
+ dev_err(codec->dev, "%s: codec not initialized\n", __func__);
+ return NULL;
+ }
+ core = dev_get_drvdata(codec->dev->parent);
+ if (core == NULL) {
+ dev_err(codec->dev, "%s: core not initialized\n", __func__);
+ return NULL;
+ }
for (i = 0; i < core->num_of_supplies; i++) {
if (core->supplies[i].supply &&
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 50681f7..2b0c9d3 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4360,13 +4360,8 @@
static int taiko_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
pr_debug("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
- if ((taiko_core != NULL) &&
- (taiko_core->dev != NULL) &&
- (taiko_core->dev->parent != NULL))
- pm_runtime_get_sync(taiko_core->dev->parent);
return 0;
}
@@ -4374,15 +4369,8 @@
static void taiko_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
pr_debug("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
- if ((taiko_core != NULL) &&
- (taiko_core->dev != NULL) &&
- (taiko_core->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(taiko_core->dev->parent);
- pm_runtime_put(taiko_core->dev->parent);
- }
}
int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index b2ec347..34cb21a 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -188,7 +188,7 @@
static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
{
- return mbhc->polling_active;
+ return snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_EN_CTL) & 0x1;
}
static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
@@ -542,13 +542,13 @@
if (cfilt_mode.cur_mode_val
!= cfilt_mode.reg_mode_val) {
- if (mbhc->polling_active)
+ if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
wcd9xxx_pause_hs_polling(mbhc);
snd_soc_update_bits(codec,
mbhc->mbhc_bias_regs.cfilt_ctl,
cfilt_mode.reg_mask,
cfilt_mode.reg_mode_val);
- if (mbhc->polling_active)
+ if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
wcd9xxx_start_hs_polling(mbhc);
pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
cfilt_mode.cur_mode_val,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 077dbe3..a5c8f8d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -73,7 +73,7 @@
static int srs_alsa_ctrl_ever_called;
static int lsm_mux_slim_port;
static int slim0_rx_aanc_fb_port;
-static int msm_route_ec_ref_rx = 3; /* NONE */
+static int msm_route_ec_ref_rx = 7; /* NONE */
static uint32_t voc_session_id = ALL_SESSION_VSID;
static int msm_route_ext_ec_ref = AFE_PORT_INVALID;
@@ -1429,9 +1429,25 @@
msm_route_ec_ref_rx = 1;
ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
break;
+ case 2:
+ msm_route_ec_ref_rx = 2;
+ ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case 3:
+ msm_route_ec_ref_rx = 3;
+ ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case 4:
+ msm_route_ec_ref_rx = 4;
+ ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case 5:
+ msm_route_ec_ref_rx = 5;
+ ec_ref_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
default:
- msm_route_ec_ref_rx = 3; /* NONE */
- ec_ref_port_id = -1;
+ msm_route_ec_ref_rx = 6; /* NONE */
+ ec_ref_port_id = AFE_PORT_INVALID;
break;
}
adm_ec_ref_rx_id(ec_ref_port_id);
@@ -1441,16 +1457,46 @@
return 0;
}
-static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
- "NONE" };
+static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PRI_MI2S_TX",
+ "SEC_MI2S_TX", "TERT_MI2S_TX", "QUAT_MI2S_TX", "PROXY_RX", "NONE"};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
- SOC_ENUM_SINGLE_EXT(4, ec_ref_rx),
+ SOC_ENUM_SINGLE_EXT(8, ec_ref_rx),
};
-static const struct snd_kcontrol_new ec_ref_rx_mixer_controls[] = {
- SOC_ENUM_EXT("EC_REF_RX", msm_route_ec_ref_rx_enum[0],
- msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
-};
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul1 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL1 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL2 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul4 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL4 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul5 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL5 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul6 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL6 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul8 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL8 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL9 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -3573,7 +3619,20 @@
&slim0_rx_vi_fb_lch_mux),
SND_SOC_DAPM_MUX("VOC_EXT_EC MUX", SND_SOC_NOPM, 0, 0,
&voc_ext_ec_mux),
-
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL1 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul1),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL2 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul2),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL4 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul4),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL5 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul5),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL6 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul6),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL8 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul8),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul9),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -3895,6 +3954,63 @@
{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
{"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
+ {"AUDIO_REF_EC_UL1 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL1 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL2 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL2 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL4 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL5 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL5 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL6 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL6 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL8 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL8 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"AUDIO_REF_EC_UL9 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "I2S_RX" , "PRI_I2S_TX"},
+ {"AUDIO_REF_EC_UL9 MUX", "SLIM_RX" , "SLIMBUS_0_TX"},
+
+ {"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
+ {"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
+ {"MM_UL4", NULL, "AUDIO_REF_EC_UL4 MUX"},
+ {"MM_UL5", NULL, "AUDIO_REF_EC_UL5 MUX"},
+ {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
+ {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
+ {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
@@ -4423,10 +4539,6 @@
ARRAY_SIZE(dolby_dap_param_end_point_controls));
snd_soc_add_platform_controls(platform,
- ec_ref_rx_mixer_controls,
- ARRAY_SIZE(ec_ref_rx_mixer_controls));
-
- snd_soc_add_platform_controls(platform,
get_rms_controls,
ARRAY_SIZE(get_rms_controls));
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 2a6ce43..7b10815 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1167,7 +1167,8 @@
open.topology_id = topology;
if ((open.topology_id == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
- (open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+ (open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+ (open.topology_id == VPM_TX_DM_RFECNS_COPP_TOPOLOGY))
rate = 16000;
if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
@@ -1175,6 +1176,10 @@
rate = ULL_SUPPORTED_SAMPLE_RATE;
if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
channel_mode = ULL_MAX_SUPPORTED_CHANNEL;
+ } else if (perf_mode == LOW_LATENCY_PCM_MODE) {
+ if ((open.topology_id == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
+ (open.topology_id == SRS_TRUMEDIA_TOPOLOGY_ID))
+ open.topology_id = DEFAULT_COPP_TOPOLOGY;
}
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0d19657..4b9d079 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -676,8 +676,11 @@
while (cnt >= 0) {
if (port->buf[cnt].data) {
- msm_audio_ion_free(port->buf[cnt].client,
- port->buf[cnt].handle);
+ if (!rc)
+ msm_audio_ion_free(
+ port->buf[cnt].client,
+ port->buf[cnt].handle);
+
port->buf[cnt].client = NULL;
port->buf[cnt].handle = NULL;
port->buf[cnt].data = NULL;
@@ -723,7 +726,9 @@
(void *)&port->buf[0].phys,
(void *)port->buf[0].client,
(void *)port->buf[0].handle);
- msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+ if (!rc)
+ msm_audio_ion_free(port->buf[0].client,
+ port->buf[0].handle);
port->buf[0].client = NULL;
port->buf[0].handle = NULL;
}
@@ -1171,6 +1176,13 @@
if (payload[1] != 0) {
pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
__func__, payload[0], payload[1], sid);
+ if (payload[0] ==
+ ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+ atomic_set(&ac->unmap_cb_success, 0);
+ } else {
+ if (payload[0] ==
+ ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
+ atomic_set(&ac->unmap_cb_success, 1);
}
if (atomic_read(&ac->cmd_state)) {
@@ -3184,6 +3196,7 @@
TRUE, ((ac->session << 8) | dir));
atomic_set(&ac->cmd_state, 1);
mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mem_unmap.mem_map_handle = 0;
list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node,
list);
@@ -3195,6 +3208,12 @@
}
pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
__func__, mem_unmap.mem_map_handle);
+
+ if (mem_unmap.mem_map_handle == 0) {
+ pr_err("%s Do not send null mem handle to DSP\n", __func__);
+ rc = 0;
+ goto fail_cmd;
+ }
rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
if (rc < 0) {
pr_err("mem_unmap op[0x%x]rc[%d]\n",
@@ -3206,7 +3225,13 @@
rc = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5 * HZ);
if (!rc) {
- pr_err("timeout. waited for memory_unmap\n");
+ pr_err("%s timeout. waited for memory_unmap of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ } else if (atomic_read(&ac->unmap_cb_success) == 0) {
+ pr_err("%s Error in mem unmap callback of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
rc = -EINVAL;
goto fail_cmd;
}
@@ -3366,6 +3391,7 @@
port = &ac->port[dir];
buf_add = (uint32_t)port->buf->phys;
mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
+ mem_unmap.mem_map_handle = 0;
list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node,
list);
@@ -3378,6 +3404,12 @@
pr_debug("%s: mem_unmap-mem_map_handle: 0x%x",
__func__, mem_unmap.mem_map_handle);
+
+ if (mem_unmap.mem_map_handle == 0) {
+ pr_err("%s Do not send null mem handle to DSP\n", __func__);
+ rc = 0;
+ goto fail_cmd;
+ }
rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
if (rc < 0) {
pr_err("mmap_regions op[0x%x]rc[%d]\n",
@@ -3388,7 +3420,14 @@
rc = wait_event_timeout(ac->cmd_wait,
(atomic_read(&ac->cmd_state) == 0), 5*HZ);
if (!rc) {
- pr_err("timeout. waited for memory_unmap\n");
+ pr_err("%s timeout. waited for memory_unmap of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ } else if (atomic_read(&ac->unmap_cb_success) == 0) {
+ pr_err("%s Error in mem unmap callback of handle 0x%x\n",
+ __func__, mem_unmap.mem_map_handle);
+ rc = -EINVAL;
goto fail_cmd;
}
rc = 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 56efb97..796d6b4 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2102,8 +2102,10 @@
{
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (!w) {
dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+ mutex_unlock(&dapm->card->dapm_mutex);
return -EINVAL;
}
@@ -2112,6 +2114,7 @@
w->force = 0;
dapm_mark_dirty(w, "pin configuration");
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
@@ -3101,7 +3104,7 @@
dev_dbg(rtd->dev, "rtd stream %d event %d\n", stream, event);
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
widget_stream_event(pdapm, rtd->cpu_dai->playback_aif, event);
widget_stream_event(cdapm, rtd->codec_dai->playback_aif, event);
@@ -3186,8 +3189,10 @@
{
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (!w) {
dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
+ mutex_unlock(&dapm->card->dapm_mutex);
return -EINVAL;
}
@@ -3195,6 +3200,7 @@
w->connected = 1;
w->force = 1;
dapm_mark_dirty(w, "force enable");
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}