Merge "msm: vidc: Add VP9 profile/level query support"
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index f4b6013..70f1148 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -143,6 +143,9 @@
rendering thread is running on masked CPUs.
Bit 0 is for CPU-0, bit 1 is for CPU-1...
+- qcom,l2pc-update-queue:
+ Disables L2PC on masked CPUs at queue time when it's true.
+
- qcom,snapshot-size:
Specify the size of snapshot in bytes. This will override
snapshot size defined in the driver code.
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
deleted file mode 100644
index ed1ddf5..0000000
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
+++ /dev/null
@@ -1,180 +0,0 @@
-Qualcomm Technologies PNP Flash LED
-
-QPNP (Qualcomm Technologies Plug N Play) Flash LED (Light
-Emitting Diode) driver is used to provide illumination to
-camera sensor when background light is dim to capture good
-picture. It can also be used for flashlight/torch application.
-It is part of PMIC on Qualcomm Technologies reference platforms.
-The PMIC is connected to the host processor via SPMI bus.
-
-Required properties:
-- compatible : should be "qcom,qpnp-flash-led"
-- reg : base address and size for flash LED modules
-
-Optional properties:
-- qcom,headroom : headroom to use. Values should be 250, 300,
- 400 and 500 in mV.
-- qcom,startup-dly : delay before flashing after flash executed.
- Values should 10, 32, 64, and 128 in us.
-- qcom,clamp-curr : current to clamp at when voltage droop happens.
- Values are in integer from 0 to 1000 inclusive,
- indicating 0 to 1000 mA.
-- qcom,self-check-enabled : boolean type. self fault check enablement
-- qcom,thermal-derate-enabled : boolean type. derate enablement when module
- temperature reaches threshold
-- qcom,thermal-derate-threshold : thermal threshold for derate. Values
- should be 95, 105, 115, 125 in C.
-- qcom,thermal-derate-rate : derate rate when module temperature
- reaches threshold. Values should be
- "1_PERCENT", "1P25_PERCENT", "2_PERCENT",
- "2P5_PERCENT", "5_PERCENT" in string.
-- qcom,current-ramp-enabled : boolean type. stepped current ramp enablement
-- qcom,ramp-up-step : current ramp up rate. Values should be
- "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
- "6P7US", "13P5US", "27US".
-- qcom,ramp-dn-step : current ramp down rate. Values should be
- "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
- "6P7US", "13P5US", "27US".
-- qcom,vph-pwr-droop-enabled : boolean type. VPH power droop enablement. Enablement
- allows current clamp when phone power drops below
- pre-determined threshold
-- qcom,vph-pwr-droop-threshold : VPH power threshold for module to clamp current.
- Values are 2500 - 3200 in mV with 100 mV steps.
-- qcom,vph-pwr-droop-debounce-time : debounce time for module to confirm a voltage
- droop is happening. Values are 0, 10, 32, 64
- in us.
-- qcom,pmic-charger-support : Boolean type. This tells if flash utilizes charger boost
- support
-- qcom,headroom-sense-ch0-enabled: Boolean type. This configures headroom sensing enablement
- for LED channel 0
-- qcom,headroom-sense-ch1-enabled: Boolean type. This configures headroom sensing enablement
- for LED channel 1
-- qcom,power-detect-enabled : Boolean type. This enables driver to get maximum flash LED
- current at current battery level to avoid intensity clamp
- when battery voltage is low
-- qcom,otst2-moduled-enabled : Boolean type. This enables driver to enable MASK to support
- OTST2 connection.
-- qcom,follow-otst2-rb-disabled : Boolean type. This allows driver to reset/deset module.
- By default, driver resets module. This entry allows driver to
- bypass reset module sequence.
-- qcom,die-current-derate-enabled: Boolean type. This enables driver to get maximum flash LED
- current, based on PMIC die temperature threshold to
- avoid significant current derate from hardware. This property
- is not needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-vadc : VADC channel source for flash LED. This property is not
- needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-threshold : Integer type array for PMIC die temperature threshold.
- Array should have at least one value. Values should be in
- celcius. This property is not needed if PMIC is older than
- PMI8994v2.0.
-- qcom,die-temp-derate-current : Integer type arrray for PMIC die temperature derate
- current. Array should have at least one value. Values
- should be in mA. This property is not needed if PMIC is older
- than PMI8994v2.0.
-
-Required properties inside child node. Chile node contains settings for each individual LED.
-Each LED hardware needs a node for itself and a switch node to control brightness.
-For the purpose of turning on/off LED and better regulator control, "led:switch" node
-is introduced. "led:switch" acquires several existing properties from other nodes for
-operational simplification. For backward compatibility purpose, switch node can be optional:
-- label : type of led that will be used, either "flash" or "torch".
-- qcom,led-name : name of the LED. Accepted values are "led:flash_0",
- "led:flash_1", "led:torch_0", "led:torch_1"
-- qcom,default-led-trigger : trigger for the camera flash and torch. Accepted values are
- "flash0_trigger", "flash1_trigger", "torch0_trigger", torch1_trigger"
-- qcom,id : enumerated ID for each physical LED. Accepted values are "0",
- "1", etc..
-- qcom,max-current : maximum current allowed on this LED. Valid values should be
- integer from 0 to 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,pmic-revid : PMIC revision id source. This property is needed for PMI8996
- revision check.
-
-Optional properties inside child node:
-- qcom,current : default current intensity for LED. Accepted values should be
- integer from 0 t 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,duration : Duration for flash LED. When duration time expires, hardware will turn off
- flash LED. Values should be from 10 ms to 1280 ms with 10 ms incremental
- step. Not applicable to torch. It is required for LED:SWITCH node to handle
- LED used as flash.
-- reg<n> : reg<n> (<n> represents number. eg 0,1,2,..) property is to add support for
- multiple power sources. It includes two properties regulator-name and max-voltage.
- Required property inside regulator node:
- - regulator-name : This denotes this node is a regulator node and which
- regulator to use.
- Optional property inside regulator node:
- - max-voltage : This specifies max voltage of regulator. Some switch
- or boost regulator does not need this property.
-
-Example:
- qcom,leds@d300 {
- compatible = "qcom,qpnp-flash-led";
- status = "okay";
- reg = <0xd300 0x100>;
- label = "flash";
- qcom,headroom = <500>;
- qcom,startup-dly = <128>;
- qcom,clamp-curr = <200>;
- qcom,pmic-charger-support;
- qcom,self-check-enabled;
- qcom,thermal-derate-enabled;
- qcom,thermal-derate-threshold = <80>;
- qcom,thermal-derate-rate = "4_PERCENT";
- qcom,current-ramp-enabled;
- qcom,ramp_up_step = "27US";
- qcom,ramp_dn_step = "27US";
- qcom,vph-pwr-droop-enabled;
- qcom,vph-pwr-droop-threshold = <3200>;
- qcom,vph-pwr-droop-debounce-time = <10>;
- qcom,headroom-sense-ch0-enabled;
- qcom,headroom-sense-ch1-enabled;
- qcom,die-current-derate-enabled;
- qcom,die-temp-vadc = <&pmi8994_vadc>;
- qcom,die-temp-threshold = <85 80 75 70 65>;
- qcom,die-temp-derate-current = <400 800 1200 1600 2000>;
- qcom,pmic-revid = <&pmi8994_revid>;
-
- pm8226_flash0: qcom,flash_0 {
- label = "flash";
- qcom,led-name = "led:flash_0";
- qcom,default-led-trigger =
- "flash0_trigger";
- qcom,max-current = <1000>;
- qcom,id = <0>;
- qcom,duration = <1280>;
- qcom,current = <625>;
- };
-
- pm8226_torch: qcom,torch_0 {
- label = "torch";
- qcom,led-name = "led:torch_0";
- qcom,default-led-trigger =
- "torch0_trigger";
- boost-supply = <&pm8226_chg_boost>;
- qcom,max-current = <200>;
- qcom,id = <0>;
- qcom,current = <120>;
- qcom,max-current = <200>;
- reg0 {
- regulator-name =
- "pm8226_chg_boost";
- max-voltage = <3600000>;
- };
- };
-
- pm8226_switch: qcom,switch {
- lable = "switch";
- qcom,led-name = "led:switch";
- qcom,default-led-trigger =
- "switch_trigger";
- qcom,id = <2>;
- qcom,current = <625>;
- qcom,duration = <1280>;
- qcom,max-current = <1000>;
- reg0 {
- regulator-name =
- "pm8226_chg_boost";
- max-voltage = <3600000>;
- };
- };
- };
-
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
index dd8668c..8ee02bf 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
@@ -26,6 +26,9 @@
reg-names = "csiphy";
interrupts = <0 477 0>;
interrupt-names = "csiphy";
+ regulator-names = "gdscr", "refgen";
+ gdscr-supply = <&titan_top_gdsc>;
+ refgen-supply = <&refgen>;
clock-names = "camnoc_axi_clk", "soc_ahb_clk",
"slow_ahb_src_clk", "cpas_ahb_clk",
"cphy_rx_clk_src", "csiphy0_clk",
@@ -34,6 +37,5 @@
clock-rates =
<0 0 80000000 0 320000000 0 269333333 0 0 384000000>;
clock-cntl-level = "turbo";
- regulator-names = "gdscr";
status = "ok";
};
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
index 63da8ec..9798ac60 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
@@ -26,12 +26,10 @@
Value type: <prop-encoded-array>
Definition: Base address of the LCDB SPMI peripheral.
-- qcom,force-module-reenable
- Usage: required if using SW mode for module enable
- Value type: <bool>
- Definition: This enables the workaround to force enable
- the vph_pwr_2p5_ok signal required for
- turning on the LCDB module.
+- qcom,pmic-revid
+ Usage: required
+ Value type: <phandle>
+ Definition: Phandle to the PMIC's revid node
Touch-to-wake (TTW) properties:
@@ -211,6 +209,12 @@
Definition: Current limit (in mA) of the BOOST rail.
Possible values are 200 to 1600mA in 200mA steps.
+- qcom,bst-headroom-mv
+ Usage: optional
+ Value type: <u16>
+ Definition: Headroom of the boost (in mV). The minimum headroom is
+ 200mV and if not specified defaults to 200mV.
+
=======
Example
=======
@@ -252,5 +256,6 @@
qcom,bst-pd-strength = <1>;
qcom,bst-ps = <1>;
qcom,bst-ps-threshold-ma = <50>;
+ qcom,bst-headroom-mv = <200>;
};
};
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b5f9be7..6468b58 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -596,7 +596,7 @@
# selected platforms.
config ARCH_NR_GPIO
int
- default 1024 if ARCH_QCOM
+ default 1280 if ARCH_QCOM
default 256
help
Maximum number of GPIOs in the system.
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index ee7f735..c18ea56 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -44,9 +44,18 @@
sdm845-interposer-sdm670-cdp.dtb
endif
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+ dtbo-$(CONFIG_ARCH_SDM670) += \
+ sdm670-cdp-overlay.dtbo \
+ sdm670-mtp-overlay.dtbo
+
+sdm670-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-mtp-overlay.dtbo-base := sdm670.dtb
+else
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
sdm670-mtp.dtb \
sdm670-cdp.dtb
+endif
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
index ce849c6..d5dc94e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
@@ -27,7 +27,7 @@
qcom,mdss-dsi-lane-3-state;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
- qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+ qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
qcom,mdss-pan-physical-width-dimension = <71>;
qcom,mdss-pan-physical-height-dimension = <129>;
qcom,mdss-dsi-te-pin-select = <1>;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
index d3411c8..6a4200d 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
@@ -27,7 +27,7 @@
qcom,mdss-dsi-lane-3-state;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
- qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+ qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
qcom,mdss-pan-physical-width-dimension = <71>;
qcom,mdss-pan-physical-height-dimension = <129>;
qcom,mdss-dsi-tx-eot-append;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi
new file mode 100644
index 0000000..ceb6856
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi
@@ -0,0 +1,286 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+ dsi_sim_dsc_375_cmd: qcom,mdss_dsi_sim_dsc_375_cmd {
+ qcom,mdss-dsi-panel-name =
+ "Simulator cmd mode DSC 3.75:1 dsi panel";
+ qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,adjust-timer-wakeup-ms = <1>;
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-wr-mem-start = <0x2c>;
+ qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+ qcom,mdss-dsi-te-check-enable;
+ qcom,mdss-dsi-te-using-wd;
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0 {
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-width = <1440>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <8>;
+ qcom,mdss-dsi-v-front-porch = <10>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1e
+ 15 01 00 00 00 00 02 0b 73
+ 15 01 00 00 00 00 02 0c 73
+ 15 01 00 00 00 00 02 0e b0
+ 15 01 00 00 00 00 02 0f aE
+ 15 01 00 00 00 00 02 11 b8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5a 00
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 80
+ 15 01 00 00 00 00 02 5d 81
+ 15 01 00 00 00 00 02 5e 00
+ 15 01 00 00 00 00 02 5f 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1c
+ 15 01 00 00 00 00 02 01 0b
+ 15 01 00 00 00 00 02 02 0c
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0f
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8a
+ 15 01 00 00 00 00 02 0a 13
+ 15 01 00 00 00 00 02 0b 13
+ 15 01 00 00 00 00 02 0c 15
+ 15 01 00 00 00 00 02 0d 15
+ 15 01 00 00 00 00 02 0e 17
+ 15 01 00 00 00 00 02 0f 17
+ 15 01 00 00 00 00 02 10 1c
+ 15 01 00 00 00 00 02 11 0b
+ 15 01 00 00 00 00 02 12 0c
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0f
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8a
+ 15 01 00 00 00 00 02 1a 13
+ 15 01 00 00 00 00 02 1b 13
+ 15 01 00 00 00 00 02 1c 15
+ 15 01 00 00 00 00 02 1d 15
+ 15 01 00 00 00 00 02 1e 17
+ 15 01 00 00 00 00 02 1f 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6d
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 e0 00
+ 15 01 00 00 00 00 02 dc 21
+ 15 01 00 00 00 00 02 dd 22
+ 15 01 00 00 00 00 02 de 07
+ 15 01 00 00 00 00 02 df 07
+ 15 01 00 00 00 00 02 e3 6d
+ 15 01 00 00 00 00 02 e1 07
+ 15 01 00 00 00 00 02 e2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 d8
+ 15 01 00 00 00 00 02 2a 2a
+ /* CLK */
+ 15 01 00 00 00 00 02 4b 03
+ 15 01 00 00 00 00 02 4c 11
+ 15 01 00 00 00 00 02 4d 10
+ 15 01 00 00 00 00 02 4e 01
+ 15 01 00 00 00 00 02 4f 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5b 43
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5f 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7a 80
+ 15 01 00 00 00 00 02 7b 91
+ 15 01 00 00 00 00 02 7c d8
+ 15 01 00 00 00 00 02 7d 60
+ 15 01 00 00 00 00 02 7f 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 b3 c0
+ 15 01 00 00 00 00 02 b4 00
+ 15 01 00 00 00 00 02 b5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0a
+ 15 01 00 00 00 00 02 94 0a
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8a 00
+ 15 01 00 00 00 00 02 9b ff
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9d b0
+ 15 01 00 00 00 00 02 9f 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 ec 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 ff 10
+ /* VESA DSC PPS settings
+ * (1440x2560 slide 16H)
+ */
+ 39 01 00 00 00 00 11 c1 09
+ 20 00 10 02 00 02 68 01 bb
+ 00 0a 06 67 04 c5
+
+ 39 01 00 00 00 00 03 c2 10 f0
+ /* C0h = 0x0(2 Port SDC)
+ * 0x01(1 PortA FBC)
+ * 0x02(MTK) 0x03(1 PortA VESA)
+ */
+ 15 01 00 00 00 00 02 c0 03
+ /* VBP+VSA=,VFP = 10H */
+ 15 01 00 00 00 00 04 3b 03 0a 0a
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 e5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 bb 10
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 fb 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+
+ qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <720>;
+ qcom,mdss-dsc-slice-per-pkt = <2>;
+ qcom,mdss-dsc-bit-per-component = <10>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ timing@1 {
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <0>;
+ qcom,mdss-dsi-h-back-porch = <0>;
+ qcom,mdss-dsi-h-pulse-width = <0>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <0>;
+ qcom,mdss-dsi-v-front-porch = <0>;
+ qcom,mdss-dsi-v-pulse-width = <0>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command = [
+ 15 01 00 00 00 00 02 bb 10
+ 15 01 00 00 00 00 02 b0 03
+ 05 01 00 00 78 00 01 11
+ 15 01 00 00 00 00 02 51 ff
+ 15 01 00 00 00 00 02 53 24
+ 15 01 00 00 00 00 02 ff 23
+ 15 01 00 00 00 00 02 08 05
+ 15 01 00 00 00 00 02 46 90
+ 15 01 00 00 00 00 02 ff 10
+ 15 01 00 00 00 00 02 ff f0
+ 15 01 00 00 00 00 02 92 01
+ 15 01 00 00 00 00 02 ff 10
+ /* enable TE generation */
+ 15 01 00 00 00 00 02 35 00
+ 05 01 00 00 28 00 01 29];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 10 00 01 28
+ 05 01 00 00 40 00 01 10];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <540>;
+ qcom,mdss-dsc-slice-per-pkt = <2>;
+ qcom,mdss-dsc-bit-per-component = <10>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi
new file mode 100644
index 0000000..5d977e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi
@@ -0,0 +1,281 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+ dsi_dual_sim_dsc_375_cmd: qcom,mdss_dsi_dual_sim_dsc_375_cmd {
+ qcom,mdss-dsi-panel-name =
+ "Sim dual cmd mode DSC 3.75:1 dsi panel";
+ qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,cmd-sync-wait-broadcast;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-hor-line-idle = <0 40 256>,
+ <40 120 128>,
+ <120 240 64>;
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-te-pin-select = <1>;
+ qcom,mdss-dsi-wr-mem-start = <0x2c>;
+ qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+ qcom,mdss-dsi-te-dcs-command = <1>;
+ qcom,mdss-dsi-te-check-enable;
+ qcom,mdss-dsi-te-using-wd;
+ qcom,mdss-dsi-te-using-te-pin;
+ qcom,panel-ack-disabled;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0 {
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <3840>;
+ qcom,mdss-dsi-h-front-porch = <30>;
+ qcom,mdss-dsi-h-back-porch = <100>;
+ qcom,mdss-dsi-h-pulse-width = <4>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 11 91 09 20 00 20 02
+ 00 03 1c 04 21 00
+ 0f 03 19 01 97
+ 39 01 00 00 00 00 03 92 10 f0
+ 15 01 00 00 00 00 02 90 03
+ 15 01 00 00 00 00 02 03 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 04
+ 15 01 00 00 00 00 02 c0 03
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 07
+ 15 01 00 00 00 00 02 ef 01
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 00
+ 15 01 00 00 00 00 02 b4 01
+ 15 01 00 00 00 00 02 35 00
+ 39 01 00 00 00 00 06 f0 55 aa 52 08 01
+ 39 01 00 00 00 00 05 ff aa 55 a5 80
+ 15 01 00 00 00 00 02 6f 01
+ 15 01 00 00 00 00 02 f3 10
+ 39 01 00 00 00 00 05 ff aa 55 a5 00
+ /* sleep out + delay 120ms */
+ 05 01 00 00 78 00 01 11
+ /* display on + delay 120ms */
+ 05 01 00 00 78 00 01 29
+ ];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command =
+ [05 01 00 00 78 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <32>;
+ qcom,mdss-dsc-slice-width = <1080>;
+ qcom,mdss-dsc-slice-per-pkt = <1>;
+ qcom,mdss-dsc-bit-per-component = <10>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ timing@1 {
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <2560>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <7>;
+ qcom,mdss-dsi-v-front-porch = <8>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-on-command = [
+ /* CMD2_P0 */
+ 15 01 00 00 00 00 02 FF 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1E
+ 15 01 00 00 00 00 02 0B 73
+ 15 01 00 00 00 00 02 0C 73
+ 15 01 00 00 00 00 02 0E B0
+ 15 01 00 00 00 00 02 0F AE
+ 15 01 00 00 00 00 02 11 B8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5A 00
+ 15 01 00 00 00 00 02 5B 01
+ 15 01 00 00 00 00 02 5C 80
+ 15 01 00 00 00 00 02 5D 81
+ 15 01 00 00 00 00 02 5E 00
+ 15 01 00 00 00 00 02 5F 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
+ /* CMD2_P4 */
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1C
+ 15 01 00 00 00 00 02 01 0B
+ 15 01 00 00 00 00 02 02 0C
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0F
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8A
+ 15 01 00 00 00 00 02 0A 13
+ 15 01 00 00 00 00 02 0B 13
+ 15 01 00 00 00 00 02 0C 15
+ 15 01 00 00 00 00 02 0D 15
+ 15 01 00 00 00 00 02 0E 17
+ 15 01 00 00 00 00 02 0F 17
+ 15 01 00 00 00 00 02 10 1C
+ 15 01 00 00 00 00 02 11 0B
+ 15 01 00 00 00 00 02 12 0C
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0F
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8A
+ 15 01 00 00 00 00 02 1A 13
+ 15 01 00 00 00 00 02 1B 13
+ 15 01 00 00 00 00 02 1C 15
+ 15 01 00 00 00 00 02 1D 15
+ 15 01 00 00 00 00 02 1E 17
+ 15 01 00 00 00 00 02 1F 17
+ /* STV */
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6D
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
+ /* Vend */
+ 15 01 00 00 00 00 02 E0 00
+ 15 01 00 00 00 00 02 DC 21
+ 15 01 00 00 00 00 02 DD 22
+ 15 01 00 00 00 00 02 DE 07
+ 15 01 00 00 00 00 02 DF 07
+ 15 01 00 00 00 00 02 E3 6D
+ 15 01 00 00 00 00 02 E1 07
+ 15 01 00 00 00 00 02 E2 07
+ /* UD */
+ 15 01 00 00 00 00 02 29 D8
+ 15 01 00 00 00 00 02 2A 2A
+ /* CLK */
+ 15 01 00 00 00 00 02 4B 03
+ 15 01 00 00 00 00 02 4C 11
+ 15 01 00 00 00 00 02 4D 10
+ 15 01 00 00 00 00 02 4E 01
+ 15 01 00 00 00 00 02 4F 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
+ /* Reset XDONB */
+ 15 01 00 00 00 00 02 5B 43
+ 15 01 00 00 00 00 02 5C 00
+ 15 01 00 00 00 00 02 5F 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
+ /* Resolution:1440x2560*/
+ 15 01 00 00 00 00 02 72 02
+ /* mux */
+ 15 01 00 00 00 00 02 7A 80
+ 15 01 00 00 00 00 02 7B 91
+ 15 01 00 00 00 00 02 7C D8
+ 15 01 00 00 00 00 02 7D 60
+ 15 01 00 00 00 00 02 7F 15
+ 15 01 00 00 00 00 02 75 15
+ /* ABOFF */
+ 15 01 00 00 00 00 02 B3 C0
+ 15 01 00 00 00 00 02 B4 00
+ 15 01 00 00 00 00 02 B5 00
+ /* Source EQ */
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
+ /* FP BP */
+ 15 01 00 00 00 00 02 93 0A
+ 15 01 00 00 00 00 02 94 0A
+ /* Inversion Type */
+ 15 01 00 00 00 00 02 8A 00
+ 15 01 00 00 00 00 02 9B FF
+ /* IMGSWAP =1 @PortSwap=1 */
+ 15 01 00 00 00 00 02 9D B0
+ 15 01 00 00 00 00 02 9F 63
+ 15 01 00 00 00 00 02 98 10
+ /* FRM */
+ 15 01 00 00 00 00 02 EC 00
+ /* CMD1 */
+ 15 01 00 00 00 00 02 ff 10
+ /* VBP+VSA=,VFP = 10H */
+ 15 01 00 00 00 00 04 3B 03 0A 0A
+ /* FTE on */
+ 15 01 00 00 00 00 02 35 00
+ /* EN_BK =1(auto black) */
+ 15 01 00 00 00 00 02 E5 01
+ /* CMD mode(10) VDO mode(03) */
+ 15 01 00 00 00 00 02 BB 10
+ /* Non Reload MTP */
+ 15 01 00 00 00 00 02 FB 01
+ /* SlpOut + DispOn */
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
+ ];
+ qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+ 02 28 00 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,compression-mode = "dsc";
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <720>;
+ qcom,mdss-dsc-slice-per-pkt = <1>;
+ qcom,mdss-dsc-bit-per-component = <10>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
new file mode 100644
index 0000000..f0c820f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
new file mode 100644
index 0000000..c8537bc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dts b/arch/arm64/boot/dts/qcom/sdm670.dts
new file mode 100644
index 0000000..1d5e5e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670.dts
@@ -0,0 +1,21 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 SoC";
+ compatible = "qcom,sdm670";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 0dec428..f6cd37b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -21,6 +21,7 @@
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/soc/qcom,tcs-mbox.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
/ {
model = "Qualcomm Technologies, Inc. SDM670";
@@ -295,6 +296,13 @@
soc: soc { };
+ vendor: vendor {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -887,6 +895,13 @@
#reset-cells = <1>;
};
+ clock_aop: qcom,aopclk {
+ compatible = "qcom,aop-qmp-clk-v2";
+ #clock-cells = <1>;
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "qdss_clk";
+ };
+
slim_aud: slim@62dc0000 {
cell-index = <1>;
compatible = "qcom,slim-ngd";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 3a0e4b6..dddf1fb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -294,6 +294,18 @@
qcom,platform-reset-gpio = <&tlmm 6 0>;
};
+&dsi_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
&dsi_nt35597_truly_dsc_cmd_display {
qcom,dsi-display-active;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index d2189a7..c1fcb62 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1862,6 +1862,18 @@
clock-names = "apb_pclk";
};
+ cti0_swao:cti@6b04000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+ reg = <0x6b04000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti0-swao";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
turing_etm0 {
compatible = "qcom,coresight-remote-etm";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index c3e8b60..3d58dc1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -152,6 +152,18 @@
qcom,platform-reset-gpio = <&tlmm 6 0>;
};
+&dsi_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
&dsi_nt35597_truly_dsc_cmd_display {
qcom,dsi-display-active;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index f33e400..db3d23c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -12,8 +12,10 @@
#include "dsi-panel-sim-video.dtsi"
#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-sim-dsc375-cmd.dtsi"
#include "dsi-panel-sim-dualmipi-video.dtsi"
#include "dsi-panel-sim-dualmipi-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi"
#include "dsi-panel-sharp-dsc-4k-video.dtsi"
#include "dsi-panel-sharp-dsc-4k-cmd.dtsi"
#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi"
@@ -363,6 +365,42 @@
qcom,dsi-panel = <&dsi_dual_sim_cmd>;
};
+ dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_sim_dsc_375_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0>;
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>;
+ };
+
+ dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_sim_dsc_375_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>;
+ };
+
sde_wb: qcom,wb-display@0 {
compatible = "qcom,wb-display";
cell-index = <0>;
@@ -668,3 +706,43 @@
};
};
};
+
+&dsi_sim_dsc_375_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0 { /* 1080p */
+ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
+ 07 04 03 04 00];
+ qcom,display-topology = <1 1 1>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1 { /* qhd */
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 05 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0 { /* qhd */
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1 { /* 4k */
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index f721025..16d0988 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -375,7 +375,7 @@
MSM_BUS_SLAVE_EBI_CH0 240000 700000>,
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3_1 0 40000>;
- dwc3@a600000 {
+ dwc3@a800000 {
compatible = "snps,dwc3";
reg = <0x0a800000 0xcd00>;
interrupts = <0 138 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 13b5bfd..c42a7be 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -20,8 +20,9 @@
reg-cam-base = <0x65000>;
interrupts = <0 477 0>;
interrupt-names = "csiphy";
- regulator-names = "gdscr";
+ regulator-names = "gdscr", "refgen";
gdscr-supply = <&titan_top_gdsc>;
+ refgen-supply = <&refgen>;
csi-vdd-voltage = <1200000>;
mipi-csi-vdd-supply = <&pm8998_l26>;
mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -55,8 +56,9 @@
reg-cam-base = <0x66000>;
interrupts = <0 478 0>;
interrupt-names = "csiphy";
- regulator-names = "gdscr";
+ regulator-names = "gdscr", "refgen";
gdscr-supply = <&titan_top_gdsc>;
+ refgen-supply = <&refgen>;
csi-vdd-voltage = <1200000>;
mipi-csi-vdd-supply = <&pm8998_l26>;
mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -91,8 +93,9 @@
reg-cam-base = <0x67000>;
interrupts = <0 479 0>;
interrupt-names = "csiphy";
- regulator-names = "gdscr";
+ regulator-names = "gdscr", "refgen";
gdscr-supply = <&titan_top_gdsc>;
+ refgen-supply = <&refgen>;
csi-vdd-voltage = <1200000>;
mipi-csi-vdd-supply = <&pm8998_l26>;
mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -126,8 +129,9 @@
reg-cam-base = <0x68000>;
interrupts = <0 448 0>;
interrupt-names = "csiphy";
- regulator-names = "gdscr";
+ regulator-names = "gdscr", "refgen";
gdscr-supply = <&titan_top_gdsc>;
+ refgen-supply = <&refgen>;
csi-vdd-voltage = <1200000>;
mipi-csi-vdd-supply = <&pm8998_l26>;
mipi-dsi-vdd-supply = <&pm8998_l1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 35ac89f..314cfbb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -459,6 +459,16 @@
};
};
};
+
+ gpu_gx_domain_addr: syscon@0x5091508 {
+ compatible = "syscon";
+ reg = <0x5091508 0x4>;
+ };
+
+ gpu_gx_sw_reset: syscon@0x5091008 {
+ compatible = "syscon";
+ reg = <0x5091008 0x4>;
+ };
};
&clock_cpucc {
@@ -521,6 +531,26 @@
< 1689600000 0x40441058 0x00004646 0x2 17 >,
< 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+ qcom,pwrcl-speedbin1-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 403200000 0x500c0115 0x00002020 0x1 2 >,
+ < 480000000 0x50140219 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x401c0422 0x00002020 0x1 5 >,
+ < 748800000 0x401c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+ < 1228800000 0x402c0b40 0x00003333 0x2 12 >,
+ < 1324800000 0x40340c45 0x00003737 0x2 13 >,
+ < 1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+ < 1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+ < 1612800000 0x403c0f54 0x00004343 0x2 16 >,
+ < 1689600000 0x40441058 0x00004646 0x2 17 >,
+ < 1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
qcom,perfcl-speedbin0-v0 =
< 300000000 0x000c000f 0x00002020 0x1 1 >,
< 403200000 0x500c0115 0x00002020 0x1 2 >,
@@ -587,11 +617,16 @@
qcom,l3-memacc-level-vc-bin1 = <8 13>;
qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
+ qcom,pwrcl-memacc-level-vc-bin1 = <12 16>;
qcom,perfcl-memacc-level-vc-bin0 = <14 22>;
qcom,perfcl-memacc-level-vc-bin1 = <14 22>;
};
+&bwmon {
+ qcom,count-unit = <0x10000>;
+};
+
&clock_gcc {
compatible = "qcom,gcc-sdm845-v2", "syscon";
};
@@ -639,3 +674,232 @@
&mdss_mdp {
clock-max-rate = <0 0 0 0 430000000 19200000 0>;
};
+
+&energy_costs {
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 300000 11
+ 403200 17
+ 480000 21
+ 576000 26
+ 652800 31
+ 748800 37
+ 825600 42
+ 902400 47
+ 979200 52
+ 1056000 57
+ 1132800 62
+ 1228800 69
+ 1324800 78
+ 1420800 89
+ 1516800 103
+ 1612800 122
+ 1689600 140
+ 1766400 159
+ >;
+ idle-cost-data = <
+ 22 18 14 12
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 300000 130
+ 403200 480
+ 480000 730
+ 576000 1030
+ 652800 1260
+ 748800 1530
+ 825600 1740
+ 902400 1930
+ 979200 2110
+ 1056000 2290
+ 1132800 2460
+ 1209600 2630
+ 1286400 2800
+ 1363200 2980
+ 1459200 3240
+ 1536000 3490
+ 1612800 3780
+ 1689600 4120
+ 1766400 4530
+ 1843200 5020
+ 1920000 5590
+ 1996800 6230
+ 2092800 7120
+ 2169600 7870
+ 2246400 8620
+ 2323200 9330
+ 2400000 10030
+ 2476800 10830
+ 2553600 12080
+ 2630400 14580
+ 2707200 19960
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 300000 3
+ 403200 4
+ 480000 4
+ 576000 4
+ 652800 5
+ 748800 5
+ 825600 6
+ 902400 7
+ 979200 7
+ 1056000 8
+ 1132800 9
+ 1228800 9
+ 1324800 10
+ 1420800 11
+ 1516800 12
+ 1612800 13
+ 1689600 15
+ 1766400 17
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 300000 24
+ 403200 24
+ 480000 25
+ 576000 25
+ 652800 26
+ 748800 27
+ 825600 28
+ 902400 29
+ 979200 30
+ 1056000 32
+ 1132800 34
+ 1209600 37
+ 1286400 40
+ 1363200 45
+ 1459200 50
+ 1536000 57
+ 1612800 64
+ 1689600 74
+ 1766400 84
+ 1843200 96
+ 1920000 106
+ 1996800 113
+ 2092800 120
+ 2169600 125
+ 2246400 127
+ 2323200 130
+ 2400000 135
+ 2476800 140
+ 2553600 145
+ 2630400 150
+ 2707200 155
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+};
+
+&gpu_gx_gdsc {
+ domain-addr = <&gpu_gx_domain_addr>;
+ sw-reset = <&gpu_gx_sw_reset>;
+ qcom,reset-aon-logic;
+};
+
+/* GPU overrides */
+&msm_gpu {
+ /* Updated chip ID */
+ qcom,chipid = <0x06030001>;
+ qcom,initial-pwrlevel = <5>;
+
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <675000000>;
+ qcom,bus-freq = <12>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <12>;
+ };
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <596000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <520000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <10>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <414000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <342000000>;
+ qcom,bus-freq = <6>;
+ qcom,bus-min = <5>;
+ qcom,bus-max = <7>;
+ };
+
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <257000000>;
+ qcom,bus-freq = <4>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <0>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
+};
+
+&gmu {
+ qcom,gmu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gmu-pwrlevels";
+
+ qcom,gmu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gmu-freq = <500000000>;
+ };
+
+ qcom,gmu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gmu-freq = <200000000>;
+ };
+
+ qcom,gmu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gmu-freq = <0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 8105588..88f2e05d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -344,7 +344,7 @@
};
};
- energy-costs {
+ energy_costs: energy-costs {
compatible = "sched-energy";
CPU_COST_0: core-cost0 {
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 8e1a31b..636c982 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2444,6 +2444,10 @@
VERIFY(err, 0 == copy_from_user(&p.init, param, size));
if (err)
goto bail;
+ VERIFY(err, p.init.init.filelen >= 0 &&
+ p.init.init.memlen >= 0);
+ if (err)
+ goto bail;
VERIFY(err, 0 == fastrpc_init_process(fl, &p.init));
if (err)
goto bail;
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f93aba1..258a6f2 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -113,8 +113,8 @@
#define PLL_MIN_LVAL 0x21
#define PLL_MIN_FREQ_REG 0x94
-#define PLL_POST_DIV1 0x1F
-#define PLL_POST_DIV2 0x11F
+#define PLL_POST_DIV1 0x09
+#define PLL_POST_DIV2 0x109
#define PLL_MODE 0x0
#define PLL_L_VAL 0x4
#define PLL_USER_CTRL 0xc
@@ -134,8 +134,8 @@
#define ISENSE_OFF_DATA 0x0
#define CONSTANT_32 0x20
-#define APM_MX_MODE 0x0
-#define APM_APC_MODE 0x2
+#define APM_MX_MODE 0x4100000
+#define APM_APC_MODE 0x4100002
#define APM_READ_DATA_MASK 0xc
#define APM_MX_MODE_VAL 0x4
#define APM_APC_READ_VAL 0x8
@@ -563,7 +563,7 @@
{
struct clk_osm *cpuclk = to_clk_osm(hw);
- clk_osm_write_reg(cpuclk, 1, ENABLE_REG, OSM_BASE);
+ clk_osm_masked_write_reg(cpuclk, ENABLE_OSM, ENABLE_REG, ENABLE_OSM);
/* Make sure the write goes through before proceeding */
clk_osm_mb(cpuclk, OSM_BASE);
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 5633a8f..ae0325e 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -49,6 +49,7 @@
#include <asm/cpuidle.h>
#include "lpm-levels.h"
#include <trace/events/power.h>
+#include "../clk/clk.h"
#define CREATE_TRACE_POINTS
#include <trace/events/trace_msm_low_power.h>
@@ -980,6 +981,9 @@
if (suspend_in_progress && from_idle && level->notify_rpm)
continue;
+ if (level->is_reset && !system_sleep_allowed())
+ continue;
+
best_level = i;
if (from_idle &&
@@ -1042,7 +1046,8 @@
clear_predict_history();
clear_cl_predict_history();
- system_sleep_enter(us);
+ if (system_sleep_enter(us))
+ return -EBUSY;
}
/* Notify cluster enter event after successfully config completion */
cluster_notify(cluster, level, true);
@@ -1631,6 +1636,7 @@
* clocks that are enabled and preventing the system level
* LPMs(XO and Vmin).
*/
+ clock_debug_print_enabled();
psci_enter_sleep(lpm_cpu, idx, true);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 4dcf3b4..7e40cc6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -532,6 +532,20 @@
return rc;
}
+static void dp_display_clean(struct dp_display_private *dp)
+{
+ if (dp_display_is_hdcp_enabled(dp)) {
+ dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
+ if (dp->hdcp.ops->off)
+ dp->hdcp.ops->off(dp->hdcp.data);
+ }
+
+ dp->ctrl->push_idle(dp->ctrl);
+ dp->ctrl->off(dp->ctrl, false);
+}
+
static int dp_display_usbpd_disconnect_cb(struct device *dev)
{
int rc = 0;
@@ -560,20 +574,14 @@
drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
reinit_completion(&dp->notification_comp);
- if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
+ if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
pr_warn("timeout\n");
- /*
- * If a cable/dongle is connected to the TX device but
- * no sink device is connected, we call host
- * initialization where orientation settings are
- * configured. When the cable/dongle is disconnect,
- * call host de-initialization to make sure
- * we re-configure the orientation settings during
- * the next connect event.
- */
- if (!dp->power_on && dp->core_initialized)
- dp_display_host_deinit(dp);
+ if (dp->power_on)
+ dp_display_clean(dp);
+ }
+
+ dp_display_host_deinit(dp);
end:
return rc;
}
@@ -613,10 +621,8 @@
goto end;
}
- if (dp->usbpd->alt_mode_cfg_done) {
- dp_display_host_init(dp);
+ if (dp->usbpd->alt_mode_cfg_done)
dp_display_process_hpd_high(dp);
- }
end:
return rc;
}
@@ -831,8 +837,10 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (!dp->power_on || !dp->core_initialized)
+ goto error;
+
dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
- dp_display_host_deinit(dp);
dp->power_on = false;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 7e3d81f..8bf3471 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -25,34 +25,12 @@
DP_LANE_COUNT_4 = 4,
};
-enum phy_test_pattern {
- PHY_TEST_PATTERN_NONE,
- PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING,
- PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT,
- PHY_TEST_PATTERN_PRBS7,
- PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN,
- PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN,
-};
-
enum dynamic_range {
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,
};
-enum test_video_pattern {
- DP_TEST_VIDEO_PATTERN_NONE = 0x00,
- DP_TEST_VIDEO_PATTERN_COLOR_RAMPS = 0x01,
- DP_TEST_VIDEO_PATTERN_BW_VERT_LINES = 0x02,
- DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03,
-};
-
-enum dp_link_response {
- TEST_ACK = 0x1,
- TEST_NACK = 0x2,
- TEST_EDID_CHECKSUM_WRITE = 0x4,
-};
-
enum audio_sample_rate {
AUDIO_SAMPLE_RATE_32_KHZ = 0x00,
AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01,
@@ -125,7 +103,7 @@
* git bit depth value. This function assumes that bit depth has
* already been validated.
*/
-static inline u32 dp_link_bit_depth_to_bpp(enum test_bit_depth tbd)
+static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
{
u32 bpp;
@@ -156,19 +134,22 @@
static char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
{
switch (phy_test_pattern_sel) {
- case PHY_TEST_PATTERN_NONE:
- return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_NONE);
- case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
- return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING);
- case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ case DP_TEST_PHY_PATTERN_NONE:
+ return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
+ case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
return DP_LINK_ENUM_STR(
- PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
- case PHY_TEST_PATTERN_PRBS7:
- return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_PRBS7);
- case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
- return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN);
- case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
- return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN);
+ DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
+ case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
+ case DP_TEST_PHY_PATTERN_PRBS7:
+ return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
+ case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
+ case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN);
default:
return "unknown";
}
@@ -242,26 +223,16 @@
static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
{
int ret = 0;
- int const test_audio_period_ch_1_addr = 0x273;
- int const test_audio_period_ch_2_addr = 0x274;
- int const test_audio_period_ch_3_addr = 0x275;
- int const test_audio_period_ch_4_addr = 0x276;
- int const test_audio_period_ch_5_addr = 0x277;
- int const test_audio_period_ch_6_addr = 0x278;
- int const test_audio_period_ch_7_addr = 0x279;
- int const test_audio_period_ch_8_addr = 0x27A;
struct dp_link_request *req = &link->request;
- /* TEST_AUDIO_PERIOD_CH_1 (Byte 0x273) */
- ret = dp_link_get_period(link, test_audio_period_ch_1_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_1 = ret;
pr_debug("test_audio_period_ch_1 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_2 (Byte 0x274) */
- ret = dp_link_get_period(link, test_audio_period_ch_2_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);
if (ret == -EINVAL)
goto exit;
@@ -269,47 +240,42 @@
pr_debug("test_audio_period_ch_2 = 0x%x\n", ret);
/* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */
- ret = dp_link_get_period(link, test_audio_period_ch_3_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_3 = ret;
pr_debug("test_audio_period_ch_3 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_4 (Byte 0x276) */
- ret = dp_link_get_period(link, test_audio_period_ch_4_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_4 = ret;
pr_debug("test_audio_period_ch_4 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_5 (Byte 0x277) */
- ret = dp_link_get_period(link, test_audio_period_ch_5_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_5 = ret;
pr_debug("test_audio_period_ch_5 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_6 (Byte 0x278) */
- ret = dp_link_get_period(link, test_audio_period_ch_6_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_6 = ret;
pr_debug("test_audio_period_ch_6 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_7 (Byte 0x279) */
- ret = dp_link_get_period(link, test_audio_period_ch_7_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_7 = ret;
pr_debug("test_audio_period_ch_7 = 0x%x\n", ret);
- /* TEST_AUDIO_PERIOD_CH_8 (Byte 0x27A) */
- ret = dp_link_get_period(link, test_audio_period_ch_8_addr);
+ ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);
if (ret == -EINVAL)
goto exit;
@@ -326,12 +292,10 @@
u8 data;
int rlen;
int const param_len = 0x1;
- int const test_audio_pattern_type_addr = 0x272;
int const max_audio_pattern_type = 0x1;
- /* Read the requested audio pattern type (Byte 0x272). */
rlen = drm_dp_dpcd_read(link->aux->drm_aux,
- test_audio_pattern_type_addr, &bp, param_len);
+ DP_TEST_AUDIO_PATTERN_TYPE, &bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link audio mode data\n");
ret = -EINVAL;
@@ -360,14 +324,12 @@
u8 data;
int rlen;
int const param_len = 0x1;
- int const test_audio_mode_addr = 0x271;
int const max_audio_sampling_rate = 0x6;
int const max_audio_channel_count = 0x8;
int sampling_rate = 0x0;
int channel_count = 0x0;
- /* Read the requested audio mode (Byte 0x271). */
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_audio_mode_addr,
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_AUDIO_MODE,
&bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link audio mode data\n");
@@ -435,10 +397,10 @@
static bool dp_link_is_video_pattern_valid(u32 pattern)
{
switch (pattern) {
- case DP_TEST_VIDEO_PATTERN_NONE:
- case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
- case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
- case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
+ case DP_NO_TEST_PATTERN:
+ case DP_COLOR_RAMP:
+ case DP_BLACK_AND_WHITE_VERTICAL_LINES:
+ case DP_COLOR_SQUARE:
return true;
default:
return false;
@@ -448,14 +410,14 @@
static char *dp_link_video_pattern_to_string(u32 test_video_pattern)
{
switch (test_video_pattern) {
- case DP_TEST_VIDEO_PATTERN_NONE:
- return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_NONE);
- case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
- return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_RAMPS);
- case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
- return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_BW_VERT_LINES);
- case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
- return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_SQUARE);
+ case DP_NO_TEST_PATTERN:
+ return DP_LINK_ENUM_STR(DP_NO_TEST_PATTERN);
+ case DP_COLOR_RAMP:
+ return DP_LINK_ENUM_STR(DP_COLOR_RAMP);
+ case DP_BLACK_AND_WHITE_VERTICAL_LINES:
+ return DP_LINK_ENUM_STR(DP_BLACK_AND_WHITE_VERTICAL_LINES);
+ case DP_COLOR_SQUARE:
+ return DP_LINK_ENUM_STR(DP_COLOR_SQUARE);
default:
return "unknown";
}
@@ -575,7 +537,6 @@
u32 len = 1;
int rlen;
- /* Read the requested video link pattern (Byte 0x221). */
rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
if (rlen < 1) {
pr_err("failed to read 0x%x\n", addr);
@@ -601,11 +562,8 @@
u8 data;
u32 dyn_range;
int const param_len = 0x1;
- int const test_video_pattern_addr = 0x221;
- int const test_misc_addr = 0x232;
- /* Read the requested video link pattern (Byte 0x221). */
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_video_pattern_addr,
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PATTERN,
&bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link video pattern\n");
@@ -627,7 +585,7 @@
link->request.test_video_pattern));
/* Read the requested color bit depth and dynamic range (Byte 0x232) */
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_misc_addr,
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0,
&bp, param_len);
if (rlen < param_len) {
pr_err("failed to read link bit depth\n");
@@ -637,7 +595,7 @@
data = bp;
/* Dynamic Range */
- dyn_range = (data & BIT(3)) >> 3;
+ dyn_range = (data & DP_TEST_DYNAMIC_RANGE_CEA) >> 3;
if (!dp_link_is_dynamic_range_valid(dyn_range)) {
pr_err("invalid link dynamic range = 0x%x", dyn_range);
ret = -EINVAL;
@@ -650,8 +608,7 @@
link->request.test_dyn_range));
/* Color bit depth */
- data &= (BIT(5) | BIT(6) | BIT(7));
- data >>= 5;
+ data &= DP_TEST_BIT_DEPTH_MASK;
if (!dp_link_is_bit_depth_valid(data)) {
pr_err("invalid link bit depth = 0x%x\n", data);
ret = -EINVAL;
@@ -664,87 +621,87 @@
dp_link_bit_depth_to_string(link->request.test_bit_depth));
/* resolution timing params */
- ret = dp_link_parse_timing_params1(link, 0x222, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
&link->request.test_h_total);
if (ret) {
- pr_err("failed to parse test_h_total (0x222)\n");
+ pr_err("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n");
goto exit;
}
pr_debug("TEST_H_TOTAL = %d\n", link->request.test_h_total);
- ret = dp_link_parse_timing_params1(link, 0x224, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
&link->request.test_v_total);
if (ret) {
- pr_err("failed to parse test_v_total (0x224)\n");
+ pr_err("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n");
goto exit;
}
pr_debug("TEST_V_TOTAL = %d\n", link->request.test_v_total);
- ret = dp_link_parse_timing_params1(link, 0x226, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
&link->request.test_h_start);
if (ret) {
- pr_err("failed to parse test_h_start (0x226)\n");
+ pr_err("failed to parse test_h_start (DP_TEST_H_START_HI)\n");
goto exit;
}
pr_debug("TEST_H_START = %d\n", link->request.test_h_start);
- ret = dp_link_parse_timing_params1(link, 0x228, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
&link->request.test_v_start);
if (ret) {
- pr_err("failed to parse test_v_start (0x228)\n");
+ pr_err("failed to parse test_v_start (DP_TEST_V_START_HI)\n");
goto exit;
}
pr_debug("TEST_V_START = %d\n", link->request.test_v_start);
- ret = dp_link_parse_timing_params2(link, 0x22A, 2,
+ ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
&link->request.test_hsync_pol,
&link->request.test_hsync_width);
if (ret) {
- pr_err("failed to parse (0x22A)\n");
+ pr_err("failed to parse (DP_TEST_HSYNC_HI)\n");
goto exit;
}
pr_debug("TEST_HSYNC_POL = %d\n", link->request.test_hsync_pol);
pr_debug("TEST_HSYNC_WIDTH = %d\n", link->request.test_hsync_width);
- ret = dp_link_parse_timing_params2(link, 0x22C, 2,
+ ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
&link->request.test_vsync_pol,
&link->request.test_vsync_width);
if (ret) {
- pr_err("failed to parse (0x22C)\n");
+ pr_err("failed to parse (DP_TEST_VSYNC_HI)\n");
goto exit;
}
pr_debug("TEST_VSYNC_POL = %d\n", link->request.test_vsync_pol);
pr_debug("TEST_VSYNC_WIDTH = %d\n", link->request.test_vsync_width);
- ret = dp_link_parse_timing_params1(link, 0x22E, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
&link->request.test_h_width);
if (ret) {
- pr_err("failed to parse test_h_width (0x22E)\n");
+ pr_err("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n");
goto exit;
}
pr_debug("TEST_H_WIDTH = %d\n", link->request.test_h_width);
- ret = dp_link_parse_timing_params1(link, 0x230, 2,
+ ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
&link->request.test_v_height);
if (ret) {
- pr_err("failed to parse test_v_height (0x230)\n");
+ pr_err("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n");
goto exit;
}
pr_debug("TEST_V_HEIGHT = %d\n", link->request.test_v_height);
- ret = dp_link_parse_timing_params3(link, 0x233,
+ ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
&link->request.test_rr_d);
- link->request.test_rr_d &= BIT(0);
+ link->request.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
if (ret) {
- pr_err("failed to parse test_rr_d (0x233)\n");
+ pr_err("failed to parse test_rr_d (DP_TEST_MISC1)\n");
goto exit;
}
pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", link->request.test_rr_d);
- ret = dp_link_parse_timing_params3(link, 0x234,
+ ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
&link->request.test_rr_n);
if (ret) {
- pr_err("failed to parse test_rr_n (0x234)\n");
+ pr_err("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n");
goto exit;
}
pr_debug("TEST_REFRESH_NUMERATOR = %d\n", link->request.test_rr_n);
@@ -795,7 +752,6 @@
int rlen;
int const param_len = 0x1;
- /* Read the requested link rate (Byte 0x219). */
rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE,
&bp, param_len);
if (rlen < param_len) {
@@ -814,7 +770,6 @@
link->request.test_link_rate = data;
pr_debug("link rate = 0x%x\n", link->request.test_link_rate);
- /* Read the requested lane count (Byte 0x220). */
rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT,
&bp, param_len);
if (rlen < param_len) {
@@ -840,12 +795,12 @@
static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel)
{
switch (phy_test_pattern_sel) {
- case PHY_TEST_PATTERN_NONE:
- case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
- case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
- case PHY_TEST_PATTERN_PRBS7:
- case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
- case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
+ case DP_TEST_PHY_PATTERN_NONE:
+ case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+ case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ case DP_TEST_PHY_PATTERN_PRBS7:
+ case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+ case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
return true;
default:
return false;
@@ -865,10 +820,9 @@
u8 data;
int rlen;
int const param_len = 0x1;
- int const phy_test_pattern_addr = 0x248;
int ret = 0;
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, phy_test_pattern_addr,
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PHY_PATTERN,
&bp, param_len);
if (rlen < param_len) {
pr_err("failed to read phy link pattern\n");
@@ -892,12 +846,18 @@
static char *dp_link_get_test_name(u32 test_requested)
{
switch (test_requested) {
- case TEST_LINK_TRAINING: return DP_LINK_ENUM_STR(TEST_LINK_TRAINING);
- case TEST_VIDEO_PATTERN: return DP_LINK_ENUM_STR(TEST_VIDEO_PATTERN);
- case PHY_TEST_PATTERN: return DP_LINK_ENUM_STR(PHY_TEST_PATTERN);
- case TEST_EDID_READ: return DP_LINK_ENUM_STR(TEST_EDID_READ);
- case TEST_AUDIO_PATTERN: return DP_LINK_ENUM_STR(TEST_AUDIO_PATTERN);
- default: return "unknown";
+ case DP_TEST_LINK_TRAINING:
+ return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
+ case DP_TEST_LINK_VIDEO_PATTERN:
+ return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
+ case DP_TEST_LINK_EDID_READ:
+ return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
+ case DP_TEST_LINK_PHY_TEST_PATTERN:
+ return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
+ case DP_TEST_LINK_AUDIO_PATTERN:
+ return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
+ default:
+ return "unknown";
}
}
@@ -909,10 +869,12 @@
*/
static bool dp_link_is_video_audio_test_requested(u32 link)
{
- return (link == TEST_VIDEO_PATTERN) ||
- (link == (TEST_AUDIO_PATTERN | TEST_VIDEO_PATTERN)) ||
- (link == TEST_AUDIO_PATTERN) ||
- (link == (TEST_AUDIO_PATTERN | TEST_AUDIO_DISABLED_VIDEO));
+ return (link == DP_TEST_LINK_VIDEO_PATTERN) ||
+ (link == (DP_TEST_LINK_AUDIO_PATTERN |
+ DP_TEST_LINK_VIDEO_PATTERN)) ||
+ (link == DP_TEST_LINK_AUDIO_PATTERN) ||
+ (link == (DP_TEST_LINK_AUDIO_PATTERN |
+ DP_TEST_LINK_AUDIO_DISABLED_VIDEO));
}
/**
@@ -923,9 +885,9 @@
*/
static bool dp_link_is_test_supported(u32 test_requested)
{
- return (test_requested == TEST_LINK_TRAINING) ||
- (test_requested == TEST_EDID_READ) ||
- (test_requested == PHY_TEST_PATTERN) ||
+ return (test_requested == DP_TEST_LINK_TRAINING) ||
+ (test_requested == DP_TEST_LINK_EDID_READ) ||
+ (test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) ||
dp_link_is_video_audio_test_requested(test_requested);
}
@@ -961,9 +923,9 @@
pr_debug("device service irq vector = 0x%x\n", data);
- if (!(data & BIT(1))) {
+ if (!(data & DP_AUTOMATED_TEST_REQUEST)) {
pr_debug("no test requested\n");
- goto end;
+ return 0;
}
/**
@@ -988,14 +950,14 @@
pr_debug("%s (0x%x) requested\n", dp_link_get_test_name(data), data);
link->request.test_requested = data;
- if (link->request.test_requested == PHY_TEST_PATTERN) {
+ if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
ret = dp_link_parse_phy_test_params(link);
if (ret)
goto end;
ret = dp_link_parse_link_training_params(link);
}
- if (link->request.test_requested == TEST_LINK_TRAINING)
+ if (link->request.test_requested == DP_TEST_LINK_TRAINING)
ret = dp_link_parse_link_training_params(link);
if (dp_link_is_video_audio_test_requested(
@@ -1012,13 +974,13 @@
drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_REQUEST, buf, 1);
/**
- * Send a TEST_ACK if all link parameters are valid, otherwise send
- * a TEST_NACK.
+ * Send a DP_TEST_ACK if all link parameters are valid, otherwise send
+ * a DP_TEST_NAK.
*/
if (ret)
- link->request.response = TEST_NACK;
+ link->request.response = DP_TEST_NAK;
else
- link->request.response = TEST_ACK;
+ link->request.response = DP_TEST_ACK;
return ret;
}
@@ -1069,7 +1031,7 @@
static bool dp_link_is_link_training_requested(struct dp_link_private *link)
{
- return (link->request.test_requested == TEST_LINK_TRAINING);
+ return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
}
/**
@@ -1089,7 +1051,7 @@
return -EINVAL;
pr_debug("%s link rate = 0x%x, lane count = 0x%x\n",
- dp_link_get_test_name(TEST_LINK_TRAINING),
+ dp_link_get_test_name(DP_TEST_LINK_PHY_TEST_PATTERN),
link->request.test_link_rate,
link->request.test_lane_count);
@@ -1104,7 +1066,7 @@
struct dp_link_private *link = container_of(dp_link,
struct dp_link_private, dp_link);
- return (link->request.test_requested == PHY_TEST_PATTERN);
+ return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
}
static int dp_link_parse_vx_px(struct dp_link_private *link)
@@ -1112,15 +1074,14 @@
u8 bp;
u8 data;
int const param_len = 0x1;
- int const addr1 = 0x206;
- int const addr2 = 0x207;
int ret = 0;
u32 v0, p0, v1, p1, v2, p2, v3, p3;
int rlen;
pr_debug("\n");
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr1, &bp, param_len);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE0_1,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed reading lanes 0/1\n");
ret = -EINVAL;
@@ -1141,7 +1102,8 @@
p1 = data & 0x3;
data = data >> 2;
- rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr2, &bp, param_len);
+ rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE2_3,
+ &bp, param_len);
if (rlen < param_len) {
pr_err("failed reading lanes 2/3\n");
ret = -EINVAL;
@@ -1218,6 +1180,11 @@
return 0;
}
+static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
+{
+ return link_status[r - DP_LANE0_1_STATUS];
+}
+
/**
* dp_link_process_link_status_update() - processes link status updates
* @link: Display Port link module data
@@ -1231,7 +1198,8 @@
*/
static int dp_link_process_link_status_update(struct dp_link_private *link)
{
- if (!(link->link_status[2] & BIT(7)) || /* link status updated */
+ if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
+ DP_LINK_STATUS_UPDATED) || /* link status updated */
(drm_dp_clock_recovery_ok(link->link_status,
link->dp_link.lane_count) &&
drm_dp_channel_eq_ok(link->link_status,
@@ -1249,7 +1217,11 @@
static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link)
{
- return (link->link_status[2] & BIT(6)); /* port status changed */
+ if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
+ DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */
+ return true;
+
+ return false;
}
/**
@@ -1273,13 +1245,14 @@
static bool dp_link_is_video_pattern_requested(struct dp_link_private *link)
{
- return (link->request.test_requested & TEST_VIDEO_PATTERN)
- && !(link->request.test_requested & TEST_AUDIO_DISABLED_VIDEO);
+ return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN)
+ && !(link->request.test_requested &
+ DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
}
static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link)
{
- return (link->request.test_requested & TEST_AUDIO_PATTERN);
+ return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN);
}
/**
@@ -1298,7 +1271,7 @@
goto end;
pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n",
- dp_link_get_test_name(TEST_VIDEO_PATTERN),
+ dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN),
link->request.test_bit_depth,
dp_link_bit_depth_to_bpp(link->request.test_bit_depth),
dp_link_video_pattern_to_string(
@@ -1349,7 +1322,6 @@
{
link->request = (const struct dp_link_request){ 0 };
link->request.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
-
link->dp_link.test_requested = 0;
}
@@ -1381,19 +1353,19 @@
ret = dp_link_process_link_training_request(link);
if (!ret) {
- dp_link->test_requested |= TEST_LINK_TRAINING;
+ dp_link->test_requested |= DP_TEST_LINK_TRAINING;
goto exit;
}
ret = dp_link_process_phy_test_pattern_request(link);
if (!ret) {
- dp_link->test_requested |= PHY_TEST_PATTERN;
+ dp_link->test_requested |= DP_TEST_LINK_PHY_TEST_PATTERN;
goto exit;
}
ret = dp_link_process_link_status_update(link);
if (!ret) {
- dp_link->test_requested |= LINK_STATUS_UPDATED;
+ dp_link->test_requested |= DP_LINK_STATUS_UPDATED;
goto exit;
}
@@ -1405,13 +1377,13 @@
ret = dp_link_process_video_pattern_request(link);
if (!ret) {
- dp_link->test_requested |= TEST_VIDEO_PATTERN;
+ dp_link->test_requested |= DP_TEST_LINK_VIDEO_PATTERN;
goto exit;
}
ret = dp_link_process_audio_pattern_request(link);
if (!ret) {
- dp_link->test_requested |= TEST_AUDIO_PATTERN;
+ dp_link->test_requested |= DP_TEST_LINK_AUDIO_PATTERN;
goto exit;
}
@@ -1532,7 +1504,7 @@
static u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
{
- enum test_bit_depth tbd;
+ u32 tbd;
/*
* Few simplistic rules and assumptions made here:
@@ -1554,6 +1526,9 @@
break;
}
+ if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN)
+ tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
+
return tbd;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 8ea43da..419186f 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -31,27 +31,8 @@
DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_2,
};
-enum test_type {
- UNKNOWN_TEST = 0,
- TEST_LINK_TRAINING = 0x01,
- TEST_VIDEO_PATTERN = 0x02,
- PHY_TEST_PATTERN = 0x08,
- TEST_EDID_READ = 0x04,
- TEST_AUDIO_PATTERN = 0x20,
- TEST_AUDIO_DISABLED_VIDEO = 0x40,
-};
-
-enum status_update {
- LINK_STATUS_UPDATED = 0x100,
- DS_PORT_STATUS_CHANGED = 0x200,
-};
-
-enum test_bit_depth {
- DP_TEST_BIT_DEPTH_6 = 0x00,
- DP_TEST_BIT_DEPTH_8 = 0x01,
- DP_TEST_BIT_DEPTH_10 = 0x02,
- DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
-};
+#define DS_PORT_STATUS_CHANGED 0x200
+#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
struct dp_link {
u32 test_requested;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 33ef04b..5e47daf 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -142,11 +142,6 @@
{
struct msm_drm_private *priv;
- if (msm_is_suspend_blocked(dev)) {
- DRM_DEBUG("rejecting commit during suspend\n");
- return -EBUSY;
- }
-
priv = dev->dev_private;
if (priv && priv->kms && priv->kms->funcs &&
priv->kms->funcs->atomic_check)
@@ -1668,12 +1663,8 @@
static int msm_pm_suspend(struct device *dev)
{
struct drm_device *ddev;
- struct drm_modeset_acquire_ctx ctx;
- struct drm_connector *conn;
- struct drm_atomic_state *state;
- struct drm_crtc_state *crtc_state;
struct msm_drm_private *priv;
- int ret = 0;
+ struct msm_kms *kms;
if (!dev)
return -EINVAL;
@@ -1683,68 +1674,10 @@
return -EINVAL;
priv = ddev->dev_private;
- SDE_EVT32(0);
+ kms = priv->kms;
- /* acquire modeset lock(s) */
- drm_modeset_acquire_init(&ctx, 0);
-
-retry:
- ret = drm_modeset_lock_all_ctx(ddev, &ctx);
- if (ret)
- goto unlock;
-
- /* save current state for resume */
- if (priv->suspend_state)
- drm_atomic_state_free(priv->suspend_state);
- priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
- if (IS_ERR_OR_NULL(priv->suspend_state)) {
- DRM_ERROR("failed to back up suspend state\n");
- priv->suspend_state = NULL;
- goto unlock;
- }
-
- /* create atomic state to disable all CRTCs */
- state = drm_atomic_state_alloc(ddev);
- if (IS_ERR_OR_NULL(state)) {
- DRM_ERROR("failed to allocate crtc disable state\n");
- goto unlock;
- }
-
- state->acquire_ctx = &ctx;
- drm_for_each_connector(conn, ddev) {
-
- if (!conn->state || !conn->state->crtc ||
- conn->dpms != DRM_MODE_DPMS_ON)
- continue;
-
- /* force CRTC to be inactive */
- crtc_state = drm_atomic_get_crtc_state(state,
- conn->state->crtc);
- if (IS_ERR_OR_NULL(crtc_state)) {
- DRM_ERROR("failed to get crtc %d state\n",
- conn->state->crtc->base.id);
- drm_atomic_state_free(state);
- goto unlock;
- }
- crtc_state->active = false;
- }
-
- /* commit the "disable all" state */
- ret = drm_atomic_commit(state);
- if (ret < 0) {
- DRM_ERROR("failed to disable crtcs, %d\n", ret);
- drm_atomic_state_free(state);
- } else {
- priv->suspend_block = true;
- }
-
-unlock:
- if (ret == -EDEADLK) {
- drm_modeset_backoff(&ctx);
- goto retry;
- }
- drm_modeset_drop_locks(&ctx);
- drm_modeset_acquire_fini(&ctx);
+ if (kms && kms->funcs && kms->funcs->pm_suspend)
+ return kms->funcs->pm_suspend(dev);
/* disable hot-plug polling */
drm_kms_helper_poll_disable(ddev);
@@ -1756,7 +1689,7 @@
{
struct drm_device *ddev;
struct msm_drm_private *priv;
- int ret;
+ struct msm_kms *kms;
if (!dev)
return -EINVAL;
@@ -1766,26 +1699,10 @@
return -EINVAL;
priv = ddev->dev_private;
+ kms = priv->kms;
- SDE_EVT32(priv->suspend_state != NULL);
-
- drm_mode_config_reset(ddev);
-
- drm_modeset_lock_all(ddev);
-
- priv->suspend_block = false;
-
- if (priv->suspend_state) {
- priv->suspend_state->acquire_ctx =
- ddev->mode_config.acquire_ctx;
- ret = drm_atomic_commit(priv->suspend_state);
- if (ret < 0) {
- DRM_ERROR("failed to restore state, %d\n", ret);
- drm_atomic_state_free(priv->suspend_state);
- }
- priv->suspend_state = NULL;
- }
- drm_modeset_unlock_all(ddev);
+ if (kms && kms->funcs && kms->funcs->pm_resume)
+ return kms->funcs->pm_resume(dev);
/* enable hot-plug polling */
drm_kms_helper_poll_enable(ddev);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index c2f17c8..fc4d243 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -591,10 +591,6 @@
*/
struct task_struct *struct_mutex_task;
- /* saved atomic state during system suspend */
- struct drm_atomic_state *suspend_state;
- bool suspend_block;
-
/* list of clients waiting for events */
struct list_head client_event_list;
@@ -605,12 +601,14 @@
struct dentry *debug_root;
};
+/* get struct msm_kms * from drm_device * */
+#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \
+ ((struct msm_drm_private *)((D)->dev_private))->kms : NULL)
+
struct msm_format {
uint32_t pixel_format;
};
-int msm_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state);
/* callback from wq once fence has passed: */
struct msm_fence_cb {
struct work_struct work;
@@ -625,25 +623,6 @@
(_cb)->func = _func; \
} while (0)
-static inline bool msm_is_suspend_state(struct drm_device *dev)
-{
- if (!dev || !dev->dev_private)
- return false;
-
- return ((struct msm_drm_private *)dev->dev_private)->suspend_state != 0;
-}
-
-static inline bool msm_is_suspend_blocked(struct drm_device *dev)
-{
- if (!dev || !dev->dev_private)
- return false;
-
- if (!msm_is_suspend_state(dev))
- return false;
-
- return ((struct msm_drm_private *)dev->dev_private)->suspend_block != 0;
-}
-
int msm_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state, bool nonblock);
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index e7fae38..76523c7 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -93,6 +93,9 @@
void (*lastclose)(struct msm_kms *kms);
int (*register_events)(struct msm_kms *kms,
struct drm_mode_object *obj, u32 event, bool en);
+ /* pm suspend/resume hooks */
+ int (*pm_suspend)(struct device *dev);
+ int (*pm_resume)(struct device *dev);
/* cleanup: */
void (*destroy)(struct msm_kms *kms);
/* get address space */
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index 9a53e56..d257a8c 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -95,6 +95,22 @@
};
/**
+ * msm_property_index_to_drm_property - get drm property struct from prop index
+ * @info: Pointer to property info container struct
+ * @property_idx: Property index
+ * Returns: drm_property pointer associated with property index
+ */
+static inline
+struct drm_property *msm_property_index_to_drm_property(
+ struct msm_property_info *info, uint32_t property_idx)
+{
+ if (!info || property_idx >= info->property_count)
+ return NULL;
+
+ return info->property_array[property_idx];
+}
+
+/**
* msm_property_get_default - query default value of a property
* @info: Pointer to property info container struct
* @property_idx: Property index
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 447a6c3..946adbb 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -903,7 +903,18 @@
}
/* signal connector's retire fence */
- sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, 0);
+ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
+}
+
+void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
+{
+ if (!connector) {
+ SDE_ERROR("invalid connector\n");
+ return;
+ }
+
+ /* signal connector's retire fence */
+ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
}
static enum drm_connector_status
@@ -980,6 +991,39 @@
return rc;
}
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+ struct drm_atomic_state *atomic_state,
+ uint32_t property_idx, uint64_t value)
+{
+ struct drm_connector_state *state;
+ struct drm_property *property;
+ struct sde_connector *c_conn;
+
+ if (!connector || !atomic_state) {
+ SDE_ERROR("invalid argument(s), conn %d, state %d\n",
+ connector != NULL, atomic_state != NULL);
+ return -EINVAL;
+ }
+
+ c_conn = to_sde_connector(connector);
+ property = msm_property_index_to_drm_property(
+ &c_conn->property_info, property_idx);
+ if (!property) {
+ SDE_ERROR("invalid property index %d\n", property_idx);
+ return -EINVAL;
+ }
+
+ state = drm_atomic_get_connector_state(atomic_state, connector);
+ if (IS_ERR_OR_NULL(state)) {
+ SDE_ERROR("failed to get conn %d state\n",
+ connector->base.id);
+ return -EINVAL;
+ }
+
+ return drm_atomic_connector_set_property(
+ connector, state, property, value);
+}
+
#ifdef CONFIG_DEBUG_FS
/**
* sde_connector_init_debugfs - initialize connector debugfs
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 4747d3a..69c7e8b0 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -403,6 +403,20 @@
}
/**
+ * sde_connector_set_property_for_commit - add property set to atomic state
+ * Add a connector state property update for the specified property index
+ * to the atomic state in preparation for a drm_atomic_commit.
+ * @connector: Pointer to drm connector
+ * @atomic_state: Pointer to DRM atomic state structure for commit
+ * @property_idx: Connector property index
+ * @value: Updated property value
+ * Returns: Zero on success
+ */
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+ struct drm_atomic_state *atomic_state,
+ uint32_t property_idx, uint64_t value);
+
+/**
* sde_connector_init - create drm connector object for a given display
* @dev: Pointer to drm device struct
* @encoder: Pointer to associated encoder
@@ -435,6 +449,13 @@
void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
/**
+ * sde_connector_commit_reset - reset the completion signal
+ * @connector: Pointer to drm connector object
+ * @ts: timestamp to be updated in the fence signalling
+ */
+void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts);
+
+/**
* sde_connector_get_info - query display specific information
* @connector: Pointer to drm connector object
* @info: Pointer to msm display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index dfdfc1a..1402fdd 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -202,6 +202,44 @@
return ret;
}
+/**
+ * sde_core_irq_disable_nolock - disable core interrupt given by the index
+ * without lock
+ * @sde_kms: Pointer to sde kms context
+ * @irq_idx: interrupt index
+ */
+int sde_core_irq_disable_nolock(struct sde_kms *sde_kms, int irq_idx)
+{
+ int ret = 0;
+
+ if (!sde_kms || !sde_kms->hw_intr || !sde_kms->irq_obj.enable_counts) {
+ SDE_ERROR("invalid params\n");
+ return -EINVAL;
+ }
+
+ if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
+ SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx);
+ return -EINVAL;
+ }
+
+ SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx,
+ atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
+
+ SDE_EVT32(irq_idx,
+ atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
+ if (atomic_dec_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) {
+ ret = sde_kms->hw_intr->ops.disable_irq_nolock(
+ sde_kms->hw_intr,
+ irq_idx);
+ if (ret)
+ SDE_ERROR("Fail to disable IRQ for irq_idx:%d\n",
+ irq_idx);
+ SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
+ }
+
+ return ret;
+}
+
u32 sde_core_irq_read_nolock(struct sde_kms *sde_kms, int irq_idx, bool clear)
{
if (!sde_kms || !sde_kms->hw_intr ||
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h
index c32c19c..88061c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.h
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h
@@ -102,6 +102,19 @@
uint32_t irq_count);
/**
+ * sde_core_irq_disable_nolock - no lock version of sde_core_irq_disable
+ * @sde_kms: SDE handle
+ * @irq_idx: Irq index
+ * @return: 0 for success disabling IRQ, otherwise failure
+ *
+ * This function increments count on each enable and decrements on each
+ * disable. Interrupts is disabled if count is 0 after decrement.
+ */
+int sde_core_irq_disable_nolock(
+ struct sde_kms *sde_kms,
+ int irq_idx);
+
+/**
* sde_core_irq_read - IRQ helper function for reading IRQ status
* @sde_kms: SDE handle
* @irq_idx: irq index
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index b35af0d..d992a5b 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2041,7 +2041,7 @@
if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
SDE_ATRACE_BEGIN("signal_release_fence");
- sde_fence_signal(&sde_crtc->output_fence, fevent->ts, 0);
+ sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false);
SDE_ATRACE_END("signal_release_fence");
}
@@ -2868,7 +2868,7 @@
}
/* revert suspend actions, if necessary */
- if (msm_is_suspend_state(crtc->dev))
+ if (sde_kms_is_suspend_state(crtc->dev))
_sde_crtc_set_suspend(crtc, false);
/* remove previous state, if present */
@@ -2992,7 +2992,7 @@
struct sde_crtc_irq_info *node = NULL;
struct drm_event event;
u32 power_on;
- int ret;
+ int ret, i;
if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
SDE_ERROR("invalid crtc\n");
@@ -3004,7 +3004,7 @@
SDE_DEBUG("crtc%d\n", crtc->base.id);
- if (msm_is_suspend_state(crtc->dev))
+ if (sde_kms_is_suspend_state(crtc->dev))
_sde_crtc_set_suspend(crtc, true);
mutex_lock(&sde_crtc->crtc_lock);
@@ -3067,6 +3067,15 @@
sde_power_handle_unregister_event(&priv->phandle,
sde_crtc->power_event);
+ /**
+ * All callbacks are unregistered and frame done waits are complete
+ * at this point. No buffers are accessed by hardware.
+ * reset the fence timeline if there is any issue.
+ */
+ sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true);
+ for (i = 0; i < cstate->num_connectors; ++i)
+ sde_connector_commit_reset(cstate->connectors[i], ktime_get());
+
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
sde_crtc->num_mixers = 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index d2637a4..edfef24 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -637,7 +637,7 @@
if (hw_mdptop->ops.setup_split_pipe)
hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
- } else {
+ } else if (sde_enc->hw_pp[0]) {
/*
* slave encoder
* - determine split index from master index,
@@ -2277,6 +2277,11 @@
return;
}
+ if (!phys->hw_pp) {
+ SDE_ERROR("invalid pingpong hw\n");
+ return;
+ }
+
ctl = phys->hw_ctl;
if (!ctl || !ctl->ops.trigger_flush) {
SDE_ERROR("missing trigger cb\n");
@@ -2318,7 +2323,12 @@
struct sde_hw_ctl *ctl;
if (!phys) {
- SDE_ERROR("invalid encoder\n");
+ SDE_ERROR("invalid argument(s)\n");
+ return;
+ }
+
+ if (!phys->hw_pp) {
+ SDE_ERROR("invalid pingpong hw\n");
return;
}
@@ -2580,7 +2590,7 @@
bool active;
phys = sde_enc->phys_encs[i];
- if (!phys || !phys->ops.update_split_role)
+ if (!phys || !phys->ops.update_split_role || !phys->hw_pp)
continue;
active = test_bit(i, ¶ms->affected_displays);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 23604bd..70a25dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -131,6 +131,9 @@
struct sde_hw_ctl *ctl;
u32 flush_mask = 0;
+ if (!phys_enc)
+ return;
+
ctl = phys_enc->hw_ctl;
if (!ctl || !ctl->ops.get_bitmask_intf ||
!ctl->ops.update_pending_flush)
@@ -151,6 +154,9 @@
struct sde_hw_ctl *ctl;
struct sde_hw_intf_cfg intf_cfg = { 0 };
+ if (!phys_enc)
+ return;
+
ctl = phys_enc->hw_ctl;
if (!ctl || !ctl->ops.setup_intf_cfg)
return;
@@ -410,6 +416,9 @@
| SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
bool do_log = false;
+ if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl)
+ return -EINVAL;
+
cmd_enc->pp_timeout_report_cnt++;
if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) {
frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;
@@ -603,7 +612,7 @@
int ret = 0;
int refcount;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return -EINVAL;
}
@@ -695,7 +704,7 @@
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- if (!phys_enc) {
+ if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
return;
}
@@ -991,8 +1000,8 @@
struct sde_encoder_wait_info wait_info;
int ret;
- if (!phys_enc) {
- SDE_ERROR("invalid encoder\n");
+ if (!phys_enc || !phys_enc->hw_ctl) {
+ SDE_ERROR("invalid argument(s)\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 7850cb7..b7d6284 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -385,6 +385,9 @@
return;
hw_ctl = phys_enc->hw_ctl;
+ if (!hw_ctl)
+ return;
+
SDE_ATRACE_BEGIN("vblank_irq");
/* signal only for master, where there is a pending kickoff */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 2b736e5..afef192 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -156,10 +156,18 @@
struct drm_framebuffer *fb, const struct sde_format *format,
struct sde_rect *wb_roi)
{
- struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
- struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
+ struct sde_hw_cdm *hw_cdm;
+ struct sde_hw_cdm_cfg *cdm_cfg;
int ret;
+ if (!phys_enc || !format)
+ return;
+
+ cdm_cfg = &phys_enc->cdm_cfg;
+ hw_cdm = phys_enc->hw_cdm;
+ if (!hw_cdm)
+ return;
+
if (!SDE_FORMAT_IS_YUV(format)) {
SDE_DEBUG("[cdm_disable fmt:%x]\n",
format->base.pixel_format);
@@ -172,6 +180,9 @@
memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));
+ if (!wb_roi)
+ return;
+
cdm_cfg->output_width = wb_roi->w;
cdm_cfg->output_height = wb_roi->h;
cdm_cfg->output_fmt = format;
@@ -512,11 +523,18 @@
static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
- struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
- struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
+ struct sde_hw_wb *hw_wb;
+ struct sde_hw_ctl *hw_ctl;
+ struct sde_hw_cdm *hw_cdm;
u32 flush_mask = 0;
+ if (!phys_enc)
+ return;
+
+ hw_wb = wb_enc->hw_wb;
+ hw_ctl = phys_enc->hw_ctl;
+ hw_cdm = phys_enc->hw_cdm;
+
SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
if (!hw_ctl) {
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index b654e5a..b3bc28f 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -338,7 +338,8 @@
return rc;
}
-void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, bool is_error)
+void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
+ bool reset_timeline)
{
unsigned long flags;
struct sde_fence *fc, *next;
@@ -348,14 +349,25 @@
if (!ctx) {
SDE_ERROR("invalid ctx, %pK\n", ctx);
return;
- } else if (is_error) {
- return;
}
INIT_LIST_HEAD(&local_list_head);
spin_lock_irqsave(&ctx->lock, flags);
- if ((int)(ctx->done_count - ctx->commit_count) < 0) {
+ if (reset_timeline) {
+ if ((int)(ctx->done_count - ctx->commit_count) < 0) {
+ SDE_ERROR(
+ "timeline reset attempt! done count:%d commit:%d\n",
+ ctx->done_count, ctx->commit_count);
+ ctx->done_count = ctx->commit_count;
+ SDE_EVT32(ctx->drm_id, ctx->done_count,
+ ctx->commit_count, ktime_to_us(ts),
+ reset_timeline, SDE_EVTLOG_FATAL);
+ } else {
+ spin_unlock_irqrestore(&ctx->lock, flags);
+ return;
+ }
+ } else if ((int)(ctx->done_count - ctx->commit_count) < 0) {
++ctx->done_count;
SDE_DEBUG("fence_signal:done count:%d commit count:%d\n",
ctx->done_count, ctx->commit_count);
@@ -363,7 +375,7 @@
SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
ctx->done_count, ctx->commit_count);
SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
- ktime_to_us(ts), SDE_EVTLOG_FATAL);
+ ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL);
spin_unlock_irqrestore(&ctx->lock, flags);
return;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index 51afdae..029175b 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -128,10 +128,10 @@
* sde_fence_signal - advance fence timeline to signal outstanding fences
* @fence: Pointer fence container
* @ts: fence timestamp
- * @is_error: Set to non-zero if the commit didn't complete successfully
+ * @reset_timeline: reset the fence timeline to done count equal to commit count
*/
void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
- bool is_error);
+ bool reset_timeline);
#else
static inline void *sde_sync_get(uint64_t fd)
{
@@ -170,7 +170,7 @@
}
static inline void sde_fence_signal(struct sde_fence_context *fence,
- ktime_t ts, bool is_error)
+ ktime_t ts, bool reset_timeline)
{
/* do nothing */
}
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 2136f9c..6880f7b 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -22,6 +22,11 @@
#define SDE_UBWC_META_BLOCK_SIZE 256
#define SDE_UBWC_PLANE_SIZE_ALIGNMENT 4096
+#define SDE_TILE_HEIGHT_DEFAULT 1
+#define SDE_TILE_HEIGHT_TILED 4
+#define SDE_TILE_HEIGHT_UBWC 4
+#define SDE_TILE_HEIGHT_NV12 8
+
#define SDE_MAX_IMG_WIDTH 0x3FFF
#define SDE_MAX_IMG_HEIGHT 0x3FFF
@@ -48,9 +53,30 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
+#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \
+alpha, bp, flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_INTERLEAVED, \
+ .alpha_enable = alpha, \
+ .element = { (e0), (e1), (e2), (e3) }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = SDE_CHROMA_RGB, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = uc, \
+ .bpp = bp, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
+}
+
+
#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \
alpha, chroma, count, bp, flg, fm, np) \
{ \
@@ -66,7 +92,8 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
#define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \
@@ -83,7 +110,27 @@
.bpp = 2, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
+}
+
+#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \
+flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
}
#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\
@@ -100,9 +147,30 @@
.bpp = 2, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
+#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \
+flg, fm, np, th) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 1, \
+ .unpack_tight = 0, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = {(flg)}, \
+ .num_planes = np, \
+ .tile_height = th \
+}
+
+
#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \
flg, fm, np) \
{ \
@@ -118,7 +186,8 @@
.bpp = bp, \
.fetch_mode = fm, \
.flag = {(flg)}, \
- .num_planes = np \
+ .num_planes = np, \
+ .tile_height = SDE_TILE_HEIGHT_DEFAULT \
}
/*
@@ -414,75 +483,99 @@
* These tables hold the A5x tile formats supported.
*/
static const struct sde_format sde_format_map_tile[] = {
- INTERLEAVED_RGB_FMT(ARGB8888,
+ INTERLEAVED_RGB_FMT_TILED(BGR565,
+ 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ false, 2, 0,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(ABGR8888,
+ INTERLEAVED_RGB_FMT_TILED(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(RGBA8888,
+ INTERLEAVED_RGB_FMT_TILED(XBGR8888,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ false, 4, 0,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(RGBA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(BGRA8888,
+ INTERLEAVED_RGB_FMT_TILED(BGRA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(BGRX8888,
+ INTERLEAVED_RGB_FMT_TILED(BGRX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(XRGB8888,
+ INTERLEAVED_RGB_FMT_TILED(XRGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- INTERLEAVED_RGB_FMT(RGBX8888,
+ INTERLEAVED_RGB_FMT_TILED(RGBX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, 0,
- SDE_FETCH_UBWC, 1),
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
- PSEUDO_YUV_FMT(NV12,
+ INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, SDE_FORMAT_FLAG_DX,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, SDE_FORMAT_FLAG_DX,
+ SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
- PSEUDO_YUV_FMT(NV21,
+ PSEUDO_YUV_FMT_TILED(NV21,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C1_B_Cb,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_p010_tile[] = {
- PSEUDO_YUV_FMT_LOOSE(NV12,
+ PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_tp10_tile[] = {
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
};
/*
@@ -492,42 +585,42 @@
* the data will be passed by user-space.
*/
static const struct sde_format sde_format_map_ubwc[] = {
- INTERLEAVED_RGB_FMT(BGR565,
+ INTERLEAVED_RGB_FMT_TILED(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(ABGR8888,
+ INTERLEAVED_RGB_FMT_TILED(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(XBGR8888,
+ INTERLEAVED_RGB_FMT_TILED(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(ABGR2101010,
+ INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- INTERLEAVED_RGB_FMT(XBGR2101010,
+ INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 2),
+ SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV |
SDE_FORMAT_FLAG_COMPRESSED,
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_p010[] = {
@@ -539,21 +632,21 @@
};
static const struct sde_format sde_format_map_p010_ubwc[] = {
- PSEUDO_YUV_FMT_LOOSE(NV12,
+ PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
SDE_FORMAT_FLAG_COMPRESSED),
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
static const struct sde_format sde_format_map_tp10_ubwc[] = {
- PSEUDO_YUV_FMT(NV12,
+ PSEUDO_YUV_FMT_TILED(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
SDE_FORMAT_FLAG_COMPRESSED),
- SDE_FETCH_UBWC, 4),
+ SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
};
/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index b1772ed..0e1ab51 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -945,6 +945,7 @@
}
sblk->format_list = sde_cfg->vig_formats;
+ sblk->virt_format_list = sde_cfg->dma_formats;
}
static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
@@ -997,6 +998,7 @@
}
sblk->format_list = sde_cfg->dma_formats;
+ sblk->virt_format_list = NULL;
}
static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
@@ -1010,6 +1012,7 @@
sblk->maxupscale = SSPP_UNITY_SCALE;
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = sde_cfg->cursor_formats;
+ sblk->virt_format_list = NULL;
sspp->id = SSPP_CURSOR0 + *cursor_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
@@ -1025,6 +1028,7 @@
sblk->maxupscale = SSPP_UNITY_SCALE;
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = sde_cfg->dma_formats;
+ sblk->virt_format_list = sde_cfg->dma_formats;
sspp->id = SSPP_DMA0 + *dma_count;
sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index db5a6b4..fa10a88 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -395,6 +395,7 @@
* @danger_vblank: danger priority during vertical blanking
* @pixel_ram_size: size of latency hiding and de-tiling buffer in bytes
* @smart_dma_priority: hw priority of rect1 of multirect pipe
+ * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
* @src_blk:
* @scaler_blk:
* @csc_blk:
@@ -403,7 +404,7 @@
* @pcc_blk:
* @igc_blk:
* @format_list: Pointer to list of supported formats
- * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
+ * @virt_format_list: Pointer to list of supported formats for virtual planes
*/
struct sde_sspp_sub_blks {
u32 maxlinewidth;
@@ -425,6 +426,7 @@
struct sde_pp_blk igc_blk;
const struct sde_format_extended *format_list;
+ const struct sde_format_extended *virt_format_list;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 0b3432b..3b3854d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -357,6 +357,7 @@
SDE_REG_WRITE(c, CTL_LAYER(LM_0 + i), 0);
SDE_REG_WRITE(c, CTL_LAYER_EXT(LM_0 + i), 0);
SDE_REG_WRITE(c, CTL_LAYER_EXT2(LM_0 + i), 0);
+ SDE_REG_WRITE(c, CTL_LAYER_EXT3(LM_0 + i), 0);
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index 8eebf89fc..0aa7650 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -682,9 +682,89 @@
{ SDE_IRQ_TYPE_RESERVED, 0, 0, 7},
{ SDE_IRQ_TYPE_RESERVED, 0, 0, 7},
- /* irq_idx: 256-257 */
+ /* BEGIN MAP_RANGE: 256-287 AD4_0_INTR */
+ /* irq_idx: 256-259 */
{ SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_0, SDE_INTR_BACKLIGHT_UPDATED, 8},
- { SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_1, SDE_INTR_BACKLIGHT_UPDATED, 9}
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 260-263 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 264-267 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 268-271 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 272-275 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 276-279 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 280-283 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ /* irq_idx: 284-287 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+
+ /* BEGIN MAP_RANGE: 288-319 AD4_1_INTR */
+ /* irq_idx: 288-291 */
+ { SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_1, SDE_INTR_BACKLIGHT_UPDATED, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 292-295 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 296-299 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 300-303 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 304-307 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 308-311 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 312-315 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ /* irq_idx: 315-319 */
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+ { SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
};
static int sde_hw_intr_irqidx_lookup(enum sde_intr_type intr_type,
@@ -830,10 +910,9 @@
return 0;
}
-static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
+static int sde_hw_intr_disable_irq_nolock(struct sde_hw_intr *intr, int irq_idx)
{
int reg_idx;
- unsigned long irq_flags;
const struct sde_intr_reg *reg;
const struct sde_irq_type *irq;
const char *dbgstr = NULL;
@@ -851,7 +930,6 @@
reg_idx = irq->reg_idx;
reg = &sde_intr_set[reg_idx];
- spin_lock_irqsave(&intr->irq_lock, irq_flags);
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if ((cache_irq_mask & irq->irq_mask) == 0) {
dbgstr = "SDE IRQ is already cleared:";
@@ -869,7 +947,6 @@
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr,
irq->irq_mask, cache_irq_mask);
@@ -877,6 +954,25 @@
return 0;
}
+static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
+{
+ unsigned long irq_flags;
+
+ if (!intr)
+ return -EINVAL;
+
+ if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
+ pr_err("invalid IRQ index: [%d]\n", irq_idx);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&intr->irq_lock, irq_flags);
+ sde_hw_intr_disable_irq_nolock(intr, irq_idx);
+ spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
+
+ return 0;
+}
+
static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr)
{
int i;
@@ -1061,6 +1157,7 @@
ops->irq_idx_lookup = sde_hw_intr_irqidx_lookup;
ops->enable_irq = sde_hw_intr_enable_irq;
ops->disable_irq = sde_hw_intr_disable_irq;
+ ops->disable_irq_nolock = sde_hw_intr_disable_irq_nolock;
ops->dispatch_irqs = sde_hw_intr_dispatch_irq;
ops->clear_all_irqs = sde_hw_intr_clear_irqs;
ops->disable_all_irqs = sde_hw_intr_disable_irqs;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
index ced4077..0635b82 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
@@ -139,6 +139,16 @@
int irq_idx);
/**
+ * disable_irq_nolock - Disable IRQ based on IRQ index without lock
+ * @intr: HW interrupt handle
+ * @irq_idx: Lookup irq index return from irq_idx_lookup
+ * @return: 0 for success, otherwise failure
+ */
+ int (*disable_irq_nolock)(
+ struct sde_hw_intr *intr,
+ int irq_idx);
+
+ /**
* clear_all_irqs - Clears all the interrupts (i.e. acknowledges
* any asserted IRQs). Useful during reset.
* @intr: HW interrupt handle
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index e88f40f..ff796f7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -69,9 +69,13 @@
static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp,
struct sde_hw_tear_check *te)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
int cfg;
+ if (!pp || !te)
+ return -EINVAL;
+ c = &pp->hw;
+
cfg = BIT(19); /*VSYNC_COUNTER_EN */
if (te->hw_vsync_mode)
cfg |= BIT(20);
@@ -149,26 +153,38 @@
static void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_DSC_MODE, 1);
}
static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_DSC_MODE, 0);
}
static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
{
- struct sde_hw_blk_reg_map *pp_c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
int data;
- data = SDE_REG_READ(pp_c, PP_DCE_DATA_OUT_SWAP);
+ if (!pp)
+ return -EINVAL;
+ c = &pp->hw;
+
+ data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP);
data |= BIT(18); /* endian flip */
- SDE_REG_WRITE(pp_c, PP_DCE_DATA_OUT_SWAP, data);
+ SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data);
return 0;
}
@@ -225,7 +241,11 @@
static int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return -EINVAL;
+ c = &pp->hw;
SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
return 0;
@@ -257,9 +277,13 @@
static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
struct sde_hw_pp_vsync_info *info)
{
- struct sde_hw_blk_reg_map *c = &pp->hw;
+ struct sde_hw_blk_reg_map *c;
u32 val;
+ if (!pp || !info)
+ return -EINVAL;
+ c = &pp->hw;
+
val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL);
info->rd_ptr_init_val = val & 0xffff;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 8c9c4c7..4efddb4 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -1636,6 +1636,11 @@
sde_kms = to_sde_kms(kms);
dev = sde_kms->dev;
+ if (sde_kms_is_suspend_blocked(dev)) {
+ SDE_DEBUG("suspended, skip atomic_check\n");
+ return -EBUSY;
+ }
+
ret = drm_atomic_helper_check(dev, state);
if (ret)
return ret;
@@ -1674,6 +1679,170 @@
sde_kms->aspace[domain] : NULL;
}
+static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file)
+{
+ struct drm_device *dev = NULL;
+ struct sde_kms *sde_kms = NULL;
+
+ if (!kms) {
+ SDE_ERROR("invalid kms\n");
+ return;
+ }
+
+ sde_kms = to_sde_kms(kms);
+ dev = sde_kms->dev;
+
+ if (!dev) {
+ SDE_ERROR("invalid device\n");
+ return;
+ }
+
+ if (dev->mode_config.funcs->output_poll_changed)
+ dev->mode_config.funcs->output_poll_changed(dev);
+}
+
+static int sde_kms_pm_suspend(struct device *dev)
+{
+ struct drm_device *ddev;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector *conn;
+ struct drm_atomic_state *state;
+ struct sde_kms *sde_kms;
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ ddev = dev_get_drvdata(dev);
+ if (!ddev || !ddev_to_msm_kms(ddev))
+ return -EINVAL;
+
+ sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+ SDE_EVT32(0);
+
+ /* disable hot-plug polling */
+ drm_kms_helper_poll_disable(ddev);
+
+ /* acquire modeset lock(s) */
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+ ret = drm_modeset_lock_all_ctx(ddev, &ctx);
+ if (ret)
+ goto unlock;
+
+ /* save current state for resume */
+ if (sde_kms->suspend_state)
+ drm_atomic_state_free(sde_kms->suspend_state);
+ sde_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
+ if (IS_ERR_OR_NULL(sde_kms->suspend_state)) {
+ DRM_ERROR("failed to back up suspend state\n");
+ sde_kms->suspend_state = NULL;
+ goto unlock;
+ }
+
+ /* create atomic state to disable all CRTCs */
+ state = drm_atomic_state_alloc(ddev);
+ if (IS_ERR_OR_NULL(state)) {
+ DRM_ERROR("failed to allocate crtc disable state\n");
+ goto unlock;
+ }
+
+ state->acquire_ctx = &ctx;
+ drm_for_each_connector(conn, ddev) {
+ struct drm_crtc_state *crtc_state;
+ uint64_t lp;
+
+ if (!conn->state || !conn->state->crtc ||
+ conn->dpms != DRM_MODE_DPMS_ON)
+ continue;
+
+ lp = sde_connector_get_lp(conn);
+ if (lp == SDE_MODE_DPMS_LP1) {
+ /* transition LP1->LP2 on pm suspend */
+ ret = sde_connector_set_property_for_commit(conn, state,
+ CONNECTOR_PROP_LP, SDE_MODE_DPMS_LP2);
+ if (ret) {
+ DRM_ERROR("failed to set lp2 for conn %d\n",
+ conn->base.id);
+ drm_atomic_state_free(state);
+ goto unlock;
+ }
+ } else if (lp != SDE_MODE_DPMS_LP2) {
+ /* force CRTC to be inactive */
+ crtc_state = drm_atomic_get_crtc_state(state,
+ conn->state->crtc);
+ if (IS_ERR_OR_NULL(crtc_state)) {
+ DRM_ERROR("failed to get crtc %d state\n",
+ conn->state->crtc->base.id);
+ drm_atomic_state_free(state);
+ goto unlock;
+ }
+ crtc_state->active = false;
+ }
+ }
+
+ /* commit the "disable all" state */
+ ret = drm_atomic_commit(state);
+ if (ret < 0) {
+ DRM_ERROR("failed to disable crtcs, %d\n", ret);
+ drm_atomic_state_free(state);
+ } else {
+ sde_kms->suspend_block = true;
+ }
+
+unlock:
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return 0;
+}
+
+static int sde_kms_pm_resume(struct device *dev)
+{
+ struct drm_device *ddev;
+ struct sde_kms *sde_kms;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ ddev = dev_get_drvdata(dev);
+ if (!ddev || !ddev_to_msm_kms(ddev))
+ return -EINVAL;
+
+ sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+
+ SDE_EVT32(sde_kms->suspend_state != NULL);
+
+ drm_mode_config_reset(ddev);
+
+ drm_modeset_lock_all(ddev);
+
+ sde_kms->suspend_block = false;
+
+ if (sde_kms->suspend_state) {
+ sde_kms->suspend_state->acquire_ctx =
+ ddev->mode_config.acquire_ctx;
+ ret = drm_atomic_commit(sde_kms->suspend_state);
+ if (ret < 0) {
+ DRM_ERROR("failed to restore state, %d\n", ret);
+ drm_atomic_state_free(sde_kms->suspend_state);
+ }
+ sde_kms->suspend_state = NULL;
+ }
+ drm_modeset_unlock_all(ddev);
+
+ /* enable hot-plug polling */
+ drm_kms_helper_poll_enable(ddev);
+
+ return 0;
+}
+
static const struct msm_kms_funcs kms_funcs = {
.hw_init = sde_kms_hw_init,
.postinit = sde_kms_postinit,
@@ -1694,9 +1863,12 @@
.atomic_check = sde_kms_atomic_check,
.get_format = sde_get_msm_format,
.round_pixclk = sde_kms_round_pixclk,
+ .pm_suspend = sde_kms_pm_suspend,
+ .pm_resume = sde_kms_pm_resume,
.destroy = sde_kms_destroy,
.register_events = _sde_kms_register_events,
.get_address_space = _sde_kms_get_address_space,
+ .postopen = _sde_kms_post_open,
};
/* the caller api needs to turn on clock before calling it */
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 0cb7008..0ddfb30 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -198,6 +198,10 @@
struct sde_core_perf perf;
+ /* saved atomic state during system suspend */
+ struct drm_atomic_state *suspend_state;
+ bool suspend_block;
+
struct sde_rm rm;
bool rm_init;
@@ -228,6 +232,33 @@
bool sde_is_custom_client(void);
/**
+ * sde_kms_is_suspend_state - whether or not the system is pm suspended
+ * @dev: Pointer to drm device
+ * Return: Suspend status
+ */
+static inline bool sde_kms_is_suspend_state(struct drm_device *dev)
+{
+ if (!ddev_to_msm_kms(dev))
+ return false;
+
+ return to_sde_kms(ddev_to_msm_kms(dev))->suspend_state != NULL;
+}
+
+/**
+ * sde_kms_is_suspend_blocked - whether or not commits are blocked due to pm
+ * suspend status
+ * @dev: Pointer to drm device
+ * Return: True if commits should be rejected due to pm suspend
+ */
+static inline bool sde_kms_is_suspend_blocked(struct drm_device *dev)
+{
+ if (!sde_kms_is_suspend_state(dev))
+ return false;
+
+ return to_sde_kms(ddev_to_msm_kms(dev))->suspend_block;
+}
+
+/**
* Debugfs functions - extra helper functions for debugfs support
*
* Main debugfs documentation is located at,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ef799b4..40dad76 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -73,8 +73,6 @@
R_MAX
};
-#define TX_MODE_BUFFER_LINE_THRES 2
-
#define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
#define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
@@ -2616,14 +2614,28 @@
struct sde_plane *sde_plane[R_MAX];
const struct sde_format *fmt[R_MAX];
bool q16_data = true;
- int i, buffer_lines = TX_MODE_BUFFER_LINE_THRES;
+ int i, buffer_lines;
+ unsigned int max_tile_height = 1;
bool parallel_fetch_qualified = true;
+ bool has_tiled_rect = false;
for (i = 0; i < R_MAX; i++) {
const struct msm_format *msm_fmt;
- int width_threshold;
drm_state[i] = i ? plane->r1 : plane->r0;
+ msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
+ fmt[i] = to_sde_format(msm_fmt);
+
+ if (SDE_FORMAT_IS_UBWC(fmt[i])) {
+ has_tiled_rect = true;
+ if (fmt[i]->tile_height > max_tile_height)
+ max_tile_height = fmt[i]->tile_height;
+ }
+ }
+
+ for (i = 0; i < R_MAX; i++) {
+ int width_threshold;
+
pstate[i] = to_sde_plane_state(drm_state[i]);
sde_plane[i] = to_sde_plane(drm_state[i]->plane);
@@ -2645,8 +2657,6 @@
return -EINVAL;
}
- msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
- fmt[i] = to_sde_format(msm_fmt);
if (SDE_FORMAT_IS_YUV(fmt[i])) {
SDE_ERROR_PLANE(sde_plane[i],
"Unsupported format for multirect mode\n");
@@ -2661,7 +2671,7 @@
* width for tiled formats.
*/
width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth;
- if (SDE_FORMAT_IS_UBWC(fmt[i]))
+ if (has_tiled_rect)
width_threshold /= 2;
if (parallel_fetch_qualified && src[i].w > width_threshold)
@@ -2680,8 +2690,7 @@
}
/* TIME_MX Mode */
- if (SDE_FORMAT_IS_UBWC(fmt[R0]))
- buffer_lines = 2 * fmt[R0]->tile_height;
+ buffer_lines = 2 * max_tile_height;
if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) ||
(dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) {
@@ -3240,7 +3249,7 @@
psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
/* force black color fill during suspend */
- if (msm_is_suspend_state(plane->dev) && suspend_blank)
+ if (sde_kms_is_suspend_state(plane->dev) && suspend_blank)
_sde_plane_color_fill(psde, 0x0, 0x0);
/* flag h/w flush complete */
@@ -3714,7 +3723,6 @@
{SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"},
};
const struct sde_format_extended *format_list;
- struct sde_format_extended *virt_format_list = NULL;
struct sde_kms_info *info;
struct sde_plane *psde = to_sde_plane(plane);
int zpos_max = 255;
@@ -3857,29 +3865,10 @@
DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
sde_kms_info_reset(info);
- format_list = psde->pipe_sblk->format_list;
-
- if (master_plane_id) {
- int index, array_size;
-
- array_size = ARRAY_SIZE(plane_formats)
- + ARRAY_SIZE(rgb_10bit_formats);
- virt_format_list = kcalloc(array_size,
- sizeof(struct sde_format_extended), GFP_KERNEL);
- if (!virt_format_list) {
- SDE_ERROR(
- "failed to allocate virtual pipe format list\n");
- return;
- }
-
- index = sde_copy_formats(virt_format_list, array_size,
- 0, plane_formats, ARRAY_SIZE(plane_formats));
- sde_copy_formats(virt_format_list, array_size,
- index, rgb_10bit_formats,
- ARRAY_SIZE(rgb_10bit_formats));
-
- format_list = virt_format_list;
-
+ if (!master_plane_id) {
+ format_list = psde->pipe_sblk->format_list;
+ } else {
+ format_list = psde->pipe_sblk->virt_format_list;
sde_kms_info_add_keyint(info, "primary_smart_plane_id",
master_plane_id);
}
@@ -3916,7 +3905,6 @@
PLANE_PROP_INFO);
kfree(info);
- kfree(virt_format_list);
if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
snprintf(feature_name, sizeof(feature_name), "%s%d",
@@ -4664,7 +4652,6 @@
{
struct drm_plane *plane = NULL, *master_plane = NULL;
const struct sde_format_extended *format_list;
- struct sde_format_extended *virt_format_list = NULL;
struct sde_plane *psde;
struct msm_drm_private *priv;
struct sde_kms *kms;
@@ -4733,30 +4720,10 @@
goto clean_sspp;
}
- format_list = psde->pipe_sblk->format_list;
-
- if (master_plane_id) {
- int index, array_size;
-
- array_size = ARRAY_SIZE(plane_formats)
- + ARRAY_SIZE(rgb_10bit_formats);
- virt_format_list = kcalloc(array_size,
- sizeof(struct sde_format_extended),
- GFP_KERNEL);
- if (!virt_format_list) {
- SDE_ERROR(
- "failed to allocate virtual pipe format list\n");
- goto clean_sspp;
- }
-
- index = sde_copy_formats(virt_format_list, array_size,
- 0, plane_formats, ARRAY_SIZE(plane_formats));
- sde_copy_formats(virt_format_list, array_size,
- index, rgb_10bit_formats,
- ARRAY_SIZE(rgb_10bit_formats));
-
- format_list = virt_format_list;
- }
+ if (!master_plane_id)
+ format_list = psde->pipe_sblk->format_list;
+ else
+ format_list = psde->pipe_sblk->virt_format_list;
psde->nformats = sde_populate_formats(format_list,
psde->formats,
@@ -4805,6 +4772,5 @@
clean_plane:
kfree(psde);
exit:
- kfree(virt_format_list);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6426363..2dae758 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1451,6 +1451,10 @@
/* make sure ADRENO_DEVICE_STARTED is not set here */
BUG_ON(test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv));
+ /* disallow l2pc during wake up to improve GPU wake up time */
+ kgsl_pwrctrl_update_l2pc(&adreno_dev->dev,
+ KGSL_L2PC_WAKEUP_TIMEOUT);
+
pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
pmqos_wakeup_vote);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 01b877f..a4c189f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -397,6 +397,8 @@
* @profile_buffer: Memdesc holding the drawobj profiling buffer
* @profile_index: Index to store the start/stop ticks in the profiling
* buffer
+ * @pwrup_reglist: Memdesc holding the power up register list
+ * which is used by CP during preemption and IFPC
* @sp_local_gpuaddr: Base GPU virtual address for SP local memory
* @sp_pvt_gpuaddr: Base GPU virtual address for SP private memory
* @lm_fw: The LM firmware handle
@@ -453,6 +455,7 @@
struct kgsl_memdesc profile_buffer;
unsigned int profile_index;
+ struct kgsl_memdesc pwrup_reglist;
uint64_t sp_local_gpuaddr;
uint64_t sp_pvt_gpuaddr;
const struct firmware *lm_fw;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 7e9482a..386c3a9 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -210,6 +210,40 @@
{ 0xA630, 0x0, 1 },
};
+static struct reg_list_pair {
+ uint32_t offset;
+ uint32_t val;
+} a6xx_pwrup_reglist[] = {
+ { A6XX_VSC_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_GRAS_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_RB_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_PC_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_HLSQ_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_VFD_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_VPC_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_UCHE_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_SP_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_TPL1_ADDR_MODE_CNTL, 0x0 },
+ { A6XX_UCHE_WRITE_RANGE_MAX_LO, 0x0 },
+ { A6XX_UCHE_WRITE_RANGE_MAX_HI, 0x0 },
+ { A6XX_UCHE_TRAP_BASE_LO, 0x0 },
+ { A6XX_UCHE_TRAP_BASE_HI, 0x0 },
+ { A6XX_UCHE_WRITE_THRU_BASE_LO, 0x0 },
+ { A6XX_UCHE_WRITE_THRU_BASE_HI, 0x0 },
+ { A6XX_UCHE_GMEM_RANGE_MIN_LO, 0x0 },
+ { A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x0 },
+ { A6XX_UCHE_GMEM_RANGE_MAX_LO, 0x0 },
+ { A6XX_UCHE_GMEM_RANGE_MAX_HI, 0x0 },
+ { A6XX_UCHE_FILTER_CNTL, 0x0 },
+ { A6XX_UCHE_CACHE_WAYS, 0x0 },
+ { A6XX_UCHE_MODE_CNTL, 0x0 },
+ { A6XX_RB_NC_MODE_CNTL, 0x0 },
+ { A6XX_TPL1_NC_MODE_CNTL, 0x0 },
+ { A6XX_SP_NC_MODE_CNTL, 0x0 },
+ { A6XX_PC_DBG_ECO_CNTL, 0x0 },
+ { A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x0 },
+};
+
static void a6xx_platform_setup(struct adreno_device *adreno_dev)
{
uint64_t addr;
@@ -233,6 +267,21 @@
A6XX_CP_ALWAYS_ON_COUNTER_HI;
}
+static void a6xx_pwrup_reglist_init(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ if (kgsl_allocate_global(device, &adreno_dev->pwrup_reglist,
+ PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED,
+ "powerup_register_list")) {
+ adreno_dev->pwrup_reglist.gpuaddr = 0;
+ return;
+ }
+
+ kgsl_sharedmem_set(device, &adreno_dev->pwrup_reglist, 0, 0,
+ PAGE_SIZE);
+}
+
static void a6xx_init(struct adreno_device *adreno_dev)
{
a6xx_crashdump_init(adreno_dev);
@@ -243,6 +292,8 @@
*/
if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev)))
_update_always_on_regs(adreno_dev);
+
+ a6xx_pwrup_reglist_init(adreno_dev);
}
/**
@@ -375,6 +426,22 @@
return adreno_dev->lm_limit;
}
+static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev)
+{
+ uint32_t i;
+
+ /* Set up the register values */
+ for (i = 0; i < ARRAY_SIZE(a6xx_pwrup_reglist); i++) {
+ struct reg_list_pair *r = &a6xx_pwrup_reglist[i];
+
+ kgsl_regread(KGSL_DEVICE(adreno_dev), r->offset, &r->val);
+ }
+
+ /* Copy Preemption register/data pairs */
+ memcpy(adreno_dev->pwrup_reglist.hostptr, &a6xx_pwrup_reglist,
+ sizeof(a6xx_pwrup_reglist));
+}
+
/*
* a6xx_start() - Device start
* @adreno_dev: Pointer to adreno device
@@ -386,6 +453,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
unsigned int bit, mal, mode, glbl_inv;
unsigned int amsbc = 0;
+ static bool patch_reglist;
/* runtime adjust callbacks based on feature sets */
if (!kgsl_gmu_isenabled(device))
@@ -488,9 +556,9 @@
kgsl_regwrite(device, A6XX_UCHE_MODE_CNTL, (glbl_inv << 29) |
(mal << 23) | (bit << 21));
- /* Set hang detection threshold to 4 million cycles (0x3FFFF*16) */
+ /* Set hang detection threshold to 0x1FFFFF * 16 cycles */
kgsl_regwrite(device, A6XX_RBBM_INTERFACE_HANG_INT_CNTL,
- (1 << 30) | 0x3ffff);
+ (1 << 30) | 0x1fffff);
kgsl_regwrite(device, A6XX_UCHE_CLIENT_PF, 1);
@@ -503,6 +571,11 @@
kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
0x1);
+ if (!patch_reglist && (adreno_dev->pwrup_reglist.gpuaddr != 0)) {
+ a6xx_patch_pwrup_reglist(adreno_dev);
+ patch_reglist = true;
+ }
+
a6xx_preemption_start(adreno_dev);
a6xx_protect_init(adreno_dev);
}
@@ -570,12 +643,16 @@
*/
#define CP_INIT_OPERATION_MODE_MASK BIT(6)
+/* Register initialization list */
+#define CP_INIT_REGISTER_INIT_LIST BIT(7)
+
#define CP_INIT_MASK (CP_INIT_MAX_CONTEXT | \
CP_INIT_ERROR_DETECTION_CONTROL | \
CP_INIT_HEADER_DUMP | \
CP_INIT_DEFAULT_RESET_STATE | \
CP_INIT_UCODE_WORKAROUND_MASK | \
- CP_INIT_OPERATION_MODE_MASK)
+ CP_INIT_OPERATION_MODE_MASK | \
+ CP_INIT_REGISTER_INIT_LIST)
static void _set_ordinals(struct adreno_device *adreno_dev,
unsigned int *cmds, unsigned int count)
@@ -611,6 +688,15 @@
if (CP_INIT_MASK & CP_INIT_OPERATION_MODE_MASK)
*cmds++ = 0x00000002;
+ if (CP_INIT_MASK & CP_INIT_REGISTER_INIT_LIST) {
+ uint64_t gpuaddr = adreno_dev->pwrup_reglist.gpuaddr;
+
+ *cmds++ = lower_32_bits(gpuaddr);
+ *cmds++ = upper_32_bits(gpuaddr);
+ /* Size is in dwords */
+ *cmds++ = sizeof(a6xx_pwrup_reglist) >> 2;
+ }
+
/* Pad rest of the cmds with 0's */
while ((unsigned int)(cmds - start) < count)
*cmds++ = 0x0;
@@ -629,13 +715,13 @@
unsigned int *cmds;
int ret;
- cmds = adreno_ringbuffer_allocspace(rb, 9);
+ cmds = adreno_ringbuffer_allocspace(rb, 12);
if (IS_ERR(cmds))
return PTR_ERR(cmds);
- *cmds++ = cp_type7_packet(CP_ME_INIT, 8);
+ *cmds++ = cp_type7_packet(CP_ME_INIT, 11);
- _set_ordinals(adreno_dev, cmds, 8);
+ _set_ordinals(adreno_dev, cmds, 11);
ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000);
if (ret)
@@ -2207,7 +2293,9 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- a6xx_preemption_trigger(adreno_dev);
+ if (adreno_is_preemption_enabled(adreno_dev))
+ a6xx_preemption_trigger(adreno_dev);
+
adreno_dispatcher_schedule(device);
}
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 6264574..80c9a61 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -260,7 +260,7 @@
0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954,
0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965,
0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
- 0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
+ 0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA01,
/* GPU RSCC */
0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747,
0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 0a45d27..8fd8b88 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1464,7 +1464,9 @@
spin_unlock(&drawctxt->lock);
- kgsl_pwrctrl_update_l2pc(&adreno_dev->dev);
+ if (device->pwrctrl.l2pc_update_queue)
+ kgsl_pwrctrl_update_l2pc(&adreno_dev->dev,
+ KGSL_L2PC_QUEUE_TIMEOUT);
/* Add the context to the dispatcher pending list */
dispatcher_queue_context(adreno_dev, drawctxt);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6bad70b..2cc1869 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -85,7 +85,12 @@
{ KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \
{ KGSL_CONTEXT_INVALIDATE_ON_FAULT, "INVALIDATE_ON_FAULT" }, \
{ KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \
- { KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }
+ { KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }, \
+ { KGSL_CONTEXT_IFH_NOP, "IFH_NOP" }, \
+ { KGSL_CONTEXT_SECURE, "SECURE" }, \
+ { KGSL_CONTEXT_NO_SNAPSHOT, "NO_SNAPSHOT" }, \
+ { KGSL_CONTEXT_SPARSE, "SPARSE" }
+
#define KGSL_CONTEXT_TYPES \
{ KGSL_CONTEXT_TYPE_ANY, "ANY" }, \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2999fb2..8cca248 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -44,13 +44,6 @@
#define DEFAULT_BUS_P 25
-/*
- * The effective duration of qos request in usecs. After
- * timeout, qos request is cancelled automatically.
- * Kept 80ms default, inline with default GPU idle time.
- */
-#define KGSL_L2PC_CPU_TIMEOUT (80 * 1000)
-
/* Order deeply matters here because reasons. New entries go on the end */
static const char * const clocks[] = {
"src_clk",
@@ -544,12 +537,14 @@
/**
* kgsl_pwrctrl_update_l2pc() - Update existing qos request
* @device: Pointer to the kgsl_device struct
+ * @timeout_us: the effective duration of qos request in usecs.
*
* Updates an existing qos request to avoid L2PC on the
* CPUs (which are selected through dtsi) on which GPU
* thread is running. This would help for performance.
*/
-void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device)
+void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device,
+ unsigned long timeout_us)
{
int cpu;
@@ -563,7 +558,7 @@
pm_qos_update_request_timeout(
&device->pwrctrl.l2pc_cpus_qos,
device->pwrctrl.pm_qos_cpu_mask_latency,
- KGSL_L2PC_CPU_TIMEOUT);
+ timeout_us);
}
}
EXPORT_SYMBOL(kgsl_pwrctrl_update_l2pc);
@@ -2194,6 +2189,10 @@
kgsl_property_read_u32(device, "qcom,l2pc-cpu-mask",
&pwr->l2pc_cpus_mask);
+ pwr->l2pc_update_queue = of_property_read_bool(
+ device->pdev->dev.of_node,
+ "qcom,l2pc-update-queue");
+
pm_runtime_enable(&pdev->dev);
ocmem_bus_node = of_find_node_by_name(
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 65e047d..53bb255 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -50,6 +50,19 @@
#define KGSL_PWR_DEL_LIMIT 1
#define KGSL_PWR_SET_LIMIT 2
+/*
+ * The effective duration of qos request in usecs at queue time.
+ * After timeout, qos request is cancelled automatically.
+ * Kept 80ms default, inline with default GPU idle time.
+ */
+#define KGSL_L2PC_QUEUE_TIMEOUT (80 * 1000)
+
+/*
+ * The effective duration of qos request in usecs at wakeup time.
+ * After timeout, qos request is cancelled automatically.
+ */
+#define KGSL_L2PC_WAKEUP_TIMEOUT (10 * 1000)
+
enum kgsl_pwrctrl_timer_type {
KGSL_PWR_IDLE_TIMER,
};
@@ -127,6 +140,7 @@
* @irq_name - resource name for the IRQ
* @clk_stats - structure of clock statistics
* @l2pc_cpus_mask - mask to avoid L2PC on masked CPUs
+ * @l2pc_update_queue - Boolean flag to avoid L2PC on masked CPUs at queue time
* @l2pc_cpus_qos - qos structure to avoid L2PC on CPUs
* @pm_qos_req_dma - the power management quality of service structure
* @pm_qos_active_latency - allowed CPU latency in microseconds when active
@@ -180,6 +194,7 @@
const char *irq_name;
struct kgsl_clk_stats clk_stats;
unsigned int l2pc_cpus_mask;
+ bool l2pc_update_queue;
struct pm_qos_request l2pc_cpus_qos;
struct pm_qos_request pm_qos_req_dma;
unsigned int pm_qos_active_latency;
@@ -244,5 +259,6 @@
void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
struct kgsl_pwr_constraint *pwrc, uint32_t id);
-void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device);
+void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device,
+ unsigned long timeout_us);
#endif /* __KGSL_PWRCTRL_H */
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index bf93b91..a06a6c7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -332,9 +332,17 @@
u32 value;
};
+/*
+ * attach_count
+ * The SMR and S2CR registers are only programmed when the number of
+ * devices attached to the iommu using these registers is > 0. This
+ * is required for the "SID switch" use case for secure display.
+ * Protected by stream_map_mutex.
+ */
struct arm_smmu_s2cr {
struct iommu_group *group;
int count;
+ int attach_count;
enum arm_smmu_s2cr_type type;
enum arm_smmu_s2cr_privcfg privcfg;
u8 cbndx;
@@ -790,6 +798,28 @@
WARN_ON(msm_bus_scale_client_update_request(pwr->bus_client, 0));
}
+static int arm_smmu_enable_regulators(struct arm_smmu_power_resources *pwr)
+{
+ struct regulator_bulk_data *consumers;
+ int num_consumers, ret;
+ int i;
+
+ num_consumers = pwr->num_gdscs;
+ consumers = pwr->gdscs;
+ for (i = 0; i < num_consumers; i++) {
+ ret = regulator_enable(consumers[i].consumer);
+ if (ret)
+ goto out;
+ }
+ return 0;
+
+out:
+ i -= 1;
+ for (; i >= 0; i--)
+ regulator_disable(consumers[i].consumer);
+ return ret;
+}
+
static int arm_smmu_disable_regulators(struct arm_smmu_power_resources *pwr)
{
struct regulator_bulk_data *consumers;
@@ -878,7 +908,7 @@
if (ret)
goto out_unlock;
- ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
+ ret = arm_smmu_enable_regulators(pwr);
if (ret)
goto out_disable_bus;
@@ -1227,7 +1257,7 @@
phys_addr_t phys_soft;
u32 frsynra;
bool non_fatal_fault = !!(smmu_domain->attributes &
- DOMAIN_ATTR_NON_FATAL_FAULTS);
+ (1 << DOMAIN_ATTR_NON_FATAL_FAULTS));
static DEFINE_RATELIMIT_STATE(_rs,
DEFAULT_RATELIMIT_INTERVAL,
@@ -1988,11 +2018,9 @@
}
iommu_group_put(group);
- /* It worked! Now, poke the actual hardware */
- for_each_cfg_sme(fwspec, i, idx) {
- arm_smmu_write_sme(smmu, idx);
+ /* It worked! Don't poke the actual hardware until we've attached */
+ for_each_cfg_sme(fwspec, i, idx)
smmu->s2crs[idx].group = group;
- }
mutex_unlock(&smmu->stream_map_mutex);
return 0;
@@ -2021,6 +2049,33 @@
mutex_unlock(&smmu->stream_map_mutex);
}
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+ struct iommu_fwspec *fwspec)
+{
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct arm_smmu_s2cr *s2cr = smmu->s2crs;
+ int i, idx;
+ const struct iommu_gather_ops *tlb;
+
+ tlb = smmu_domain->pgtbl_cfg.tlb;
+
+ mutex_lock(&smmu->stream_map_mutex);
+ for_each_cfg_sme(fwspec, i, idx) {
+ WARN_ON(s2cr[idx].attach_count == 0);
+ s2cr[idx].attach_count -= 1;
+
+ if (s2cr[idx].attach_count > 0)
+ continue;
+
+ writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
+ writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
+ }
+ mutex_unlock(&smmu->stream_map_mutex);
+
+ /* Ensure there are no stale mappings for this context bank */
+ tlb->tlb_flush_all(smmu_domain);
+}
+
static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
struct iommu_fwspec *fwspec)
{
@@ -2030,15 +2085,17 @@
u8 cbndx = smmu_domain->cfg.cbndx;
int i, idx;
+ mutex_lock(&smmu->stream_map_mutex);
for_each_cfg_sme(fwspec, i, idx) {
- if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
+ if (s2cr[idx].attach_count++ > 0)
continue;
s2cr[idx].type = type;
s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
s2cr[idx].cbndx = cbndx;
- arm_smmu_write_s2cr(smmu, idx);
+ arm_smmu_write_sme(smmu, idx);
}
+ mutex_unlock(&smmu->stream_map_mutex);
return 0;
}
@@ -2048,6 +2105,7 @@
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
int dynamic = smmu_domain->attributes & (1 << DOMAIN_ATTR_DYNAMIC);
int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);
@@ -2059,6 +2117,8 @@
return;
}
+ arm_smmu_domain_remove_master(smmu_domain, fwspec);
+
/* Remove additional vote for atomic power */
if (atomic_domain) {
WARN_ON(arm_smmu_power_on_atomic(smmu->pwr));
@@ -4247,36 +4307,6 @@
u32 halt_count;
};
-static int qsmmuv500_tbu_power_on_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
- int ret = 0;
-
- list_for_each_entry(tbu, &data->tbus, list) {
- ret = arm_smmu_power_on(tbu->pwr);
- if (ret)
- break;
- }
- if (!ret)
- return 0;
-
- list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
- arm_smmu_power_off(tbu->pwr);
- }
- return ret;
-}
-
-static void qsmmuv500_tbu_power_off_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
- list_for_each_entry_reverse(tbu, &data->tbus, list) {
- arm_smmu_power_off(tbu->pwr);
- }
-}
-
static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu)
{
unsigned long flags;
@@ -4335,37 +4365,6 @@
spin_unlock_irqrestore(&tbu->halt_lock, flags);
}
-static int qsmmuv500_halt_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
- int ret = 0;
-
- list_for_each_entry(tbu, &data->tbus, list) {
- ret = qsmmuv500_tbu_halt(tbu);
- if (ret)
- break;
- }
-
- if (!ret)
- return 0;
-
- list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
- qsmmuv500_tbu_resume(tbu);
- }
- return ret;
-}
-
-static void qsmmuv500_resume_all(struct arm_smmu_device *smmu)
-{
- struct qsmmuv500_tbu_device *tbu;
- struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
- list_for_each_entry(tbu, &data->tbus, list) {
- qsmmuv500_tbu_resume(tbu);
- }
-}
-
static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu(
struct arm_smmu_device *smmu, u32 sid)
{
@@ -4380,24 +4379,6 @@
return NULL;
}
-static void qsmmuv500_device_reset(struct arm_smmu_device *smmu)
-{
- int i, ret;
- struct arm_smmu_impl_def_reg *regs = smmu->impl_def_attach_registers;
-
- ret = qsmmuv500_tbu_power_on_all(smmu);
- if (ret)
- return;
-
- /* Program implementation defined registers */
- qsmmuv500_halt_all(smmu);
- for (i = 0; i < smmu->num_impl_def_attach_registers; ++i)
- writel_relaxed(regs[i].value,
- ARM_SMMU_GR0(smmu) + regs[i].offset);
- qsmmuv500_resume_all(smmu);
- qsmmuv500_tbu_power_off_all(smmu);
-}
-
static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain,
struct qsmmuv500_tbu_device *tbu,
unsigned long *flags)
@@ -4635,7 +4616,6 @@
struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
.init = qsmmuv500_arch_init,
- .device_reset = qsmmuv500_device_reset,
.iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
};
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 2db06b0..04a9d7f 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -255,16 +255,17 @@
__av8l_fast_unmap(ptep, size, true);
}
-/* upper layer must take care of TLB invalidation */
static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
+ struct io_pgtable *iop = &data->iop;
av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, iova);
unsigned long nptes = size >> AV8L_FAST_PAGE_SHIFT;
__av8l_fast_unmap(ptep, size, false);
dmac_clean_range(ptep, ptep + nptes);
+ io_pgtable_tlb_flush_all(iop);
return size;
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 400839d..785d689 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -668,18 +668,9 @@
LEDs in both PWM and light pattern generator (LPG) modes. For older
PMICs, it also supports WLEDs and flash LEDs.
-config LEDS_QPNP_FLASH
- tristate "Support for QPNP Flash LEDs"
- depends on LEDS_CLASS && SPMI
- help
- This driver supports the flash LED functionality of Qualcomm
- Technologies, Inc. QPNP PMICs. This driver supports PMICs up through
- PM8994. It can configure the flash LED target current for several
- independent channels.
-
config LEDS_QPNP_FLASH_V2
tristate "Support for QPNP V2 Flash LEDs"
- depends on LEDS_CLASS && MFD_SPMI_PMIC && !LEDS_QPNP_FLASH
+ depends on LEDS_CLASS && MFD_SPMI_PMIC
help
This driver supports the flash V2 LED functionality of Qualcomm
Technologies, Inc. QPNP PMICs. This driver supports PMICs starting
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index ba9bb8d..2ff9a7c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -72,7 +72,6 @@
obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
obj-$(CONFIG_LEDS_QPNP) += leds-qpnp.o
-obj-$(CONFIG_LEDS_QPNP_FLASH) += leds-qpnp-flash.o
obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o
obj-$(CONFIG_LEDS_QPNP_WLED) += leds-qpnp-wled.o
obj-$(CONFIG_LEDS_QPNP_HAPTICS) += leds-qpnp-haptics.o
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
deleted file mode 100644
index c27c059..0000000
--- a/drivers/leds/leds-qpnp-flash.c
+++ /dev/null
@@ -1,2649 +0,0 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/regmap.h>
-#include <linux/errno.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/spmi.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/power_supply.h>
-#include <linux/leds-qpnp-flash.h>
-#include <linux/qpnp/qpnp-adc.h>
-#include <linux/qpnp/qpnp-revid.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include "leds.h"
-
-#define FLASH_LED_PERIPHERAL_SUBTYPE(base) (base + 0x05)
-#define FLASH_SAFETY_TIMER(base) (base + 0x40)
-#define FLASH_MAX_CURRENT(base) (base + 0x41)
-#define FLASH_LED0_CURRENT(base) (base + 0x42)
-#define FLASH_LED1_CURRENT(base) (base + 0x43)
-#define FLASH_CLAMP_CURRENT(base) (base + 0x44)
-#define FLASH_MODULE_ENABLE_CTRL(base) (base + 0x46)
-#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
-#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
-#define FLASH_HEADROOM(base) (base + 0x4A)
-#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
-#define FLASH_MASK_ENABLE(base) (base + 0x4C)
-#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
-#define FLASH_FAULT_DETECT(base) (base + 0x51)
-#define FLASH_THERMAL_DRATE(base) (base + 0x52)
-#define FLASH_CURRENT_RAMP(base) (base + 0x54)
-#define FLASH_VPH_PWR_DROOP(base) (base + 0x5A)
-#define FLASH_HDRM_SNS_ENABLE_CTRL0(base) (base + 0x5C)
-#define FLASH_HDRM_SNS_ENABLE_CTRL1(base) (base + 0x5D)
-#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
-#define FLASH_PERPH_RESET_CTRL(base) (base + 0xDA)
-#define FLASH_TORCH(base) (base + 0xE4)
-
-#define FLASH_STATUS_REG_MASK 0xFF
-#define FLASH_LED_FAULT_STATUS(base) (base + 0x08)
-#define INT_LATCHED_STS(base) (base + 0x18)
-#define IN_POLARITY_HIGH(base) (base + 0x12)
-#define INT_SET_TYPE(base) (base + 0x11)
-#define INT_EN_SET(base) (base + 0x15)
-#define INT_LATCHED_CLR(base) (base + 0x14)
-
-#define FLASH_HEADROOM_MASK 0x03
-#define FLASH_STARTUP_DLY_MASK 0x03
-#define FLASH_VREG_OK_FORCE_MASK 0xC0
-#define FLASH_FAULT_DETECT_MASK 0x80
-#define FLASH_THERMAL_DERATE_MASK 0xBF
-#define FLASH_SECURE_MASK 0xFF
-#define FLASH_TORCH_MASK 0x03
-#define FLASH_CURRENT_MASK 0x7F
-#define FLASH_TMR_MASK 0x03
-#define FLASH_TMR_SAFETY 0x00
-#define FLASH_SAFETY_TIMER_MASK 0x7F
-#define FLASH_MODULE_ENABLE_MASK 0xE0
-#define FLASH_STROBE_MASK 0xC0
-#define FLASH_CURRENT_RAMP_MASK 0xBF
-#define FLASH_VPH_PWR_DROOP_MASK 0xF3
-#define FLASH_LED_HDRM_SNS_ENABLE_MASK 0x81
-#define FLASH_MASK_MODULE_CONTRL_MASK 0xE0
-#define FLASH_FOLLOW_OTST2_RB_MASK 0x08
-
-#define FLASH_LED_TRIGGER_DEFAULT "none"
-#define FLASH_LED_HEADROOM_DEFAULT_MV 500
-#define FLASH_LED_STARTUP_DELAY_DEFAULT_US 128
-#define FLASH_LED_CLAMP_CURRENT_DEFAULT_MA 200
-#define FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C 80
-#define FLASH_LED_RAMP_UP_STEP_DEFAULT_US 3
-#define FLASH_LED_RAMP_DN_STEP_DEFAULT_US 3
-#define FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV 3200
-#define FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US 10
-#define FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT 2
-#define FLASH_RAMP_UP_DELAY_US_MIN 1000
-#define FLASH_RAMP_UP_DELAY_US_MAX 1001
-#define FLASH_RAMP_DN_DELAY_US_MIN 2160
-#define FLASH_RAMP_DN_DELAY_US_MAX 2161
-#define FLASH_BOOST_REGULATOR_PROBE_DELAY_MS 2000
-#define FLASH_TORCH_MAX_LEVEL 0x0F
-#define FLASH_MAX_LEVEL 0x4F
-#define FLASH_LED_FLASH_HW_VREG_OK 0x40
-#define FLASH_LED_FLASH_SW_VREG_OK 0x80
-#define FLASH_LED_STROBE_TYPE_HW 0x04
-#define FLASH_DURATION_DIVIDER 10
-#define FLASH_LED_HEADROOM_DIVIDER 100
-#define FLASH_LED_HEADROOM_OFFSET 2
-#define FLASH_LED_MAX_CURRENT_MA 1000
-#define FLASH_LED_THERMAL_THRESHOLD_MIN 95
-#define FLASH_LED_THERMAL_DEVIDER 10
-#define FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV 2500
-#define FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER 100
-#define FLASH_LED_HDRM_SNS_ENABLE 0x81
-#define FLASH_LED_HDRM_SNS_DISABLE 0x01
-#define FLASH_LED_UA_PER_MA 1000
-#define FLASH_LED_MASK_MODULE_MASK2_ENABLE 0x20
-#define FLASH_LED_MASK3_ENABLE_SHIFT 7
-#define FLASH_LED_MODULE_CTRL_DEFAULT 0x60
-#define FLASH_LED_CURRENT_READING_DELAY_MIN 5000
-#define FLASH_LED_CURRENT_READING_DELAY_MAX 5001
-#define FLASH_LED_OPEN_FAULT_DETECTED 0xC
-
-#define FLASH_UNLOCK_SECURE 0xA5
-#define FLASH_LED_TORCH_ENABLE 0x00
-#define FLASH_LED_TORCH_DISABLE 0x03
-#define FLASH_MODULE_ENABLE 0x80
-#define FLASH_LED0_TRIGGER 0x80
-#define FLASH_LED1_TRIGGER 0x40
-#define FLASH_LED0_ENABLEMENT 0x40
-#define FLASH_LED1_ENABLEMENT 0x20
-#define FLASH_LED_DISABLE 0x00
-#define FLASH_LED_MIN_CURRENT_MA 13
-#define FLASH_SUBTYPE_DUAL 0x01
-#define FLASH_SUBTYPE_SINGLE 0x02
-
-/*
- * ID represents physical LEDs for individual control purpose.
- */
-enum flash_led_id {
- FLASH_LED_0 = 0,
- FLASH_LED_1,
- FLASH_LED_SWITCH,
-};
-
-enum flash_led_type {
- FLASH = 0,
- TORCH,
- SWITCH,
-};
-
-enum thermal_derate_rate {
- RATE_1_PERCENT = 0,
- RATE_1P25_PERCENT,
- RATE_2_PERCENT,
- RATE_2P5_PERCENT,
- RATE_5_PERCENT,
-};
-
-enum current_ramp_steps {
- RAMP_STEP_0P2_US = 0,
- RAMP_STEP_0P4_US,
- RAMP_STEP_0P8_US,
- RAMP_STEP_1P6_US,
- RAMP_STEP_3P3_US,
- RAMP_STEP_6P7_US,
- RAMP_STEP_13P5_US,
- RAMP_STEP_27US,
-};
-
-struct flash_regulator_data {
- struct regulator *regs;
- const char *reg_name;
- u32 max_volt_uv;
-};
-
-/*
- * Configurations for each individual LED
- */
-struct flash_node_data {
- struct platform_device *pdev;
- struct regmap *regmap;
- struct led_classdev cdev;
- struct work_struct work;
- struct flash_regulator_data *reg_data;
- u16 max_current;
- u16 prgm_current;
- u16 prgm_current2;
- u16 duration;
- u8 id;
- u8 type;
- u8 trigger;
- u8 enable;
- u8 num_regulators;
- bool flash_on;
-};
-
-/*
- * Flash LED configuration read from device tree
- */
-struct flash_led_platform_data {
- unsigned int temp_threshold_num;
- unsigned int temp_derate_curr_num;
- unsigned int *die_temp_derate_curr_ma;
- unsigned int *die_temp_threshold_degc;
- u16 ramp_up_step;
- u16 ramp_dn_step;
- u16 vph_pwr_droop_threshold;
- u16 headroom;
- u16 clamp_current;
- u8 thermal_derate_threshold;
- u8 vph_pwr_droop_debounce_time;
- u8 startup_dly;
- u8 thermal_derate_rate;
- bool pmic_charger_support;
- bool self_check_en;
- bool thermal_derate_en;
- bool current_ramp_en;
- bool vph_pwr_droop_en;
- bool hdrm_sns_ch0_en;
- bool hdrm_sns_ch1_en;
- bool power_detect_en;
- bool mask3_en;
- bool follow_rb_disable;
- bool die_current_derate_en;
-};
-
-struct qpnp_flash_led_buffer {
- size_t rpos;
- size_t wpos;
- size_t len;
- char data[0];
-};
-
-/*
- * Flash LED data structure containing flash LED attributes
- */
-struct qpnp_flash_led {
- struct pmic_revid_data *revid_data;
- struct platform_device *pdev;
- struct regmap *regmap;
- struct flash_led_platform_data *pdata;
- struct pinctrl *pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
- struct flash_node_data *flash_node;
- struct power_supply *battery_psy;
- struct workqueue_struct *ordered_workq;
- struct qpnp_vadc_chip *vadc_dev;
- struct mutex flash_led_lock;
- struct qpnp_flash_led_buffer *log;
- struct dentry *dbgfs_root;
- int num_leds;
- u32 buffer_cnt;
- u16 base;
- u16 current_addr;
- u16 current2_addr;
- u8 peripheral_type;
- u8 fault_reg;
- bool gpio_enabled;
- bool charging_enabled;
- bool strobe_debug;
- bool dbg_feature_en;
- bool open_fault;
-};
-
-static u8 qpnp_flash_led_ctrl_dbg_regs[] = {
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x4A, 0x4B, 0x4C, 0x4F, 0x51, 0x52, 0x54, 0x55, 0x5A, 0x5C, 0x5D,
-};
-
-static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
- struct file *file)
-{
- struct qpnp_flash_led_buffer *log;
- size_t logbufsize = SZ_4K;
-
- log = kzalloc(logbufsize, GFP_KERNEL);
- if (!log)
- return -ENOMEM;
-
- log->rpos = 0;
- log->wpos = 0;
- log->len = logbufsize - sizeof(*log);
- led->log = log;
-
- led->buffer_cnt = 1;
- file->private_data = led;
-
- return 0;
-}
-
-static int flash_led_dfs_open(struct inode *inode, struct file *file)
-{
- struct qpnp_flash_led *led = inode->i_private;
-
- return flash_led_dbgfs_file_open(led, file);
-}
-
-static int flash_led_dfs_close(struct inode *inode, struct file *file)
-{
- struct qpnp_flash_led *led = file->private_data;
-
- if (led && led->log) {
- file->private_data = NULL;
- kfree(led->log);
- }
-
- return 0;
-}
-
-static int print_to_log(struct qpnp_flash_led_buffer *log,
- const char *fmt, ...)
-{
- va_list args;
- int cnt;
- char *log_buf = &log->data[log->wpos];
- size_t size = log->len - log->wpos;
-
- va_start(args, fmt);
- cnt = vscnprintf(log_buf, size, fmt, args);
- va_end(args);
-
- log->wpos += cnt;
- return cnt;
-}
-
-static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
- size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
- uint val;
- int rc;
- size_t len;
- size_t ret;
-
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
-
- rc = regmap_read(led->regmap, INT_LATCHED_STS(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from address %x, rc(%d)\n",
- INT_LATCHED_STS(led->base), rc);
- return -EINVAL;
- }
- led->buffer_cnt--;
-
- rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
- if (rc == 0)
- return rc;
-
- rc = print_to_log(log, "0x%02X ", val);
- if (rc == 0)
- return rc;
-
- if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
- log->data[log->wpos - 1] = '\n';
-
- len = min(count, log->wpos - log->rpos);
-
- ret = copy_to_user(buf, &log->data[log->rpos], len);
- if (ret) {
- pr_err("error copy register value to user\n");
- return -EFAULT;
- }
-
- len -= ret;
- *ppos += len;
- log->rpos += len;
-
- return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
- size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
- int rc;
- size_t len;
- size_t ret;
-
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
-
- led->buffer_cnt--;
-
- rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
- if (rc == 0)
- return rc;
-
- rc = print_to_log(log, "0x%02X ", led->fault_reg);
- if (rc == 0)
- return rc;
-
- if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
- log->data[log->wpos - 1] = '\n';
-
- len = min(count, log->wpos - log->rpos);
-
- ret = copy_to_user(buf, &log->data[log->rpos], len);
- if (ret) {
- pr_err("error copy register value to user\n");
- return -EFAULT;
- }
-
- len -= ret;
- *ppos += len;
- log->rpos += len;
-
- return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos) {
-
- u8 *val;
- int pos = 0;
- int cnt = 0;
- int data;
- size_t ret = 0;
-
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
- if (!kbuf)
- return -ENOMEM;
-
- ret = copy_from_user(kbuf, buf, count);
- if (!ret) {
- pr_err("failed to copy data from user\n");
- ret = -EFAULT;
- goto free_buf;
- }
-
- count -= ret;
- *ppos += count;
- kbuf[count] = '\0';
- val = kbuf;
- while (sscanf(kbuf + pos, "%i", &data) == 1) {
- pos++;
- val[cnt++] = data & 0xff;
- }
-
- if (!cnt)
- goto free_buf;
-
- ret = count;
- if (*val == 1)
- led->strobe_debug = true;
- else
- led->strobe_debug = false;
-
-free_buf:
- kfree(kbuf);
- return ret;
-}
-
-static ssize_t flash_led_dfs_dbg_enable(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos) {
-
- u8 *val;
- int pos = 0;
- int cnt = 0;
- int data;
- size_t ret = 0;
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
- if (!kbuf)
- return -ENOMEM;
-
- ret = copy_from_user(kbuf, buf, count);
- if (ret == count) {
- pr_err("failed to copy data from user\n");
- ret = -EFAULT;
- goto free_buf;
- }
- count -= ret;
- *ppos += count;
- kbuf[count] = '\0';
- val = kbuf;
- while (sscanf(kbuf + pos, "%i", &data) == 1) {
- pos++;
- val[cnt++] = data & 0xff;
- }
-
- if (!cnt)
- goto free_buf;
-
- ret = count;
- if (*val == 1)
- led->dbg_feature_en = true;
- else
- led->dbg_feature_en = false;
-
-free_buf:
- kfree(kbuf);
- return ret;
-}
-
-static const struct file_operations flash_led_dfs_latched_reg_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .read = flash_led_dfs_latched_reg_read,
-};
-
-static const struct file_operations flash_led_dfs_strobe_reg_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .read = flash_led_dfs_fault_reg_read,
- .write = flash_led_dfs_fault_reg_enable,
-};
-
-static const struct file_operations flash_led_dfs_dbg_feature_fops = {
- .open = flash_led_dfs_open,
- .release = flash_led_dfs_close,
- .write = flash_led_dfs_dbg_enable,
-};
-
-static int
-qpnp_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, u8 val)
-{
- int rc;
-
- rc = regmap_update_bits(led->regmap, addr, mask, val);
- if (rc)
- dev_err(&led->pdev->dev,
- "Unable to update_bits to addr=%x, rc(%d)\n", addr, rc);
-
- dev_dbg(&led->pdev->dev, "Write 0x%02X to addr 0x%02X\n", val, addr);
-
- return rc;
-}
-
-static int qpnp_flash_led_get_allowed_die_temp_curr(struct qpnp_flash_led *led,
- int64_t die_temp_degc)
-{
- int die_temp_curr_ma;
-
- if (die_temp_degc >= led->pdata->die_temp_threshold_degc[0])
- die_temp_curr_ma = 0;
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[1])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[0];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[2])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[1];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[3])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[2];
- else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[4])
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[3];
- else
- die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[4];
-
- return die_temp_curr_ma;
-}
-
-static int64_t qpnp_flash_led_get_die_temp(struct qpnp_flash_led *led)
-{
- struct qpnp_vadc_result die_temp_result;
- int rc;
-
- rc = qpnp_vadc_read(led->vadc_dev, SPARE2, &die_temp_result);
- if (rc) {
- pr_err("failed to read the die temp\n");
- return -EINVAL;
- }
-
- return die_temp_result.physical;
-}
-
-static int qpnp_get_pmic_revid(struct qpnp_flash_led *led)
-{
- struct device_node *revid_dev_node;
-
- revid_dev_node = of_parse_phandle(led->pdev->dev.of_node,
- "qcom,pmic-revid", 0);
- if (!revid_dev_node) {
- dev_err(&led->pdev->dev,
- "qcom,pmic-revid property missing\n");
- return -EINVAL;
- }
-
- led->revid_data = get_revid_data(revid_dev_node);
- if (IS_ERR(led->revid_data)) {
- pr_err("Couldn't get revid data rc = %ld\n",
- PTR_ERR(led->revid_data));
- return PTR_ERR(led->revid_data);
- }
-
- return 0;
-}
-
-static int
-qpnp_flash_led_get_max_avail_current(struct flash_node_data *flash_node,
- struct qpnp_flash_led *led)
-{
- union power_supply_propval prop;
- int64_t chg_temp_milidegc, die_temp_degc;
- int max_curr_avail_ma = 2000;
- int allowed_die_temp_curr_ma = 2000;
- int rc;
-
- if (led->pdata->power_detect_en) {
- if (!led->battery_psy) {
- dev_err(&led->pdev->dev,
- "Failed to query power supply\n");
- return -EINVAL;
- }
-
- /*
- * When charging is enabled, enforce this new enablement
- * sequence to reduce fuel gauge reading resolution.
- */
- if (led->charging_enabled) {
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- return -EINVAL;
- }
-
- usleep_range(FLASH_LED_CURRENT_READING_DELAY_MIN,
- FLASH_LED_CURRENT_READING_DELAY_MAX);
- }
-
- power_supply_get_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_CURRENT_MAX, &prop);
- if (!prop.intval) {
- dev_err(&led->pdev->dev,
- "battery too low for flash\n");
- return -EINVAL;
- }
-
- max_curr_avail_ma = (prop.intval / FLASH_LED_UA_PER_MA);
- }
-
- /*
- * When thermal mitigation is available, this logic will execute to
- * derate current based upon the PMIC die temperature.
- */
- if (led->pdata->die_current_derate_en) {
- chg_temp_milidegc = qpnp_flash_led_get_die_temp(led);
- if (chg_temp_milidegc < 0)
- return -EINVAL;
-
- die_temp_degc = div_s64(chg_temp_milidegc, 1000);
- allowed_die_temp_curr_ma =
- qpnp_flash_led_get_allowed_die_temp_curr(led,
- die_temp_degc);
- if (allowed_die_temp_curr_ma < 0)
- return -EINVAL;
- }
-
- max_curr_avail_ma = (max_curr_avail_ma >= allowed_die_temp_curr_ma)
- ? allowed_die_temp_curr_ma : max_curr_avail_ma;
-
- return max_curr_avail_ma;
-}
-
-static ssize_t qpnp_flash_led_die_temp_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- unsigned long val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- /*'0' for disable die_temp feature; non-zero to enable feature*/
- if (val == 0)
- led->pdata->die_current_derate_en = false;
- else
- led->pdata->die_current_derate_en = true;
-
- return count;
-}
-
-static ssize_t qpnp_led_strobe_type_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct flash_node_data *flash_node;
- unsigned long state;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret = -EINVAL;
-
- ret = kstrtoul(buf, 10, &state);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-
- /* '0' for sw strobe; '1' for hw strobe */
- if (state == 1)
- flash_node->trigger |= FLASH_LED_STROBE_TYPE_HW;
- else
- flash_node->trigger &= ~FLASH_LED_STROBE_TYPE_HW;
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_dump_regs_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- int rc, i, count = 0;
- u16 addr;
- uint val;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
- for (i = 0; i < ARRAY_SIZE(qpnp_flash_led_ctrl_dbg_regs); i++) {
- addr = led->base + qpnp_flash_led_ctrl_dbg_regs[i];
- rc = regmap_read(led->regmap, addr, &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from addr=%x, rc(%d)\n",
- addr, rc);
- return -EINVAL;
- }
-
- count += snprintf(buf + count, PAGE_SIZE - count,
- "REG_0x%x = 0x%02x\n", addr, val);
-
- if (count >= PAGE_SIZE)
- return PAGE_SIZE - 1;
- }
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_current_derate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- unsigned long val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- ssize_t ret;
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- /*'0' for disable derate feature; non-zero to enable derate feature */
- if (val == 0)
- led->pdata->power_detect_en = false;
- else
- led->pdata->power_detect_en = true;
-
- return count;
-}
-
-static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qpnp_flash_led *led;
- struct flash_node_data *flash_node;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- int max_curr_avail_ma = 0;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (led->flash_node[0].flash_on)
- max_curr_avail_ma += led->flash_node[0].max_current;
- if (led->flash_node[1].flash_on)
- max_curr_avail_ma += led->flash_node[1].max_current;
-
- if (led->pdata->power_detect_en ||
- led->pdata->die_current_derate_en) {
- max_curr_avail_ma =
- qpnp_flash_led_get_max_avail_current(flash_node, led);
-
- if (max_curr_avail_ma < 0)
- return -EINVAL;
- }
-
- return snprintf(buf, PAGE_SIZE, "%u\n", max_curr_avail_ma);
-}
-
-static struct device_attribute qpnp_flash_led_attrs[] = {
- __ATTR(strobe, 0664, NULL, qpnp_led_strobe_type_store),
- __ATTR(reg_dump, 0664, qpnp_flash_led_dump_regs_show, NULL),
- __ATTR(enable_current_derate, 0664, NULL,
- qpnp_flash_led_current_derate_store),
- __ATTR(max_allowed_current, 0664, qpnp_flash_led_max_current_show,
- NULL),
- __ATTR(enable_die_temp_current_derate, 0664, NULL,
- qpnp_flash_led_die_temp_store),
-};
-
-static int qpnp_flash_led_get_thermal_derate_rate(const char *rate)
-{
- /*
- * return 5% derate as default value if user specifies
- * a value un-supported
- */
- if (strcmp(rate, "1_PERCENT") == 0)
- return RATE_1_PERCENT;
- else if (strcmp(rate, "1P25_PERCENT") == 0)
- return RATE_1P25_PERCENT;
- else if (strcmp(rate, "2_PERCENT") == 0)
- return RATE_2_PERCENT;
- else if (strcmp(rate, "2P5_PERCENT") == 0)
- return RATE_2P5_PERCENT;
- else if (strcmp(rate, "5_PERCENT") == 0)
- return RATE_5_PERCENT;
- else
- return RATE_5_PERCENT;
-}
-
-static int qpnp_flash_led_get_ramp_step(const char *step)
-{
- /*
- * return 27 us as default value if user specifies
- * a value un-supported
- */
- if (strcmp(step, "0P2_US") == 0)
- return RAMP_STEP_0P2_US;
- else if (strcmp(step, "0P4_US") == 0)
- return RAMP_STEP_0P4_US;
- else if (strcmp(step, "0P8_US") == 0)
- return RAMP_STEP_0P8_US;
- else if (strcmp(step, "1P6_US") == 0)
- return RAMP_STEP_1P6_US;
- else if (strcmp(step, "3P3_US") == 0)
- return RAMP_STEP_3P3_US;
- else if (strcmp(step, "6P7_US") == 0)
- return RAMP_STEP_6P7_US;
- else if (strcmp(step, "13P5_US") == 0)
- return RAMP_STEP_13P5_US;
- else
- return RAMP_STEP_27US;
-}
-
-static u8 qpnp_flash_led_get_droop_debounce_time(u8 val)
-{
- /*
- * return 10 us as default value if user specifies
- * a value un-supported
- */
- switch (val) {
- case 0:
- return 0;
- case 10:
- return 1;
- case 32:
- return 2;
- case 64:
- return 3;
- default:
- return 1;
- }
-}
-
-static u8 qpnp_flash_led_get_startup_dly(u8 val)
-{
- /*
- * return 128 us as default value if user specifies
- * a value un-supported
- */
- switch (val) {
- case 10:
- return 0;
- case 32:
- return 1;
- case 64:
- return 2;
- case 128:
- return 3;
- default:
- return 3;
- }
-}
-
-static int
-qpnp_flash_led_get_peripheral_type(struct qpnp_flash_led *led)
-{
- int rc;
- uint val;
-
- rc = regmap_read(led->regmap,
- FLASH_LED_PERIPHERAL_SUBTYPE(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read peripheral subtype\n");
- return -EINVAL;
- }
-
- return val;
-}
-
-static int qpnp_flash_led_module_disable(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node)
-{
- union power_supply_propval psy_prop;
- int rc;
- uint val, tmp;
-
- rc = regmap_read(led->regmap, FLASH_LED_STROBE_CTRL(led->base), &val);
- if (rc) {
- dev_err(&led->pdev->dev, "Unable to read strobe reg\n");
- return -EINVAL;
- }
-
- tmp = (~flash_node->trigger) & val;
- if (!tmp) {
- if (flash_node->type == TORCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Secure reg write failed\n");
- return -EINVAL;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- return -EINVAL;
- }
- }
-
- if (led->battery_psy &&
- led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
- !led->revid_data->rev3) {
- psy_prop.intval = false;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_TRIGGER,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to enble charger i/p current limit\n");
- return -EINVAL;
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK,
- FLASH_LED_MODULE_CTRL_DEFAULT);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- return -EINVAL;
- }
-
- if (led->pinctrl) {
- rc = pinctrl_select_state(led->pinctrl,
- led->gpio_state_suspend);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to disable GPIO\n");
- return -EINVAL;
- }
- led->gpio_enabled = false;
- }
-
- if (led->battery_psy) {
- psy_prop.intval = false;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_ACTIVE,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to setup OTG pulse skip enable\n");
- return -EINVAL;
- }
- }
- }
-
- if (flash_node->trigger & FLASH_LED0_TRIGGER) {
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, 0x00);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current register write failed\n");
- return -EINVAL;
- }
- }
-
- if (flash_node->trigger & FLASH_LED1_TRIGGER) {
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, 0x00);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current register write failed\n");
- return -EINVAL;
- }
- }
-
- if (flash_node->id == FLASH_LED_SWITCH)
- flash_node->trigger &= FLASH_LED_STROBE_TYPE_HW;
-
- return 0;
-}
-
-static enum
-led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
-{
- return led_cdev->brightness;
-}
-
-static int flash_regulator_parse_dt(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node) {
-
- int i = 0, rc;
- struct device_node *node = flash_node->cdev.dev->of_node;
- struct device_node *temp = NULL;
- const char *temp_string;
- u32 val;
-
- flash_node->reg_data = devm_kzalloc(&led->pdev->dev,
- sizeof(struct flash_regulator_data *) *
- flash_node->num_regulators,
- GFP_KERNEL);
- if (!flash_node->reg_data) {
- dev_err(&led->pdev->dev,
- "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- for_each_child_of_node(node, temp) {
- rc = of_property_read_string(temp, "regulator-name",
- &temp_string);
- if (!rc)
- flash_node->reg_data[i].reg_name = temp_string;
- else {
- dev_err(&led->pdev->dev,
- "Unable to read regulator name\n");
- return rc;
- }
-
- rc = of_property_read_u32(temp, "max-voltage", &val);
- if (!rc) {
- flash_node->reg_data[i].max_volt_uv = val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read max voltage\n");
- return rc;
- }
-
- i++;
- }
-
- return 0;
-}
-
-static int flash_regulator_setup(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node, bool on)
-{
- int i, rc = 0;
-
- if (on == false) {
- i = flash_node->num_regulators;
- goto error_regulator_setup;
- }
-
- for (i = 0; i < flash_node->num_regulators; i++) {
- flash_node->reg_data[i].regs =
- regulator_get(flash_node->cdev.dev,
- flash_node->reg_data[i].reg_name);
- if (IS_ERR(flash_node->reg_data[i].regs)) {
- rc = PTR_ERR(flash_node->reg_data[i].regs);
- dev_err(&led->pdev->dev,
- "Failed to get regulator\n");
- goto error_regulator_setup;
- }
-
- if (regulator_count_voltages(flash_node->reg_data[i].regs)
- > 0) {
- rc = regulator_set_voltage(flash_node->reg_data[i].regs,
- flash_node->reg_data[i].max_volt_uv,
- flash_node->reg_data[i].max_volt_uv);
- if (rc) {
- dev_err(&led->pdev->dev,
- "regulator set voltage failed\n");
- regulator_put(flash_node->reg_data[i].regs);
- goto error_regulator_setup;
- }
- }
- }
-
- return rc;
-
-error_regulator_setup:
- while (i--) {
- if (regulator_count_voltages(flash_node->reg_data[i].regs)
- > 0) {
- regulator_set_voltage(flash_node->reg_data[i].regs,
- 0, flash_node->reg_data[i].max_volt_uv);
- }
-
- regulator_put(flash_node->reg_data[i].regs);
- }
-
- return rc;
-}
-
-static int flash_regulator_enable(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node, bool on)
-{
- int i, rc = 0;
-
- if (on == false) {
- i = flash_node->num_regulators;
- goto error_regulator_enable;
- }
-
- for (i = 0; i < flash_node->num_regulators; i++) {
- rc = regulator_enable(flash_node->reg_data[i].regs);
- if (rc) {
- dev_err(&led->pdev->dev,
- "regulator enable failed\n");
- goto error_regulator_enable;
- }
- }
-
- return rc;
-
-error_regulator_enable:
- while (i--)
- regulator_disable(flash_node->reg_data[i].regs);
-
- return rc;
-}
-
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
- int *max_current)
-{
- struct led_classdev *led_cdev = trigger_to_lcdev(trig);
- struct flash_node_data *flash_node;
- struct qpnp_flash_led *led;
- int rc;
-
- if (!led_cdev) {
- pr_err("Invalid led_trigger provided\n");
- return -EINVAL;
- }
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
- dev_err(&led->pdev->dev, "Invalid options %d\n", options);
- return -EINVAL;
- }
-
- if (options & ENABLE_REGULATOR) {
- rc = flash_regulator_enable(led, flash_node, true);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "enable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
-
- if (options & DISABLE_REGULATOR) {
- rc = flash_regulator_enable(led, flash_node, false);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "disable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
-
- if (options & QUERY_MAX_CURRENT) {
- rc = qpnp_flash_led_get_max_avail_current(flash_node, led);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "query max current failed, rc=%d\n", rc);
- return rc;
- }
- *max_current = rc;
- }
-
- return 0;
-}
-
-static void qpnp_flash_led_work(struct work_struct *work)
-{
- struct flash_node_data *flash_node = container_of(work,
- struct flash_node_data, work);
- struct qpnp_flash_led *led = dev_get_drvdata(&flash_node->pdev->dev);
- union power_supply_propval psy_prop;
- int rc, brightness = flash_node->cdev.brightness;
- int max_curr_avail_ma = 0;
- int total_curr_ma = 0;
- int i;
- u8 val;
- uint temp;
-
- mutex_lock(&led->flash_led_lock);
-
- if (!brightness)
- goto turn_off;
-
- if (led->open_fault) {
- dev_err(&led->pdev->dev, "Open fault detected\n");
- mutex_unlock(&led->flash_led_lock);
- return;
- }
-
- if (!flash_node->flash_on && flash_node->num_regulators > 0) {
- rc = flash_regulator_enable(led, flash_node, true);
- if (rc) {
- mutex_unlock(&led->flash_led_lock);
- return;
- }
- }
-
- if (!led->gpio_enabled && led->pinctrl) {
- rc = pinctrl_select_state(led->pinctrl,
- led->gpio_state_active);
- if (rc) {
- dev_err(&led->pdev->dev, "failed to enable GPIO\n");
- goto error_enable_gpio;
- }
- led->gpio_enabled = true;
- }
-
- if (led->dbg_feature_en) {
- rc = qpnp_led_masked_write(led,
- INT_SET_TYPE(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "INT_SET_TYPE write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- IN_POLARITY_HIGH(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "IN_POLARITY_HIGH write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- INT_EN_SET(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev, "INT_EN_SET write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- INT_LATCHED_CLR(led->base),
- FLASH_STATUS_REG_MASK, 0x1F);
- if (rc) {
- dev_err(&led->pdev->dev,
- "INT_LATCHED_CLR write failed\n");
- goto exit_flash_led_work;
- }
- }
-
- if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
- flash_node->id != FLASH_LED_SWITCH) {
- led->flash_node[led->num_leds - 1].trigger |=
- (0x80 >> flash_node->id);
- if (flash_node->id == FLASH_LED_0)
- led->flash_node[led->num_leds - 1].prgm_current =
- flash_node->prgm_current;
- else if (flash_node->id == FLASH_LED_1)
- led->flash_node[led->num_leds - 1].prgm_current2 =
- flash_node->prgm_current;
- }
-
- if (flash_node->type == TORCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (flash_node->id == FLASH_LED_SWITCH) {
- val = (u8)(flash_node->prgm_current *
- FLASH_TORCH_MAX_LEVEL
- / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
-
- val = (u8)(flash_node->prgm_current2 *
- FLASH_TORCH_MAX_LEVEL
- / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Torch reg write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- val = (u8)(flash_node->prgm_current *
- FLASH_TORCH_MAX_LEVEL /
- flash_node->max_current);
- if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- rc = qpnp_led_masked_write(led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURRENT(led->base),
- FLASH_CURRENT_MASK, FLASH_TORCH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Max current reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (led->pdata->hdrm_sns_ch0_en ||
- led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- flash_node->trigger &
- FLASH_LED0_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- flash_node->trigger &
- FLASH_LED1_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger |
- FLASH_LED_STROBE_TYPE_HW),
- flash_node->trigger);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe reg write failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->type == FLASH) {
- if (flash_node->trigger & FLASH_LED0_TRIGGER)
- max_curr_avail_ma += flash_node->max_current;
- if (flash_node->trigger & FLASH_LED1_TRIGGER)
- max_curr_avail_ma += flash_node->max_current;
-
- psy_prop.intval = true;
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_ACTIVE,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to setup OTG pulse skip enable\n");
- goto exit_flash_led_work;
- }
-
- if (led->pdata->power_detect_en ||
- led->pdata->die_current_derate_en) {
- if (led->battery_psy) {
- power_supply_get_property(led->battery_psy,
- POWER_SUPPLY_PROP_STATUS,
- &psy_prop);
- if (psy_prop.intval < 0) {
- dev_err(&led->pdev->dev,
- "Invalid battery status\n");
- goto exit_flash_led_work;
- }
-
- if (psy_prop.intval ==
- POWER_SUPPLY_STATUS_CHARGING)
- led->charging_enabled = true;
- else if (psy_prop.intval ==
- POWER_SUPPLY_STATUS_DISCHARGING
- || psy_prop.intval ==
- POWER_SUPPLY_STATUS_NOT_CHARGING)
- led->charging_enabled = false;
- }
- max_curr_avail_ma =
- qpnp_flash_led_get_max_avail_current
- (flash_node, led);
- if (max_curr_avail_ma < 0) {
- dev_err(&led->pdev->dev,
- "Failed to get max avail curr\n");
- goto exit_flash_led_work;
- }
- }
-
- if (flash_node->id == FLASH_LED_SWITCH) {
- if (flash_node->trigger & FLASH_LED0_TRIGGER)
- total_curr_ma += flash_node->prgm_current;
- if (flash_node->trigger & FLASH_LED1_TRIGGER)
- total_curr_ma += flash_node->prgm_current2;
-
- if (max_curr_avail_ma < total_curr_ma) {
- flash_node->prgm_current =
- (flash_node->prgm_current *
- max_curr_avail_ma) / total_curr_ma;
- flash_node->prgm_current2 =
- (flash_node->prgm_current2 *
- max_curr_avail_ma) / total_curr_ma;
- }
-
- val = (u8)(flash_node->prgm_current *
- FLASH_MAX_LEVEL / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current_addr, FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Current register write failed\n");
- goto exit_flash_led_work;
- }
-
- val = (u8)(flash_node->prgm_current2 *
- FLASH_MAX_LEVEL / flash_node->max_current);
- rc = qpnp_led_masked_write(led,
- led->current2_addr, FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Current register write failed\n");
- goto exit_flash_led_work;
- }
- } else {
- if (max_curr_avail_ma < flash_node->prgm_current) {
- dev_err(&led->pdev->dev,
- "battery only supprots %d mA\n",
- max_curr_avail_ma);
- flash_node->prgm_current =
- (u16)max_curr_avail_ma;
- }
-
- val = (u8)(flash_node->prgm_current *
- FLASH_MAX_LEVEL
- / flash_node->max_current);
- if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(
- led,
- led->current_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(
- led,
- led->current2_addr,
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "current reg write failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- val = (u8)((flash_node->duration - FLASH_DURATION_DIVIDER)
- / FLASH_DURATION_DIVIDER);
- rc = qpnp_led_masked_write(led,
- FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Safety timer reg write failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURRENT(led->base),
- FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Max current reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (!led->charging_enabled) {
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Module enable reg write failed\n");
- goto exit_flash_led_work;
- }
-
- usleep_range(FLASH_RAMP_UP_DELAY_US_MIN,
- FLASH_RAMP_UP_DELAY_US_MAX);
- }
-
- if (led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
- !led->revid_data->rev3) {
- rc = power_supply_set_property(led->battery_psy,
- POWER_SUPPLY_PROP_FLASH_TRIGGER,
- &psy_prop);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to disable charger i/p curr limit\n");
- goto exit_flash_led_work;
- }
- }
-
- if (led->pdata->hdrm_sns_ch0_en ||
- led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- (flash_node->trigger &
- FLASH_LED0_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE));
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- (flash_node->trigger &
- FLASH_LED1_TRIGGER ?
- FLASH_LED_HDRM_SNS_ENABLE :
- FLASH_LED_HDRM_SNS_DISABLE));
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense enable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_0) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- } else if (flash_node->id == FLASH_LED_1) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_ENABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_led_work;
- }
- }
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger |
- FLASH_LED_STROBE_TYPE_HW),
- flash_node->trigger);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe reg write failed\n");
- goto exit_flash_led_work;
- }
-
- if (led->strobe_debug && led->dbg_feature_en) {
- udelay(2000);
- rc = regmap_read(led->regmap,
- FLASH_LED_FAULT_STATUS(led->base),
- &temp);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from addr= %x, rc(%d)\n",
- FLASH_LED_FAULT_STATUS(led->base), rc);
- goto exit_flash_led_work;
- }
- led->fault_reg = temp;
- }
- } else {
- pr_err("Both Torch and Flash cannot be select at same time\n");
- for (i = 0; i < led->num_leds; i++)
- led->flash_node[i].flash_on = false;
- goto turn_off;
- }
-
- flash_node->flash_on = true;
- mutex_unlock(&led->flash_led_lock);
-
- return;
-
-turn_off:
- if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
- flash_node->id != FLASH_LED_SWITCH)
- led->flash_node[led->num_leds - 1].trigger &=
- ~(0x80 >> flash_node->id);
- if (flash_node->type == TORCH) {
- /*
- * Checking LED fault status detects hardware open fault.
- * If fault occurs, all subsequent LED enablement requests
- * will be rejected to protect hardware.
- */
- rc = regmap_read(led->regmap,
- FLASH_LED_FAULT_STATUS(led->base), &temp);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to read out fault status register\n");
- goto exit_flash_led_work;
- }
-
- led->open_fault |= (val & FLASH_LED_OPEN_FAULT_DETECTED);
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- (flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
- | FLASH_LED_STROBE_TYPE_HW
- : flash_node->trigger
- | FLASH_LED_STROBE_TYPE_HW),
- FLASH_LED_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe disable failed\n");
- goto exit_flash_led_work;
- }
-
- usleep_range(FLASH_RAMP_DN_DELAY_US_MIN, FLASH_RAMP_DN_DELAY_US_MAX);
-exit_flash_hdrm_sns:
- if (led->pdata->hdrm_sns_ch0_en) {
- if (flash_node->id == FLASH_LED_0 ||
- flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_hdrm_sns;
- }
- }
- }
-
- if (led->pdata->hdrm_sns_ch1_en) {
- if (flash_node->id == FLASH_LED_1 ||
- flash_node->id == FLASH_LED_SWITCH) {
- rc = qpnp_led_masked_write(led,
- FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
- FLASH_LED_HDRM_SNS_ENABLE_MASK,
- FLASH_LED_HDRM_SNS_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Headroom sense disable failed\n");
- goto exit_flash_hdrm_sns;
- }
- }
- }
-exit_flash_led_work:
- rc = qpnp_flash_led_module_disable(led, flash_node);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- goto exit_flash_led_work;
- }
-error_enable_gpio:
- if (flash_node->flash_on && flash_node->num_regulators > 0)
- flash_regulator_enable(led, flash_node, false);
-
- flash_node->flash_on = false;
- mutex_unlock(&led->flash_led_lock);
-}
-
-static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct flash_node_data *flash_node;
- struct qpnp_flash_led *led;
-
- flash_node = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&flash_node->pdev->dev);
-
- if (value < LED_OFF) {
- pr_err("Invalid brightness value\n");
- return;
- }
-
- if (value > flash_node->cdev.max_brightness)
- value = flash_node->cdev.max_brightness;
-
- flash_node->cdev.brightness = value;
- if (led->flash_node[led->num_leds - 1].id ==
- FLASH_LED_SWITCH) {
- if (flash_node->type == TORCH)
- led->flash_node[led->num_leds - 1].type = TORCH;
- else if (flash_node->type == FLASH)
- led->flash_node[led->num_leds - 1].type = FLASH;
-
- led->flash_node[led->num_leds - 1].max_current
- = flash_node->max_current;
-
- if (flash_node->id == FLASH_LED_0 ||
- flash_node->id == FLASH_LED_1) {
- if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
- value = FLASH_LED_MIN_CURRENT_MA;
-
- flash_node->prgm_current = value;
- flash_node->flash_on = value ? true : false;
- } else if (flash_node->id == FLASH_LED_SWITCH) {
- if (!value) {
- flash_node->prgm_current = 0;
- flash_node->prgm_current2 = 0;
- }
- }
- } else {
- if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
- value = FLASH_LED_MIN_CURRENT_MA;
- flash_node->prgm_current = value;
- }
-
- queue_work(led->ordered_workq, &flash_node->work);
-}
-
-static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
-{
- int rc;
- u8 val, temp_val;
- uint val_int;
-
- rc = qpnp_led_masked_write(led,
- FLASH_MODULE_ENABLE_CTRL(led->base),
- FLASH_MODULE_ENABLE_MASK,
- FLASH_LED_MODULE_CTRL_DEFAULT);
- if (rc) {
- dev_err(&led->pdev->dev, "Module disable failed\n");
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- FLASH_STROBE_MASK, FLASH_LED_DISABLE);
- if (rc) {
- dev_err(&led->pdev->dev, "Strobe disable failed\n");
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_SAFETY);
- if (rc) {
- dev_err(&led->pdev->dev,
- "LED timer ctrl reg write failed(%d)\n", rc);
- return rc;
- }
-
- val = (u8)(led->pdata->headroom / FLASH_LED_HEADROOM_DIVIDER -
- FLASH_LED_HEADROOM_OFFSET);
- rc = qpnp_led_masked_write(led,
- FLASH_HEADROOM(led->base),
- FLASH_HEADROOM_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Headroom reg write failed\n");
- return rc;
- }
-
- val = qpnp_flash_led_get_startup_dly(led->pdata->startup_dly);
-
- rc = qpnp_led_masked_write(led,
- FLASH_STARTUP_DELAY(led->base),
- FLASH_STARTUP_DLY_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Startup delay reg write failed\n");
- return rc;
- }
-
- val = (u8)(led->pdata->clamp_current * FLASH_MAX_LEVEL /
- FLASH_LED_MAX_CURRENT_MA);
- rc = qpnp_led_masked_write(led,
- FLASH_CLAMP_CURRENT(led->base),
- FLASH_CURRENT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Clamp current reg write failed\n");
- return rc;
- }
-
- if (led->pdata->pmic_charger_support)
- val = FLASH_LED_FLASH_HW_VREG_OK;
- else
- val = FLASH_LED_FLASH_SW_VREG_OK;
- rc = qpnp_led_masked_write(led,
- FLASH_VREG_OK_FORCE(led->base),
- FLASH_VREG_OK_FORCE_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "VREG OK force reg write failed\n");
- return rc;
- }
-
- if (led->pdata->self_check_en)
- val = FLASH_MODULE_ENABLE;
- else
- val = FLASH_LED_DISABLE;
- rc = qpnp_led_masked_write(led,
- FLASH_FAULT_DETECT(led->base),
- FLASH_FAULT_DETECT_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Fault detect reg write failed\n");
- return rc;
- }
-
- val = 0x0;
- val |= led->pdata->mask3_en << FLASH_LED_MASK3_ENABLE_SHIFT;
- val |= FLASH_LED_MASK_MODULE_MASK2_ENABLE;
- rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
- FLASH_MASK_MODULE_CONTRL_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Mask module enable failed\n");
- return rc;
- }
-
- rc = regmap_read(led->regmap, FLASH_PERPH_RESET_CTRL(led->base),
- &val_int);
- if (rc) {
- dev_err(&led->pdev->dev,
- "Unable to read from address %x, rc(%d)\n",
- FLASH_PERPH_RESET_CTRL(led->base), rc);
- return -EINVAL;
- }
- val = (u8)val_int;
-
- if (led->pdata->follow_rb_disable) {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- return -EINVAL;
- }
-
- val |= FLASH_FOLLOW_OTST2_RB_MASK;
- rc = qpnp_led_masked_write(led,
- FLASH_PERPH_RESET_CTRL(led->base),
- FLASH_FOLLOW_OTST2_RB_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to reset OTST2_RB bit\n");
- return rc;
- }
- } else {
- rc = qpnp_led_masked_write(led,
- FLASH_LED_UNLOCK_SECURE(led->base),
- FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
- if (rc) {
- dev_err(&led->pdev->dev, "Secure reg write failed\n");
- return -EINVAL;
- }
-
- val &= ~FLASH_FOLLOW_OTST2_RB_MASK;
- rc = qpnp_led_masked_write(led,
- FLASH_PERPH_RESET_CTRL(led->base),
- FLASH_FOLLOW_OTST2_RB_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to reset OTST2_RB bit\n");
- return rc;
- }
- }
-
- if (!led->pdata->thermal_derate_en)
- val = 0x0;
- else {
- val = led->pdata->thermal_derate_en << 7;
- val |= led->pdata->thermal_derate_rate << 3;
- val |= (led->pdata->thermal_derate_threshold -
- FLASH_LED_THERMAL_THRESHOLD_MIN) /
- FLASH_LED_THERMAL_DEVIDER;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_THERMAL_DRATE(led->base),
- FLASH_THERMAL_DERATE_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Thermal derate reg write failed\n");
- return rc;
- }
-
- if (!led->pdata->current_ramp_en)
- val = 0x0;
- else {
- val = led->pdata->current_ramp_en << 7;
- val |= led->pdata->ramp_up_step << 3;
- val |= led->pdata->ramp_dn_step;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_CURRENT_RAMP(led->base),
- FLASH_CURRENT_RAMP_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "Current ramp reg write failed\n");
- return rc;
- }
-
- if (!led->pdata->vph_pwr_droop_en)
- val = 0x0;
- else {
- val = led->pdata->vph_pwr_droop_en << 7;
- val |= ((led->pdata->vph_pwr_droop_threshold -
- FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV) /
- FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER) << 4;
- temp_val =
- qpnp_flash_led_get_droop_debounce_time(
- led->pdata->vph_pwr_droop_debounce_time);
- if (temp_val == 0xFF) {
- dev_err(&led->pdev->dev, "Invalid debounce time\n");
- return temp_val;
- }
-
- val |= temp_val;
- }
- rc = qpnp_led_masked_write(led,
- FLASH_VPH_PWR_DROOP(led->base),
- FLASH_VPH_PWR_DROOP_MASK, val);
- if (rc) {
- dev_err(&led->pdev->dev, "VPH PWR droop reg write failed\n");
- return rc;
- }
-
- led->battery_psy = power_supply_get_by_name("battery");
- if (!led->battery_psy) {
- dev_err(&led->pdev->dev,
- "Failed to get battery power supply\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
- struct flash_node_data *flash_node)
-{
- const char *temp_string;
- struct device_node *node = flash_node->cdev.dev->of_node;
- struct device_node *temp = NULL;
- int rc = 0, num_regs = 0;
- u32 val;
-
- rc = of_property_read_string(node, "label", &temp_string);
- if (!rc) {
- if (strcmp(temp_string, "flash") == 0)
- flash_node->type = FLASH;
- else if (strcmp(temp_string, "torch") == 0)
- flash_node->type = TORCH;
- else if (strcmp(temp_string, "switch") == 0)
- flash_node->type = SWITCH;
- else {
- dev_err(&led->pdev->dev, "Wrong flash LED type\n");
- return -EINVAL;
- }
- } else if (rc < 0) {
- dev_err(&led->pdev->dev, "Unable to read flash type\n");
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- flash_node->prgm_current = val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read current\n");
- return rc;
- }
-
- rc = of_property_read_u32(node, "qcom,id", &val);
- if (!rc)
- flash_node->id = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read led ID\n");
- return rc;
- }
-
- if (flash_node->type == SWITCH || flash_node->type == FLASH) {
- rc = of_property_read_u32(node, "qcom,duration", &val);
- if (!rc)
- flash_node->duration = (u16)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read duration\n");
- return rc;
- }
- }
-
- switch (led->peripheral_type) {
- case FLASH_SUBTYPE_SINGLE:
- flash_node->trigger = FLASH_LED0_TRIGGER;
- break;
- case FLASH_SUBTYPE_DUAL:
- if (flash_node->id == FLASH_LED_0)
- flash_node->trigger = FLASH_LED0_TRIGGER;
- else if (flash_node->id == FLASH_LED_1)
- flash_node->trigger = FLASH_LED1_TRIGGER;
- break;
- default:
- dev_err(&led->pdev->dev, "Invalid peripheral type\n");
- }
-
- while ((temp = of_get_next_child(node, temp))) {
- if (of_find_property(temp, "regulator-name", NULL))
- num_regs++;
- }
-
- if (num_regs)
- flash_node->num_regulators = num_regs;
-
- return rc;
-}
-
-static int qpnp_flash_led_parse_common_dt(
- struct qpnp_flash_led *led,
- struct device_node *node)
-{
- int rc;
- u32 val, temp_val;
- const char *temp;
-
- led->pdata->headroom = FLASH_LED_HEADROOM_DEFAULT_MV;
- rc = of_property_read_u32(node, "qcom,headroom", &val);
- if (!rc)
- led->pdata->headroom = (u16)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read headroom\n");
- return rc;
- }
-
- led->pdata->startup_dly = FLASH_LED_STARTUP_DELAY_DEFAULT_US;
- rc = of_property_read_u32(node, "qcom,startup-dly", &val);
- if (!rc)
- led->pdata->startup_dly = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read startup delay\n");
- return rc;
- }
-
- led->pdata->clamp_current = FLASH_LED_CLAMP_CURRENT_DEFAULT_MA;
- rc = of_property_read_u32(node, "qcom,clamp-current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- led->pdata->clamp_current = (u16)val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev, "Unable to read clamp current\n");
- return rc;
- }
-
- led->pdata->pmic_charger_support =
- of_property_read_bool(node,
- "qcom,pmic-charger-support");
-
- led->pdata->self_check_en =
- of_property_read_bool(node, "qcom,self-check-enabled");
-
- led->pdata->thermal_derate_en =
- of_property_read_bool(node,
- "qcom,thermal-derate-enabled");
-
- if (led->pdata->thermal_derate_en) {
- led->pdata->thermal_derate_rate =
- FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT;
- rc = of_property_read_string(node, "qcom,thermal-derate-rate",
- &temp);
- if (!rc) {
- temp_val =
- qpnp_flash_led_get_thermal_derate_rate(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid thermal derate rate\n");
- return -EINVAL;
- }
-
- led->pdata->thermal_derate_rate = (u8)temp_val;
- } else {
- dev_err(&led->pdev->dev,
- "Unable to read thermal derate rate\n");
- return -EINVAL;
- }
-
- led->pdata->thermal_derate_threshold =
- FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C;
- rc = of_property_read_u32(node, "qcom,thermal-derate-threshold",
- &val);
- if (!rc)
- led->pdata->thermal_derate_threshold = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read thermal derate threshold\n");
- return rc;
- }
- }
-
- led->pdata->current_ramp_en =
- of_property_read_bool(node,
- "qcom,current-ramp-enabled");
- if (led->pdata->current_ramp_en) {
- led->pdata->ramp_up_step = FLASH_LED_RAMP_UP_STEP_DEFAULT_US;
- rc = of_property_read_string(node, "qcom,ramp_up_step", &temp);
- if (!rc) {
- temp_val = qpnp_flash_led_get_ramp_step(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid ramp up step values\n");
- return -EINVAL;
- }
- led->pdata->ramp_up_step = (u8)temp_val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read ramp up steps\n");
- return rc;
- }
-
- led->pdata->ramp_dn_step = FLASH_LED_RAMP_DN_STEP_DEFAULT_US;
- rc = of_property_read_string(node, "qcom,ramp_dn_step", &temp);
- if (!rc) {
- temp_val = qpnp_flash_led_get_ramp_step(temp);
- if (temp_val < 0) {
- dev_err(&led->pdev->dev,
- "Invalid ramp down step values\n");
- return rc;
- }
- led->pdata->ramp_dn_step = (u8)temp_val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read ramp down steps\n");
- return rc;
- }
- }
-
- led->pdata->vph_pwr_droop_en = of_property_read_bool(node,
- "qcom,vph-pwr-droop-enabled");
- if (led->pdata->vph_pwr_droop_en) {
- led->pdata->vph_pwr_droop_threshold =
- FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV;
- rc = of_property_read_u32(node,
- "qcom,vph-pwr-droop-threshold", &val);
- if (!rc) {
- led->pdata->vph_pwr_droop_threshold = (u16)val;
- } else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read VPH PWR droop threshold\n");
- return rc;
- }
-
- led->pdata->vph_pwr_droop_debounce_time =
- FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US;
- rc = of_property_read_u32(node,
- "qcom,vph-pwr-droop-debounce-time", &val);
- if (!rc)
- led->pdata->vph_pwr_droop_debounce_time = (u8)val;
- else if (rc != -EINVAL) {
- dev_err(&led->pdev->dev,
- "Unable to read VPH PWR droop debounce time\n");
- return rc;
- }
- }
-
- led->pdata->hdrm_sns_ch0_en = of_property_read_bool(node,
- "qcom,headroom-sense-ch0-enabled");
-
- led->pdata->hdrm_sns_ch1_en = of_property_read_bool(node,
- "qcom,headroom-sense-ch1-enabled");
-
- led->pdata->power_detect_en = of_property_read_bool(node,
- "qcom,power-detect-enabled");
-
- led->pdata->mask3_en = of_property_read_bool(node,
- "qcom,otst2-module-enabled");
-
- led->pdata->follow_rb_disable = of_property_read_bool(node,
- "qcom,follow-otst2-rb-disabled");
-
- led->pdata->die_current_derate_en = of_property_read_bool(node,
- "qcom,die-current-derate-enabled");
-
- if (led->pdata->die_current_derate_en) {
- led->vadc_dev = qpnp_get_vadc(&led->pdev->dev, "die-temp");
- if (IS_ERR(led->vadc_dev)) {
- pr_err("VADC channel property Missing\n");
- return -EINVAL;
- }
-
- if (of_find_property(node, "qcom,die-temp-threshold",
- &led->pdata->temp_threshold_num)) {
- if (led->pdata->temp_threshold_num > 0) {
- led->pdata->die_temp_threshold_degc =
- devm_kzalloc(&led->pdev->dev,
- led->pdata->temp_threshold_num,
- GFP_KERNEL);
-
- if (led->pdata->die_temp_threshold_degc
- == NULL) {
- dev_err(&led->pdev->dev,
- "failed to allocate die temp array\n");
- return -ENOMEM;
- }
- led->pdata->temp_threshold_num /=
- sizeof(unsigned int);
-
- rc = of_property_read_u32_array(node,
- "qcom,die-temp-threshold",
- led->pdata->die_temp_threshold_degc,
- led->pdata->temp_threshold_num);
- if (rc) {
- dev_err(&led->pdev->dev,
- "couldn't read temp threshold rc=%d\n",
- rc);
- return rc;
- }
- }
- }
-
- if (of_find_property(node, "qcom,die-temp-derate-current",
- &led->pdata->temp_derate_curr_num)) {
- if (led->pdata->temp_derate_curr_num > 0) {
- led->pdata->die_temp_derate_curr_ma =
- devm_kzalloc(&led->pdev->dev,
- led->pdata->temp_derate_curr_num,
- GFP_KERNEL);
- if (led->pdata->die_temp_derate_curr_ma
- == NULL) {
- dev_err(&led->pdev->dev,
- "failed to allocate die derate current array\n");
- return -ENOMEM;
- }
- led->pdata->temp_derate_curr_num /=
- sizeof(unsigned int);
-
- rc = of_property_read_u32_array(node,
- "qcom,die-temp-derate-current",
- led->pdata->die_temp_derate_curr_ma,
- led->pdata->temp_derate_curr_num);
- if (rc) {
- dev_err(&led->pdev->dev,
- "couldn't read temp limits rc =%d\n",
- rc);
- return rc;
- }
- }
- }
- if (led->pdata->temp_threshold_num !=
- led->pdata->temp_derate_curr_num) {
- pr_err("Both array size are not same\n");
- return -EINVAL;
- }
- }
-
- led->pinctrl = devm_pinctrl_get(&led->pdev->dev);
- if (IS_ERR_OR_NULL(led->pinctrl)) {
- dev_err(&led->pdev->dev, "Unable to acquire pinctrl\n");
- led->pinctrl = NULL;
- return 0;
- }
-
- led->gpio_state_active = pinctrl_lookup_state(led->pinctrl,
- "flash_led_enable");
- if (IS_ERR_OR_NULL(led->gpio_state_active)) {
- dev_err(&led->pdev->dev, "Cannot lookup LED active state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_active);
- }
-
- led->gpio_state_suspend = pinctrl_lookup_state(led->pinctrl,
- "flash_led_disable");
- if (IS_ERR_OR_NULL(led->gpio_state_suspend)) {
- dev_err(&led->pdev->dev, "Cannot lookup LED disable state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_suspend);
- }
-
- return 0;
-}
-
-static int qpnp_flash_led_probe(struct platform_device *pdev)
-{
- struct qpnp_flash_led *led;
- unsigned int base;
- struct device_node *node, *temp;
- struct dentry *root, *file;
- int rc, i = 0, j, num_leds = 0;
- u32 val;
-
- root = NULL;
- node = pdev->dev.of_node;
- if (node == NULL) {
- dev_info(&pdev->dev, "No flash device defined\n");
- return -ENODEV;
- }
-
- rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
- if (rc < 0) {
- dev_err(&pdev->dev,
- "Couldn't find reg in node = %s rc = %d\n",
- pdev->dev.of_node->full_name, rc);
- return rc;
- }
-
- led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
- if (!led)
- return -ENOMEM;
-
- led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!led->regmap) {
- dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
- return -EINVAL;
- }
-
- led->base = base;
- led->pdev = pdev;
- led->current_addr = FLASH_LED0_CURRENT(led->base);
- led->current2_addr = FLASH_LED1_CURRENT(led->base);
-
- led->pdata = devm_kzalloc(&pdev->dev, sizeof(*led->pdata), GFP_KERNEL);
- if (!led->pdata)
- return -ENOMEM;
-
- led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
- if (led->peripheral_type < 0) {
- dev_err(&pdev->dev, "Failed to get peripheral type\n");
- return rc;
- }
-
- rc = qpnp_flash_led_parse_common_dt(led, node);
- if (rc) {
- dev_err(&pdev->dev,
- "Failed to get common config for flash LEDs\n");
- return rc;
- }
-
- rc = qpnp_flash_led_init_settings(led);
- if (rc) {
- dev_err(&pdev->dev, "Failed to initialize flash LED\n");
- return rc;
- }
-
- rc = qpnp_get_pmic_revid(led);
- if (rc)
- return rc;
-
- temp = NULL;
- while ((temp = of_get_next_child(node, temp)))
- num_leds++;
-
- if (!num_leds)
- return -ECHILD;
-
- led->flash_node = devm_kzalloc(&pdev->dev,
- (sizeof(struct flash_node_data) * num_leds),
- GFP_KERNEL);
- if (!led->flash_node) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
-
- mutex_init(&led->flash_led_lock);
-
- led->ordered_workq = alloc_ordered_workqueue("flash_led_workqueue", 0);
- if (!led->ordered_workq) {
- dev_err(&pdev->dev, "Failed to allocate ordered workqueue\n");
- return -ENOMEM;
- }
-
- for_each_child_of_node(node, temp) {
- led->flash_node[i].cdev.brightness_set =
- qpnp_flash_led_brightness_set;
- led->flash_node[i].cdev.brightness_get =
- qpnp_flash_led_brightness_get;
- led->flash_node[i].pdev = pdev;
-
- INIT_WORK(&led->flash_node[i].work, qpnp_flash_led_work);
- rc = of_property_read_string(temp, "qcom,led-name",
- &led->flash_node[i].cdev.name);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "Unable to read flash name\n");
- return rc;
- }
-
- rc = of_property_read_string(temp, "qcom,default-led-trigger",
- &led->flash_node[i].cdev.default_trigger);
- if (rc < 0) {
- dev_err(&led->pdev->dev,
- "Unable to read trigger name\n");
- return rc;
- }
-
- rc = of_property_read_u32(temp, "qcom,max-current", &val);
- if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
- led->flash_node[i].max_current = (u16)val;
- led->flash_node[i].cdev.max_brightness = val;
- } else {
- dev_err(&led->pdev->dev,
- "Unable to read max current\n");
- return rc;
- }
- rc = led_classdev_register(&pdev->dev,
- &led->flash_node[i].cdev);
- if (rc) {
- dev_err(&pdev->dev, "Unable to register led\n");
- goto error_led_register;
- }
-
- led->flash_node[i].cdev.dev->of_node = temp;
-
- rc = qpnp_flash_led_parse_each_led_dt(led, &led->flash_node[i]);
- if (rc) {
- dev_err(&pdev->dev,
- "Failed to parse config for each LED\n");
- goto error_led_register;
- }
-
- if (led->flash_node[i].num_regulators) {
- rc = flash_regulator_parse_dt(led, &led->flash_node[i]);
- if (rc) {
- dev_err(&pdev->dev,
- "Unable to parse regulator data\n");
- goto error_led_register;
- }
-
- rc = flash_regulator_setup(led, &led->flash_node[i],
- true);
- if (rc) {
- dev_err(&pdev->dev,
- "Unable to set up regulator\n");
- goto error_led_register;
- }
- }
-
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
- rc =
- sysfs_create_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- if (rc)
- goto error_led_register;
- }
-
- i++;
- }
-
- led->num_leds = i;
-
- root = debugfs_create_dir("flashLED", NULL);
- if (IS_ERR_OR_NULL(root)) {
- pr_err("Error creating top level directory err%ld",
- (long)root);
- if (PTR_ERR(root) == -ENODEV)
- pr_err("debugfs is not enabled in kernel");
- goto error_led_debugfs;
- }
-
- led->dbgfs_root = root;
- file = debugfs_create_file("enable_debug", 0600, root, led,
- &flash_led_dfs_dbg_feature_fops);
- if (!file) {
- pr_err("error creating 'enable_debug' entry\n");
- goto error_led_debugfs;
- }
-
- file = debugfs_create_file("latched", 0600, root, led,
- &flash_led_dfs_latched_reg_fops);
- if (!file) {
- pr_err("error creating 'latched' entry\n");
- goto error_led_debugfs;
- }
-
- file = debugfs_create_file("strobe", 0600, root, led,
- &flash_led_dfs_strobe_reg_fops);
- if (!file) {
- pr_err("error creating 'strobe' entry\n");
- goto error_led_debugfs;
- }
-
- dev_set_drvdata(&pdev->dev, led);
-
- return 0;
-
-error_led_debugfs:
- i = led->num_leds - 1;
- j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
-error_led_register:
- for (; i >= 0; i--) {
- for (; j >= 0; j--)
- sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
- led_classdev_unregister(&led->flash_node[i].cdev);
- }
- debugfs_remove_recursive(root);
- mutex_destroy(&led->flash_led_lock);
- destroy_workqueue(led->ordered_workq);
-
- return rc;
-}
-
-static int qpnp_flash_led_remove(struct platform_device *pdev)
-{
- struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
- int i, j;
-
- for (i = led->num_leds - 1; i >= 0; i--) {
- if (led->flash_node[i].reg_data) {
- if (led->flash_node[i].flash_on)
- flash_regulator_enable(led,
- &led->flash_node[i], false);
- flash_regulator_setup(led, &led->flash_node[i],
- false);
- }
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
- sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- led_classdev_unregister(&led->flash_node[i].cdev);
- }
- debugfs_remove_recursive(led->dbgfs_root);
- mutex_destroy(&led->flash_led_lock);
- destroy_workqueue(led->ordered_workq);
-
- return 0;
-}
-
-static const struct of_device_id spmi_match_table[] = {
- { .compatible = "qcom,qpnp-flash-led",},
- { },
-};
-
-static struct platform_driver qpnp_flash_led_driver = {
- .driver = {
- .name = "qcom,qpnp-flash-led",
- .of_match_table = spmi_match_table,
- },
- .probe = qpnp_flash_led_probe,
- .remove = qpnp_flash_led_remove,
-};
-
-static int __init qpnp_flash_led_init(void)
-{
- return platform_driver_register(&qpnp_flash_led_driver);
-}
-late_initcall(qpnp_flash_led_init);
-
-static void __exit qpnp_flash_led_exit(void)
-{
- platform_driver_unregister(&qpnp_flash_led_driver);
-}
-module_exit(qpnp_flash_led_exit);
-
-MODULE_DESCRIPTION("QPNP Flash LED driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("leds:leds-qpnp-flash");
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index f18022b..568c9f9 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -537,6 +537,11 @@
{
int i, rc;
u8 reg;
+ u16 low_limit = WLED_MAX_LEVEL_4095 * 4 / 1000;
+
+ /* WLED's lower limit of operation is 0.4% */
+ if (level > 0 && level < low_limit)
+ level = low_limit;
/* set brightness registers */
for (i = 0; i < wled->max_strings; i++) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 68ce696f..a315268 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -18,6 +18,7 @@
#include <linux/timer.h>
#include <media/cam_icp.h>
#include <linux/iopoll.h>
+#include <soc/qcom/socinfo.h>
#include "cam_io_util.h"
#include "hfi_reg.h"
@@ -38,6 +39,9 @@
#define HFI_VERSION_INFO_STEP_BMSK 0xFF
#define HFI_VERSION_INFO_STEP_SHFT 0
+#define SOC_VERSION_HW1 0x10000
+#define SOC_VERSION_HW2 0x20000
+
static struct hfi_info *g_hfi;
unsigned int g_icp_mmu_hdl;
static DEFINE_MUTEX(hfi_cmd_q_mutex);
@@ -350,7 +354,7 @@
struct hfi_qtbl *qtbl;
struct hfi_qtbl_hdr *qtbl_hdr;
struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
- uint32_t hw_version, fw_version, status = 0;
+ uint32_t hw_version, soc_version, fw_version, status = 0;
mutex_lock(&hfi_cmd_q_mutex);
mutex_lock(&hfi_msg_q_mutex);
@@ -370,7 +374,7 @@
memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map));
g_hfi->hfi_state = HFI_DEINIT;
-
+ soc_version = socinfo_get_version();
if (debug) {
cam_io_w_mb(
(uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN |
@@ -382,7 +386,9 @@
icp_base + HFI_REG_A5_CSR_A5_CONTROL);
} else {
cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
- ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI,
+ ICP_FLAG_CSR_WAKE_UP_EN |
+ ((soc_version == SOC_VERSION_HW1) ?
+ (ICP_CSR_EN_CLKGATE_WFI) : (0x0)),
icp_base + HFI_REG_A5_CSR_A5_CONTROL);
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index f878403..5055e8d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -652,9 +652,7 @@
return -ENOMEM;
abort_cmd.size =
- sizeof(struct hfi_cmd_ipebps_async) +
- sizeof(struct hfi_cmd_abort_destroy) -
- sizeof(abort_cmd.payload.direct);
+ sizeof(struct hfi_cmd_ipebps_async);
abort_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
abort_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT;
@@ -706,9 +704,7 @@
return -ENOMEM;
destroy_cmd.size =
- sizeof(struct hfi_cmd_ipebps_async) +
- sizeof(struct ipe_bps_destroy) -
- sizeof(destroy_cmd.payload.direct);
+ sizeof(struct hfi_cmd_ipebps_async);
destroy_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 5d7a1b9..c041eef 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -36,6 +36,9 @@
#define CAM_VFE_RDI_BUS_DEFAULT_WIDTH 0xFF01
#define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFF01
+#define ALIGNUP(value, alignment) \
+ ((value + alignment - 1) / alignment * alignment)
+
#define MAX_BUF_UPDATE_REG_NUM \
(sizeof(struct cam_vfe_bus_ver2_reg_offset_bus_client)/4)
#define MAX_REG_VAL_PAIR_SIZE \
@@ -732,9 +735,22 @@
rsrc_data->index == 7 || rsrc_data->index == 8) {
/* Write master 3, 4 - for Full OUT , 7-8 FD OUT */
switch (rsrc_data->format) {
- case CAM_FORMAT_UBWC_NV12:
case CAM_FORMAT_UBWC_NV12_4R:
rsrc_data->en_ubwc = 1;
+ rsrc_data->width = ALIGNUP(rsrc_data->width, 64);
+ switch (plane) {
+ case PLANE_C:
+ rsrc_data->height /= 2;
+ break;
+ case PLANE_Y:
+ break;
+ default:
+ CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ return -EINVAL;
+ }
+ break;
+ case CAM_FORMAT_UBWC_NV12:
+ rsrc_data->en_ubwc = 1;
/* Fall through for NV12 */
case CAM_FORMAT_NV21:
case CAM_FORMAT_NV12:
@@ -751,9 +767,22 @@
break;
case CAM_FORMAT_UBWC_TP10:
rsrc_data->en_ubwc = 1;
- /* Fall through for LINEAR TP10 */
+ rsrc_data->width =
+ ALIGNUP(rsrc_data->width, 48) * 4 / 3;
+ switch (plane) {
+ case PLANE_C:
+ rsrc_data->height /= 2;
+ break;
+ case PLANE_Y:
+ break;
+ default:
+ CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ return -EINVAL;
+ }
+ break;
case CAM_FORMAT_TP10:
- rsrc_data->width = rsrc_data->width * 4 / 3;
+ rsrc_data->width =
+ ALIGNUP(rsrc_data->width, 3) * 4 / 3;
switch (plane) {
case PLANE_C:
rsrc_data->height /= 2;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index b0fe8db..0704602 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -915,6 +915,44 @@
}
/*
+ * sde_rotator_req_wait_for_idle - wait for hw for a request to be idle
+ * @mgr: Pointer to rotator manager
+ * @req: Pointer to rotation request
+ */
+static void sde_rotator_req_wait_for_idle(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req)
+{
+ struct sde_rot_queue *queue;
+ struct sde_rot_hw_resource *hw;
+ int i, ret;
+
+ if (!mgr || !req) {
+ SDEROT_ERR("invalid params\n");
+ return;
+ }
+
+ for (i = 0; i < req->count; i++) {
+ queue = req->entries[i].commitq;
+ if (!queue || !queue->hw)
+ continue;
+ hw = queue->hw;
+ while (atomic_read(&hw->num_active) > 1) {
+ sde_rot_mgr_unlock(mgr);
+ ret = wait_event_timeout(hw->wait_queue,
+ atomic_read(&hw->num_active) <= 1,
+ msecs_to_jiffies(mgr->hwacquire_timeout));
+ sde_rot_mgr_lock(mgr);
+ if (!ret) {
+ SDEROT_ERR(
+ "timeout waiting for hw idle, a:%d\n",
+ atomic_read(&hw->num_active));
+ return;
+ }
+ }
+ }
+}
+
+/*
* sde_rotator_get_hw_resource - block waiting for hw availability or timeout
* @queue: Pointer to rotator queue
* @entry: Pointer to rotation entry
@@ -1220,6 +1258,11 @@
return;
}
+ if (!req->entries) {
+ SDEROT_DBG("no entries in request\n");
+ return;
+ }
+
for (i = 0; i < req->count; i++) {
entry = req->entries + i;
queue = entry->commitq;
@@ -1542,10 +1585,23 @@
goto error;
}
+ if (entry->item.ts)
+ entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
+
+ ret = sde_rotator_req_wait_start(mgr, request);
+ if (ret) {
+ SDEROT_WARN("timeout waiting for inline start\n");
+ SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+ SDE_ROT_EVTLOG_ERROR);
+ goto kickoff_error;
+ }
+
ret = mgr->ops_kickoff_entry(hw, entry);
if (ret) {
SDEROT_ERR("fail to do kickoff %d\n", ret);
- goto error;
+ SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+ SDE_ROT_EVTLOG_ERROR);
+ goto kickoff_error;
}
if (entry->item.ts)
@@ -1556,6 +1612,13 @@
kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work);
sde_rot_mgr_unlock(mgr);
return;
+kickoff_error:
+ /*
+ * Wait for any pending operations to complete before cancelling this
+ * one so that the system is left in a consistent state.
+ */
+ sde_rotator_req_wait_for_idle(mgr, request);
+ mgr->ops_cancel_hw(hw, entry);
error:
sde_smmu_ctrl(0);
smmu_error:
@@ -1609,18 +1672,6 @@
entry->item.flags,
entry->dnsc_factor_w, entry->dnsc_factor_h);
- ret = wait_for_completion_timeout(
- &entry->item.inline_start,
- msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
- if (!ret) {
- SDEROT_WARN("timeout waiting for inline start\n");
- SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
- SDE_ROT_EVTLOG_ERROR);
- }
-
- if (entry->item.ts)
- entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
-
SDEROT_EVTLOG(entry->item.session_id, 0);
ret = mgr->ops_wait_for_entry(hw, entry);
if (ret) {
@@ -2164,34 +2215,6 @@
return ret;
}
-/*
- * sde_rotator_commit_request - commit the request to hardware
- * @mgr: pointer to rotator manager
- * @private: pointer to per file context
- * @req: pointer to rotation request
- *
- * This differs from sde_rotator_queue_request in that this
- * function will wait until request is committed to hardware.
- */
-void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
- struct sde_rot_file_private *ctx,
- struct sde_rot_entry_container *req)
-{
- int i;
-
- if (!mgr || !ctx || !req || !req->entries) {
- SDEROT_ERR("null parameters\n");
- return;
- }
-
- sde_rotator_queue_request(mgr, ctx, req);
-
- sde_rot_mgr_unlock(mgr);
- for (i = 0; i < req->count; i++)
- kthread_flush_work(&req->entries[i].commit_work);
- sde_rot_mgr_lock(mgr);
-}
-
static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
struct sde_rot_file_private *private, u32 session_id)
{
@@ -2408,26 +2431,67 @@
return req;
}
-void sde_rotator_req_reset_start(struct sde_rot_entry_container *req)
+void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req)
{
int i;
- if (!req)
+ if (!mgr || !req)
return;
for (i = 0; i < req->count; i++)
reinit_completion(&req->entries[i].item.inline_start);
}
-void sde_rotator_req_set_start(struct sde_rot_entry_container *req)
+void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req)
{
+ struct kthread_work *commit_work;
int i;
- if (!req)
+ if (!mgr || !req || !req->entries)
return;
+ /* signal ready to start */
for (i = 0; i < req->count; i++)
complete_all(&req->entries[i].item.inline_start);
+
+ for (i = 0; i < req->count; i++) {
+ commit_work = &req->entries[i].commit_work;
+
+ SDEROT_EVTLOG(i, req->count);
+
+ sde_rot_mgr_unlock(mgr);
+ kthread_flush_work(commit_work);
+ sde_rot_mgr_lock(mgr);
+ }
+}
+
+int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req)
+{
+ struct completion *inline_start;
+ int i, ret;
+
+ if (!mgr || !req || !req->entries)
+ return -EINVAL;
+
+ /* only wait for sbuf mode */
+ if (!mgr->sbuf_ctx || !req->count ||
+ mgr->sbuf_ctx != req->entries[0].private)
+ return 0;
+
+ for (i = 0; i < req->count; i++) {
+ inline_start = &req->entries[i].item.inline_start;
+
+ sde_rot_mgr_unlock(mgr);
+ ret = wait_for_completion_timeout(inline_start,
+ msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
+ sde_rot_mgr_lock(mgr);
+ }
+
+ /* wait call returns zero on timeout */
+ return ret ? 0 : -EBUSY;
}
void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 3d368a1..eb8cb88 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -115,8 +115,8 @@
SDE_ROTATOR_TS_FENCE, /* wait for source buffer fence */
SDE_ROTATOR_TS_QUEUE, /* wait for h/w resource */
SDE_ROTATOR_TS_COMMIT, /* prepare h/w command */
+ SDE_ROTATOR_TS_START, /* wait for h/w kickoff rdy (inline) */
SDE_ROTATOR_TS_FLUSH, /* initiate h/w processing */
- SDE_ROTATOR_TS_START, /* h/w triggered (if inline) */
SDE_ROTATOR_TS_DONE, /* receive h/w completion */
SDE_ROTATOR_TS_RETIRE, /* signal destination buffer fence */
SDE_ROTATOR_TS_SRCDQB, /* dequeue source buffer */
@@ -448,6 +448,8 @@
int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
struct sde_rot_entry *entry);
+ int (*ops_cancel_hw)(struct sde_rot_hw_resource *hw,
+ struct sde_rot_entry *entry);
int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw,
struct sde_rot_entry *entry);
int (*ops_wait_for_entry)(struct sde_rot_hw_resource *hw,
@@ -622,20 +624,33 @@
* indicator that allows the rotator to delay its rotator
* timeout waiting until such time as the inline rotation has
* really started.
+ * @mgr: Pointer to rotator manager
* @req: Pointer to rotation request
*/
-void sde_rotator_req_reset_start(struct sde_rot_entry_container *req);
+void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req);
/*
* sde_rotator_req_set_start - set inline h/w 'start' indicator
+ * @mgr: Pointer to rotator manager
* @req: Pointer to rotation request
*/
-void sde_rotator_req_set_start(struct sde_rot_entry_container *req);
+void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req);
+
+/*
+ * sde_rotator_req_wait_start - wait for inline h/w 'start' indicator
+ * @mgr: Pointer to rotator manager
+ * @req: Pointer to rotation request
+ * return: Zero on success
+ */
+int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
+ struct sde_rot_entry_container *req);
/*
* sde_rotator_req_finish - notify manager that client is finished with the
* given request and manager can release the request as required
- * @rot_dev: Pointer to rotator device
+ * @mgr: Pointer to rotator manager
* @private: Pointer to rotator manager per file context
* @req: Pointer to rotation request
* return: none
@@ -668,18 +683,6 @@
struct sde_rot_entry_container *req);
/*
- * sde_rotator_commit_request - queue/schedule the given request and wait
- * until h/w commit
- * @rot_dev: Pointer to rotator device
- * @private: Pointer to rotator manager per file context
- * @req: Pointer to rotation request
- * return: 0 if success; error code otherwise
- */
-void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
- struct sde_rot_file_private *ctx,
- struct sde_rot_entry_container *req);
-
-/*
* sde_rotator_verify_config_all - verify given rotation configuration
* @rot_dev: Pointer to rotator device
* @config: Pointer to rotator configuration
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 2a9573d..46f64d2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -793,7 +793,7 @@
start_time));
seq_printf(s,
- "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld st:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
+ "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld st:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
i,
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
ts[SDE_ROTATOR_TS_SRCQB])),
@@ -803,12 +803,12 @@
ts[SDE_ROTATOR_TS_FENCE])),
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_COMMIT],
ts[SDE_ROTATOR_TS_QUEUE])),
- ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
- ts[SDE_ROTATOR_TS_COMMIT])),
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_START],
- ts[SDE_ROTATOR_TS_FLUSH])),
- ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
+ ts[SDE_ROTATOR_TS_COMMIT])),
+ ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
ts[SDE_ROTATOR_TS_START])),
+ ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
+ ts[SDE_ROTATOR_TS_FLUSH])),
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
ts[SDE_ROTATOR_TS_DONE])),
ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_SRCDQB],
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index acd4b7d..4ad960d8 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1686,9 +1686,9 @@
goto error_handle_request;
}
- sde_rotator_req_reset_start(req);
+ sde_rotator_req_reset_start(rot_dev->mgr, req);
- sde_rotator_commit_request(rot_dev->mgr, ctx->private, req);
+ sde_rotator_queue_request(rot_dev->mgr, ctx->private, req);
request->committed = true;
@@ -1703,7 +1703,7 @@
}
request = cmd->priv_handle;
- sde_rotator_req_set_start(request->req);
+ sde_rotator_req_set_start(rot_dev->mgr, request->req);
} else if (cmd_type == SDE_ROTATOR_INLINE_CMD_CLEANUP) {
if (!cmd->priv_handle) {
ret = -EINVAL;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 1b4913b..89ad438 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -343,6 +343,12 @@
return ret;
}
+static int sde_rotator_cancel_hw(struct sde_rot_hw_resource *hw,
+ struct sde_rot_entry *entry)
+{
+ return 0;
+}
+
static int sde_rotator_kickoff_entry(struct sde_rot_hw_resource *hw,
struct sde_rot_entry *entry)
{
@@ -684,6 +690,7 @@
mgr->hw_data = hw_data;
mgr->ops_config_hw = sde_rotator_config_hw;
+ mgr->ops_cancel_hw = sde_rotator_cancel_hw;
mgr->ops_kickoff_entry = sde_rotator_kickoff_entry;
mgr->ops_wait_for_entry = sde_rotator_wait_for_entry;
mgr->ops_hw_alloc = sde_rotator_hw_alloc_ext;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 3c47dd7..2f2a439 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2522,6 +2522,55 @@
}
/*
+ * sde_hw_rotator_cancel - cancel hw configuration for the given rotation entry
+ * @hw: Pointer to rotator resource
+ * @entry: Pointer to rotation entry
+ *
+ * This function cancels a previously configured rotation entry.
+ */
+static int sde_hw_rotator_cancel(struct sde_rot_hw_resource *hw,
+ struct sde_rot_entry *entry)
+{
+ struct sde_hw_rotator *rot;
+ struct sde_hw_rotator_resource_info *resinfo;
+ struct sde_hw_rotator_context *ctx;
+ unsigned long flags;
+
+ if (!hw || !entry) {
+ SDEROT_ERR("null hw resource/entry\n");
+ return -EINVAL;
+ }
+
+ resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
+ rot = resinfo->rot;
+
+ /* Lookup rotator context from session-id */
+ ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id,
+ entry->item.sequence_id, hw->wb_id);
+ if (!ctx) {
+ SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
+ entry->item.session_id);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&rot->rotisr_lock, flags);
+ sde_hw_rotator_update_swts(rot, ctx, ctx->timestamp);
+ spin_unlock_irqrestore(&rot->rotisr_lock, flags);
+
+ SDEROT_EVTLOG(entry->item.session_id, ctx->timestamp);
+
+ if (rot->dbgmem) {
+ sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf);
+ sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf);
+ }
+
+ /* Current rotator context job is finished, time to free up */
+ sde_hw_rotator_free_rotctx(rot, ctx);
+
+ return 0;
+}
+
+/*
* sde_hw_rotator_kickoff - kickoff processing on the given entry
* @hw: Pointer to rotator resource
* @entry: Pointer to rotation entry
@@ -3331,6 +3380,7 @@
mgr->ops_hw_alloc = sde_hw_rotator_alloc_ext;
mgr->ops_hw_free = sde_hw_rotator_free_ext;
mgr->ops_config_hw = sde_hw_rotator_config;
+ mgr->ops_cancel_hw = sde_hw_rotator_cancel;
mgr->ops_kickoff_entry = sde_hw_rotator_kickoff;
mgr->ops_wait_for_entry = sde_hw_rotator_wait4done;
mgr->ops_hw_validate_entry = sde_hw_rotator_validate_entry;
@@ -3349,8 +3399,11 @@
goto error_parse_dt;
rot->irq_num = platform_get_irq(mgr->pdev, 0);
- if (rot->irq_num < 0) {
- SDEROT_ERR("fail to get rotator irq\n");
+ if (rot->irq_num == -EPROBE_DEFER) {
+ SDEROT_INFO("irq master master not ready, defer probe\n");
+ return -EPROBE_DEFER;
+ } else if (rot->irq_num < 0) {
+ SDEROT_ERR("fail to get rotator irq, fallback to polling\n");
} else {
if (rot->mode == ROT_REGDMA_OFF)
ret = devm_request_threaded_irq(&mgr->pdev->dev,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index b6c0d57..85db6f0 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1605,6 +1605,9 @@
HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION;
hfi = (struct hfi_vpe_color_space_conversion *)
&pkt->rg_property_data[1];
+
+ hfi->input_color_primaries = hal->input_color_primaries;
+ hfi->custom_matrix_enabled = hal->custom_matrix_enabled;
memcpy(hfi->csc_matrix, hal->csc_matrix,
sizeof(hfi->csc_matrix));
memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias));
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 0eb6d39..dfb2ad5 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -42,25 +42,6 @@
#define MIN_NUM_ENC_OUTPUT_BUFFERS 4
#define MIN_NUM_ENC_CAPTURE_BUFFERS 5
-/*
- * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
- * coeffs are converted to s4.9 format (e.g. -22 converted to ((1 << 13) - 22)
- * 3x3 transformation matrix coefficients in s4.9 fixed point format
- */
-static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
- 470, 8170, 8148, 0, 490, 50, 0, 34, 483
-};
-
-/* offset coefficients in s9 fixed point format */
-static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
- 34, 0, 4
-};
-
-/* clamping value for Y/U/V([min,max] for Y/U/V) */
-static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
- 16, 235, 16, 240, 16, 240
-};
-
static const char *const mpeg_video_rate_control[] = {
"No Rate Control",
"VBR VFR",
@@ -1046,6 +1027,15 @@
.default_value = 0,
.step = 1,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX,
+ .name = "Enable/Disable CSC Custom Matrix",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ },
};
@@ -1124,7 +1114,8 @@
},
};
-static int msm_venc_set_csc(struct msm_vidc_inst *inst);
+static int msm_venc_set_csc(struct msm_vidc_inst *inst,
+ u32 color_primaries, u32 custom_matrix);
static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
{
@@ -1198,6 +1189,7 @@
struct hal_video_signal_info signal_info = {0};
struct hal_vui_timing_info vui_timing_info = {0};
enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
+ u32 color_primaries, custom_matrix;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -1898,11 +1890,23 @@
break;
}
case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC:
- if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) {
- rc = msm_venc_set_csc(inst);
- if (rc)
- dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
- }
+ if (ctrl->val != V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE)
+ break;
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+ color_primaries = temp_ctrl->val;
+ temp_ctrl =
+ TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX);
+ custom_matrix = temp_ctrl->val;
+ rc = msm_venc_set_csc(inst, color_primaries, custom_matrix);
+ if (rc)
+ dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX:
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+ color_primaries = temp_ctrl->val;
+ rc = msm_venc_set_csc(inst, color_primaries, ctrl->val);
+ if (rc)
+ dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
{
@@ -2291,22 +2295,42 @@
return rc;
}
-static int msm_venc_set_csc(struct msm_vidc_inst *inst)
+static int msm_venc_set_csc(struct msm_vidc_inst *inst,
+ u32 color_primaries, u32 custom_matrix)
{
int rc = 0;
int count = 0;
struct hal_vpe_color_space_conversion vpe_csc;
+ struct msm_vidc_platform_resources *resources;
+ u32 *bias_coeff = NULL;
+ u32 *csc_limit = NULL;
+ u32 *csc_matrix = NULL;
- while (count < HAL_MAX_MATRIX_COEFFS) {
- if (count < HAL_MAX_BIAS_COEFFS)
- vpe_csc.csc_bias[count] =
- vpe_csc_601_to_709_bias_coeff[count];
- if (count < HAL_MAX_LIMIT_COEFFS)
- vpe_csc.csc_limit[count] =
- vpe_csc_601_to_709_limit_coeff[count];
- vpe_csc.csc_matrix[count] =
- vpe_csc_601_to_709_matrix_coeff[count];
- count = count + 1;
+ resources = &(inst->core->resources);
+ bias_coeff =
+ resources->csc_coeff_data->vpe_csc_custom_bias_coeff;
+ csc_limit =
+ resources->csc_coeff_data->vpe_csc_custom_limit_coeff;
+ csc_matrix =
+ resources->csc_coeff_data->vpe_csc_custom_matrix_coeff;
+
+ vpe_csc.input_color_primaries = color_primaries;
+ /* Custom bias, matrix & limit */
+ vpe_csc.custom_matrix_enabled = custom_matrix;
+
+ if (vpe_csc.custom_matrix_enabled && bias_coeff != NULL
+ && csc_limit != NULL && csc_matrix != NULL) {
+ while (count < HAL_MAX_MATRIX_COEFFS) {
+ if (count < HAL_MAX_BIAS_COEFFS)
+ vpe_csc.csc_bias[count] =
+ bias_coeff[count];
+ if (count < HAL_MAX_LIMIT_COEFFS)
+ vpe_csc.csc_limit[count] =
+ csc_limit[count];
+ vpe_csc.csc_matrix[count] =
+ csc_matrix[count];
+ count = count + 1;
+ }
}
rc = msm_comm_try_set_prop(inst,
HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 5f372c7..920e91a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1026,6 +1026,14 @@
goto stream_start_failed;
}
+ rc = msm_vidc_send_pending_eos_buffers(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed : Send pending EOS buffs for Inst = %pK, %d\n",
+ inst, rc);
+ goto stream_start_failed;
+ }
+
stream_start_failed:
if (rc) {
struct msm_vidc_buffer *temp, *next;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 6e8e1ed..8fd1dd1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2935,6 +2935,8 @@
}
core->state = VIDC_CORE_INIT;
core->smmu_fault_handled = false;
+ core->trigger_ssr = false;
+
core_already_inited:
change_inst_state(inst, MSM_VIDC_CORE_INIT);
mutex_unlock(&core->lock);
@@ -3763,6 +3765,42 @@
return rc;
}
+int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst)
+{
+ struct vidc_frame_data data = {0};
+ struct hfi_device *hdev;
+ struct eos_buf *binfo = NULL, *temp = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst->eosbufs.lock);
+ list_for_each_entry_safe(binfo, temp, &inst->eosbufs.list, list) {
+ data.alloc_len = binfo->smem.size;
+ data.device_addr = binfo->smem.device_addr;
+ data.clnt_data = data.device_addr;
+ data.buffer_type = HAL_BUFFER_INPUT;
+ data.filled_len = 0;
+ data.offset = 0;
+ data.flags = HAL_BUFFERFLAG_EOS;
+ data.timestamp = LLONG_MAX;
+ data.extradata_addr = data.device_addr;
+ data.extradata_size = 0;
+ dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n",
+ (void *)(u64)data.device_addr);
+ hdev = inst->core->device;
+
+ rc = call_hfi_op(hdev, session_etb, inst->session,
+ &data);
+ }
+ mutex_unlock(&inst->eosbufs.lock);
+
+ return rc;
+}
+
int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
{
struct msm_vidc_inst *inst = instance;
@@ -3835,9 +3873,7 @@
}
case V4L2_DEC_CMD_STOP:
{
- struct vidc_frame_data data = {0};
- struct hfi_device *hdev;
- struct eos_buf *binfo;
+ struct eos_buf *binfo = NULL;
u32 smem_flags = 0;
get_inst(inst->core, inst);
@@ -3864,6 +3900,7 @@
if (rc) {
dprintk(VIDC_ERR,
"Failed to allocate output memory\n");
+ rc = -ENOMEM;
goto exit;
}
@@ -3871,22 +3908,14 @@
list_add_tail(&binfo->list, &inst->eosbufs.list);
mutex_unlock(&inst->eosbufs.lock);
- data.alloc_len = binfo->smem.size;
- data.device_addr = binfo->smem.device_addr;
- data.clnt_data = data.device_addr;
- data.buffer_type = HAL_BUFFER_INPUT;
- data.filled_len = 0;
- data.offset = 0;
- data.flags = HAL_BUFFERFLAG_EOS;
- data.timestamp = LLONG_MAX;
- data.extradata_addr = data.device_addr;
- data.extradata_size = 0;
- dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n",
- (void *)(u64)data.device_addr);
- hdev = inst->core->device;
+ if (inst->state != MSM_VIDC_START_DONE) {
+ dprintk(VIDC_DBG,
+ "Inst = %pK is not ready for EOS\n", inst);
+ goto exit;
+ }
- rc = call_hfi_op(hdev, session_etb, inst->session,
- &data);
+ rc = msm_vidc_send_pending_eos_buffers(inst);
+
exit:
put_inst(inst);
break;
@@ -5247,11 +5276,14 @@
* to know if fatal error is due to SSR or not. Handle
* user SSR as non-fatal.
*/
- mutex_lock(&core->lock);
- core->resources.debug_timeout = false;
- mutex_unlock(&core->lock);
+ core->trigger_ssr = true;
rc = call_hfi_op(hdev, core_trigger_ssr,
hdev->hfi_device_data, type);
+ if (rc) {
+ dprintk(VIDC_ERR, "%s: trigger_ssr failed\n",
+ __func__);
+ core->trigger_ssr = false;
+ }
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index a272a10..05e2b91 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -107,6 +107,7 @@
int msm_comm_get_v4l2_profile(int fourcc, int profile);
int msm_comm_get_v4l2_level(int fourcc, int level);
int msm_comm_session_continue(void *instance);
+int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst);
enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
u32 get_frame_size_nv12(int plane, u32 height, u32 width);
u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5be1ee2..98120ac 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -29,7 +29,6 @@
bool msm_vidc_sys_idle_indicator = !true;
bool msm_vidc_thermal_mitigation_disabled = !true;
bool msm_vidc_clock_scaling = true;
-bool msm_vidc_debug_timeout = !true;
bool msm_vidc_syscache_disable = !true;
#define MAX_DBG_BUF_SIZE 4096
@@ -208,8 +207,6 @@
&msm_vidc_thermal_mitigation_disabled) &&
__debugfs_create(bool, "clock_scaling",
&msm_vidc_clock_scaling) &&
- __debugfs_create(bool, "debug_timeout",
- &msm_vidc_debug_timeout) &&
__debugfs_create(bool, "disable_video_syscache",
&msm_vidc_syscache_disable);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 9a798b5..7a73a50 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -61,7 +61,6 @@
extern bool msm_vidc_sys_idle_indicator;
extern bool msm_vidc_thermal_mitigation_disabled;
extern bool msm_vidc_clock_scaling;
-extern bool msm_vidc_debug_timeout;
extern bool msm_vidc_syscache_disable;
#define VIDC_MSG_PRIO2STRING(__level) ({ \
@@ -184,7 +183,18 @@
{
bool enable_fatal;
- enable_fatal = msm_vidc_debug_timeout;
+ enable_fatal = core->resources.debug_timeout;
+
+ /*
+ * In current implementation user-initiated SSR triggers
+ * a fatal error from hardware. However, there is no way
+ * to know if fatal error is due to SSR or not. Handle
+ * user SSR as non-fatal.
+ */
+ if (core->trigger_ssr) {
+ core->trigger_ssr = false;
+ enable_fatal = false;
+ }
/* Video driver can decide FATAL handling of HW errors
* based on multiple factors. This condition check will
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1ad28ba..ba05059 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -169,6 +169,12 @@
enum buffer_owner buffer_ownership;
};
+struct msm_vidc_csc_coeff {
+ u32 *vpe_csc_custom_matrix_coeff;
+ u32 *vpe_csc_custom_bias_coeff;
+ u32 *vpe_csc_custom_limit_coeff;
+};
+
struct msm_vidc_common_data {
char key[128];
int value;
@@ -187,6 +193,7 @@
unsigned int common_data_length;
struct msm_vidc_codec_data *codec_data;
unsigned int codec_data_length;
+ struct msm_vidc_csc_coeff csc_data;
};
struct msm_vidc_format {
@@ -317,6 +324,7 @@
struct msm_vidc_capability *capabilities;
struct delayed_work fw_unload_work;
bool smmu_fault_handled;
+ bool trigger_ssr;
unsigned long min_freq;
unsigned long curr_freq;
struct vidc_bus_vote_data *vote_data;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 7ca6ab0..0fe09e2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -52,6 +52,26 @@
CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200),
};
+/*
+ * Custom conversion coefficients for resolution: 176x144 negative
+ * coeffs are converted to s4.9 format
+ * (e.g. -22 converted to ((1 << 13) - 22)
+ * 3x3 transformation matrix coefficients in s4.9 fixed point format
+ */
+static u32 vpe_csc_custom_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
+ 470, 8170, 8148, 0, 490, 50, 0, 34, 483
+};
+
+/* offset coefficients in s9 fixed point format */
+static u32 vpe_csc_custom_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
+ 34, 0, 4
+};
+
+/* clamping value for Y/U/V([min,max] for Y/U/V) */
+static u32 vpe_csc_custom_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
+ 16, 235, 16, 240, 16, 240
+};
+
static struct msm_vidc_common_data default_common_data[] = {
{
.key = "qcom,never-unload-fw",
@@ -104,6 +124,10 @@
.key = "qcom,hw-resp-timeout",
.value = 250,
},
+ {
+ .key = "qcom,debug-timeout",
+ .value = 0,
+ },
};
@@ -112,6 +136,9 @@
.codec_data_length = ARRAY_SIZE(default_codec_data),
.common_data = default_common_data,
.common_data_length = ARRAY_SIZE(default_common_data),
+ .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+ .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+ .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
};
static struct msm_vidc_platform_data sdm845_data = {
@@ -119,6 +146,9 @@
.codec_data_length = ARRAY_SIZE(sdm845_codec_data),
.common_data = sdm845_common_data,
.common_data_length = ARRAY_SIZE(sdm845_common_data),
+ .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+ .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+ .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
};
static const struct of_device_id msm_vidc_dt_match[] = {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 46fb75f..f343939 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -765,8 +765,6 @@
res->debug_timeout = find_key_value(platform_data,
"qcom,debug-timeout");
- res->debug_timeout |= msm_vidc_debug_timeout;
-
res->pm_qos_latency_us = find_key_value(platform_data,
"qcom,pm-qos-latency-us");
@@ -788,6 +786,8 @@
res->non_fatal_pagefaults = find_key_value(platform_data,
"qcom,domain-attr-non-fatal-faults");
+ res->csc_coeff_data = &platform_data->csc_data;
+
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 31d5a42..8309fce 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -192,6 +192,7 @@
bool non_fatal_pagefaults;
struct msm_vidc_codec_data *codec_data;
int codec_data_count;
+ struct msm_vidc_csc_coeff *csc_coeff_data;
};
static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 82c3ffc..47ff1db 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -4110,7 +4110,9 @@
dprintk(VIDC_PROF, "Resumed from power collapse\n");
exit:
- device->skip_pc_count = 0;
+ /* Don't reset skip_pc_count for SYS_PC_PREP cmd */
+ if (device->last_packet_type != HFI_CMD_SYS_PC_PREP)
+ device->skip_pc_count = 0;
return rc;
err_reset_core:
__tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 8e9e51f..e899af3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -226,8 +226,6 @@
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
#define HFI_PROPERTY_PARAM_VPE_OX_START \
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
-#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION \
- (HFI_PROPERTY_PARAM_VPE_OX_START + 0x001)
#define HFI_PROPERTY_CONFIG_VPE_OX_START \
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a4b7276..13ea3f4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -876,6 +876,8 @@
};
struct hal_vpe_color_space_conversion {
+ u32 input_color_primaries;
+ u32 custom_matrix_enabled;
u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
u32 csc_bias[HAL_MAX_BIAS_COEFFS];
u32 csc_limit[HAL_MAX_LIMIT_COEFFS];
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index fec1517..001ca39 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -355,6 +355,8 @@
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
#define HFI_PROPERTY_PARAM_VPE_ROTATION \
(HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION \
+ (HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x002)
#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
@@ -712,6 +714,8 @@
};
struct hfi_vpe_color_space_conversion {
+ u32 input_color_primaries;
+ u32 custom_matrix_enabled;
u32 csc_matrix[HFI_MAX_MATRIX_COEFFS];
u32 csc_bias[HFI_MAX_BIAS_COEFFS];
u32 csc_limit[HFI_MAX_LIMIT_COEFFS];
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index a12d5ca..176d3dc 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -592,6 +592,7 @@
{
device_init_wakeup(wcd9xxx->dev, false);
wcd9xxx_irq_exit(&wcd9xxx->core_res);
+ mfd_remove_devices(wcd9xxx->dev);
wcd9xxx_bringdown(wcd9xxx->dev);
wcd9xxx_reset_low(wcd9xxx->dev);
wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 092f446..cb98083 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -52,6 +52,8 @@
struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
static unsigned int wcd9xxx_irq_get_upstream_irq(
struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_downstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res);
static void wcd9xxx_irq_put_upstream_irq(
struct wcd9xxx_core_resource *wcd9xxx_res);
static int wcd9xxx_map_irq(
@@ -632,6 +634,7 @@
disable_irq_wake(wcd9xxx_res->irq);
free_irq(wcd9xxx_res->irq, wcd9xxx_res);
wcd9xxx_res->irq = 0;
+ wcd9xxx_irq_put_downstream_irq(wcd9xxx_res);
wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
}
mutex_destroy(&wcd9xxx_res->irq_lock);
@@ -754,6 +757,29 @@
return data->irq;
}
+static void wcd9xxx_irq_put_downstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+ int irq, virq, ret;
+
+ /*
+ * IRQ migration hits error if the chip data and handles
+ * are not made NULL. make associated data and handles
+ * to NULL at irq_exit
+ */
+ for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
+ virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
+ pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+ ret = irq_set_chip_data(virq, NULL);
+ if (ret) {
+ pr_err("%s: Failed to configure irq %d (%d)\n",
+ __func__, irq, ret);
+ return;
+ }
+ irq_set_chip_and_handler(virq, NULL, NULL);
+ }
+}
+
static void wcd9xxx_irq_put_upstream_irq(
struct wcd9xxx_core_resource *wcd9xxx_res)
{
@@ -821,7 +847,6 @@
wmb();
irq_domain_remove(data->domain);
kfree(data);
- domain->host_data = NULL;
return 0;
}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index d092d34..e2e9603 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -122,5 +122,6 @@
support.
source "drivers/net/wireless/cnss_utils/Kconfig"
+source "drivers/net/wireless/cnss_genl/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 005523c..7a75193 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -29,3 +29,4 @@
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
+obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/cnss_genl/Kconfig b/drivers/net/wireless/cnss_genl/Kconfig
new file mode 100644
index 0000000..f1b8a58
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Kconfig
@@ -0,0 +1,7 @@
+config CNSS_GENL
+ tristate "CNSS Generic Netlink Socket Driver"
+ ---help---
+ This module creates generic netlink family "CLD80211". This can be
+ used by cld driver and userspace utilities to communicate over
+ netlink sockets. This module creates different multicast groups to
+ facilitate the same.
diff --git a/drivers/net/wireless/cnss_genl/Makefile b/drivers/net/wireless/cnss_genl/Makefile
new file mode 100644
index 0000000..9431c9e
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CNSS_GENL) := cnss_nl.o
diff --git a/drivers/net/wireless/cnss_genl/cnss_nl.c b/drivers/net/wireless/cnss_genl/cnss_nl.c
new file mode 100644
index 0000000..fafd9ce
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/cnss_nl.c
@@ -0,0 +1,204 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <net/genetlink.h>
+#include <net/cnss_nl.h>
+#include <linux/module.h>
+
+#define CLD80211_GENL_NAME "cld80211"
+
+#define CLD80211_MULTICAST_GROUP_SVC_MSGS "svc_msgs"
+#define CLD80211_MULTICAST_GROUP_HOST_LOGS "host_logs"
+#define CLD80211_MULTICAST_GROUP_FW_LOGS "fw_logs"
+#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS "per_pkt_stats"
+#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS "diag_events"
+#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS "fatal_events"
+#define CLD80211_MULTICAST_GROUP_OEM_MSGS "oem_msgs"
+
+static const struct genl_multicast_group nl_mcgrps[] = {
+ [CLD80211_MCGRP_SVC_MSGS] = { .name =
+ CLD80211_MULTICAST_GROUP_SVC_MSGS},
+ [CLD80211_MCGRP_HOST_LOGS] = { .name =
+ CLD80211_MULTICAST_GROUP_HOST_LOGS},
+ [CLD80211_MCGRP_FW_LOGS] = { .name =
+ CLD80211_MULTICAST_GROUP_FW_LOGS},
+ [CLD80211_MCGRP_PER_PKT_STATS] = { .name =
+ CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
+ [CLD80211_MCGRP_DIAG_EVENTS] = { .name =
+ CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
+ [CLD80211_MCGRP_FATAL_EVENTS] = { .name =
+ CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
+ [CLD80211_MCGRP_OEM_MSGS] = { .name =
+ CLD80211_MULTICAST_GROUP_OEM_MSGS},
+};
+
+struct cld_ops {
+ cld80211_cb cb;
+ void *cb_ctx;
+};
+
+struct cld80211_nl_data {
+ struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
+};
+
+static struct cld80211_nl_data nl_data;
+
+static inline struct cld80211_nl_data *get_local_ctx(void)
+{
+ return &nl_data;
+}
+
+static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
+
+/* policy for the attributes */
+static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = {
+ [CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
+ [CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = CLD80211_MAX_NL_DATA },
+};
+
+static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ u8 cmd_id = ops->cmd;
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
+ return -EOPNOTSUPP;
+ }
+ info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
+ info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
+
+ return 0;
+}
+
+/* The netlink family */
+static struct genl_family cld80211_fam = {
+ .id = GENL_ID_GENERATE,
+ .name = CLD80211_GENL_NAME,
+ .hdrsize = 0, /* no private header */
+ .version = 1, /* no particular meaning now */
+ .maxattr = CLD80211_ATTR_MAX,
+ .netnsok = true,
+ .pre_doit = cld80211_pre_doit,
+ .post_doit = NULL,
+};
+
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
+{
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ pr_debug("CLD80211: Registering command: %d\n", cmd_id);
+ if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+ return -EINVAL;
+ }
+
+ nl->cld_ops[cmd_id - 1].cb = func;
+ nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
+
+ return 0;
+}
+EXPORT_SYMBOL(register_cld_cmd_cb);
+
+int deregister_cld_cmd_cb(u8 cmd_id)
+{
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
+ if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+ return -EINVAL;
+ }
+
+ nl->cld_ops[cmd_id - 1].cb = NULL;
+ nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(deregister_cld_cmd_cb);
+
+struct genl_family *cld80211_get_genl_family(void)
+{
+ return &cld80211_fam;
+}
+EXPORT_SYMBOL(cld80211_get_genl_family);
+
+static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ cld80211_cb cld_cb;
+ void *cld_ctx;
+
+ cld_cb = info->user_ptr[0];
+
+ if (!cld_cb) {
+ pr_err("CLD80211: Not supported\n");
+ return -EOPNOTSUPP;
+ }
+ cld_ctx = info->user_ptr[1];
+
+ if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
+ cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+ nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+ cld_ctx, info->snd_portid);
+ } else {
+ pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __cld80211_init(void)
+{
+ int err, i;
+
+ memset(&nl_ops[0], 0, sizeof(nl_ops));
+
+ pr_info("CLD80211: Initializing\n");
+ for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
+ nl_ops[i].cmd = i + 1;
+ nl_ops[i].doit = cld80211_doit;
+ nl_ops[i].flags = GENL_ADMIN_PERM;
+ nl_ops[i].policy = cld80211_policy;
+ }
+
+ err = genl_register_family_with_ops_groups(&cld80211_fam, nl_ops,
+ nl_mcgrps);
+ if (err) {
+ pr_err("CLD80211: Failed to register cld80211 family: %d\n",
+ err);
+ }
+
+ return err;
+}
+
+static void __cld80211_exit(void)
+{
+ genl_unregister_family(&cld80211_fam);
+}
+
+static int __init cld80211_init(void)
+{
+ return __cld80211_init();
+}
+
+static void __exit cld80211_exit(void)
+{
+ __cld80211_exit();
+}
+
+module_init(cld80211_init);
+module_exit(cld80211_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS generic netlink module");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 4d4e993..d1766dd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -4298,12 +4298,12 @@
ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
}
-static int ipa3_trigger_fw_loading_mdms(void)
+static int ipa3_manual_load_ipa_fws(void)
{
int result;
const struct firmware *fw;
- IPADBG("FW loading process initiated\n");
+ IPADBG("Manual FW loading process initiated\n");
result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
if (result < 0) {
@@ -4319,7 +4319,7 @@
result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
if (result) {
- IPAERR("IPA FWs loading has failed\n");
+ IPAERR("Manual IPA FWs loading has failed\n");
release_firmware(fw);
return result;
}
@@ -4335,15 +4335,15 @@
release_firmware(fw);
- IPADBG("FW loading process is complete\n");
+ IPADBG("Manual FW loading process is complete\n");
return 0;
}
-static int ipa3_trigger_fw_loading_msms(void)
+static int ipa3_pil_load_ipa_fws(void)
{
void *subsystem_get_retval = NULL;
- IPADBG("FW loading process initiated\n");
+ IPADBG("PIL FW loading process initiated\n");
subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
if (IS_ERR_OR_NULL(subsystem_get_retval)) {
@@ -4351,7 +4351,7 @@
return -EINVAL;
}
- IPADBG("FW loading process is complete\n");
+ IPADBG("PIL FW loading process is complete\n");
return 0;
}
@@ -4377,11 +4377,8 @@
if (ipa3_is_ready())
return count;
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
- if (ipa3_is_msm_device()) {
- result = ipa3_trigger_fw_loading_msms();
- } else {
+ /* Check MHI configuration on MDM devices */
+ if (!ipa3_is_msm_device()) {
if (!strcasecmp(dbg_buff, "MHI")) {
ipa3_ctx->ipa_config_is_mhi = true;
pr_info(
@@ -4390,19 +4387,26 @@
pr_info(
"IPA is loading with non MHI configuration\n");
}
- result = ipa3_trigger_fw_loading_mdms();
}
- /* No IPAv3.x chipsets that don't support FW loading */
+
+ IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+ if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
+ result = ipa3_pil_load_ipa_fws();
+ else
+ result = ipa3_manual_load_ipa_fws();
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
if (result) {
- IPAERR("FW loading process has failed\n");
- return result;
- } else {
- queue_work(ipa3_ctx->transport_power_mgmt_wq,
- &ipa3_post_init_work);
+ IPAERR("IPA FW loading process has failed\n");
+ return result;
}
+
+ queue_work(ipa3_ctx->transport_power_mgmt_wq,
+ &ipa3_post_init_work);
+ pr_info("IPA FW loaded successfully\n");
+
return count;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 9486b0a..153548b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -540,6 +540,12 @@
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE)
pr_err("ether_type:%x ", attrib->ether_type);
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
+ pr_err("tcp syn ");
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP)
+ pr_err("tcp syn l2tp ");
+
pr_err("\n");
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
index b6427d0..f821dd2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
@@ -204,6 +204,7 @@
struct ipa_mem_buffer cmd;
struct Ipa3HwNtnSetUpCmdData_t *Ntn_params;
struct IpaHwOffloadSetUpCmdData_t *cmd_data;
+ struct IpaHwOffloadSetUpCmdData_t_v4_0 *cmd_data_v4_0;
if (ntn_info == NULL) {
IPAERR("invalid input\n");
@@ -225,8 +226,10 @@
IPADBG("num_buffers = %d\n", ntn_info->num_buffers);
IPADBG("data_buff_size = %d\n", ntn_info->data_buff_size);
IPADBG("tail_ptr_base_pa = 0x%pa\n", &ntn_info->ntn_reg_base_ptr_pa);
-
- cmd.size = sizeof(*cmd_data);
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ cmd.size = sizeof(*cmd_data_v4_0);
+ else
+ cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
if (cmd.base == NULL) {
@@ -234,10 +237,17 @@
return -ENOMEM;
}
- cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
- cmd_data->protocol = IPA_HW_FEATURE_NTN;
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ cmd_data_v4_0 = (struct IpaHwOffloadSetUpCmdData_t_v4_0 *)
+ cmd.base;
+ cmd_data_v4_0->protocol = IPA_HW_FEATURE_NTN;
+ Ntn_params = &cmd_data_v4_0->SetupCh_params.NtnSetupCh_params;
+ } else {
+ cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
+ cmd_data->protocol = IPA_HW_FEATURE_NTN;
+ Ntn_params = &cmd_data->SetupCh_params.NtnSetupCh_params;
+ }
- Ntn_params = &cmd_data->SetupCh_params.NtnSetupCh_params;
Ntn_params->ring_base_pa = ntn_info->ring_base_pa;
Ntn_params->buff_pool_base_pa = ntn_info->buff_pool_base_pa;
Ntn_params->ntn_ring_size = ntn_info->ntn_ring_size;
@@ -372,6 +382,7 @@
struct ipa_mem_buffer cmd;
struct ipa3_ep_context *ep_ul, *ep_dl;
struct IpaHwOffloadCommonChCmdData_t *cmd_data;
+ struct IpaHwOffloadCommonChCmdData_t_v4_0 *cmd_data_v4_0;
union Ipa3HwNtnCommonChCmdData_t *tear;
int result = 0;
@@ -388,7 +399,10 @@
return -EFAULT;
}
- cmd.size = sizeof(*cmd_data);
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+ cmd.size = sizeof(*cmd_data_v4_0);
+ else
+ cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
if (cmd.base == NULL) {
@@ -397,9 +411,16 @@
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
- cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
- cmd_data->protocol = IPA_HW_FEATURE_NTN;
- tear = &cmd_data->CommonCh_params.NtnCommonCh_params;
+ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+ cmd_data_v4_0 = (struct IpaHwOffloadCommonChCmdData_t_v4_0 *)
+ cmd.base;
+ cmd_data_v4_0->protocol = IPA_HW_FEATURE_NTN;
+ tear = &cmd_data_v4_0->CommonCh_params.NtnCommonCh_params;
+ } else {
+ cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
+ cmd_data->protocol = IPA_HW_FEATURE_NTN;
+ tear = &cmd_data->CommonCh_params.NtnCommonCh_params;
+ }
/* teardown the DL pipe */
ipa3_disable_data_path(ipa_ep_idx_dl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
index 2e5a832..44afb28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
@@ -536,6 +536,16 @@
} __packed;
/**
+ * struct IpaHwOffloadSetUpCmdData_t_v4_0 -
+ *
+ *
+ */
+struct IpaHwOffloadSetUpCmdData_t_v4_0 {
+ u32 protocol;
+ union IpaHwSetUpCmd SetupCh_params;
+} __packed;
+
+/**
* struct IpaHwCommonChCmd - Structure holding the parameters
* for IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN
*
@@ -550,4 +560,10 @@
union IpaHwCommonChCmd CommonCh_params;
} __packed;
+struct IpaHwOffloadCommonChCmdData_t_v4_0 {
+ u32 protocol;
+ union IpaHwCommonChCmd CommonCh_params;
+} __packed;
+
+
#endif /* _IPA_UC_OFFLOAD_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 8fe15bc..8c55a01 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -408,7 +408,7 @@
enum ipa_ees {
IPA_EE_AP = 0,
IPA_EE_Q6 = 1,
- IPA_EE_UC = 3,
+ IPA_EE_UC = 2,
};
struct ipa_ep_configuration {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 2253b4b..acc72f0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -829,6 +829,21 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ extra = ipa_write_8(12, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ ihl_ofst_meq32++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1167,6 +1182,57 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ extra = ipa_write_8(12, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ ihl_ofst_meq32++;
+ }
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+ ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+ /* populate TCP protocol eq */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(30, extra);
+ rest = ipa_write_32(0xFF0000, rest);
+ rest = ipa_write_32(0x60000, rest);
+ } else {
+ extra = ipa_write_8(26, extra);
+ rest = ipa_write_32(0xFF00, rest);
+ rest = ipa_write_32(0x600, rest);
+ }
+
+ /* populate TCP SYN eq */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(54, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ } else {
+ extra = ipa_write_8(74, extra);
+ rest = ipa_write_32(0x20000, rest);
+ rest = ipa_write_32(0x20000, rest);
+ }
+ ihl_ofst_meq32 += 2;
+ }
+
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1241,6 +1307,27 @@
ihl_ofst_rng16++;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+ ihl_ofst_rng16)) {
+ IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+ goto err;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+ /* 20 => offset of Ethertype after v4 header */
+ if (attrib->ether_type == 0x0800) {
+ extra = ipa_write_8(21, extra);
+ rest = ipa_write_16(0x0045, rest);
+ rest = ipa_write_16(0x0045, rest);
+ } else {
+ extra = ipa_write_8(20, extra);
+ rest = ipa_write_16(attrib->ether_type, rest);
+ rest = ipa_write_16(attrib->ether_type, rest);
+ }
+ ihl_ofst_rng16++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
rest = ipa_write_32(attrib->u.v6.flow_label & 0xFFFFF,
@@ -1711,6 +1798,21 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+ ihl_ofst_meq32++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2108,6 +2210,65 @@
ihl_ofst_meq32 += 2;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ /* 12 => offset of SYN after v4 header */
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+ ihl_ofst_meq32++;
+ }
+
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+ ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+ ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+ IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+ /* populate TCP protocol eq */
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 30;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0xFF0000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x60000;
+ } else {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 26;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0xFF00;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x600;
+ }
+
+ /* populate TCP SYN eq */
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 54;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x20000;
+ } else {
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 74;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+ 0x20000;
+ eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+ 0x20000;
+ }
+ ihl_ofst_meq32 += 2;
+ }
+
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2250,6 +2411,32 @@
ihl_ofst_rng16++;
}
+ if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+ if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+ ihl_ofst_rng16)) {
+ IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+ return -EPERM;
+ }
+ *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+ ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+ if (attrib->ether_type == 0x0800) {
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset
+ = 21;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+ = 0x0045;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+ = 0x0045;
+ } else {
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset =
+ 20;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+ = attrib->ether_type;
+ eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+ = attrib->ether_type;
+ }
+ ihl_ofst_rng16++;
+ }
+
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
eq_atrb->fl_eq_present = 1;
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index 3be414b..d5fc867 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -218,6 +218,12 @@
goto end;
}
+ if (!ext_disp->ops) {
+ pr_err("codec ops not registered\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
if (state == EXT_DISPLAY_CABLE_CONNECT) {
/* connect codec with interface */
*ext_disp->ops = data->codec_ops;
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 2818d56..aafb8fc 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -66,7 +66,7 @@
struct msm_bus_client_handle *bus_bw;
u32 bus_mas_id;
u32 bus_slv_id;
- spinlock_t ab_ib_lock;
+ struct mutex ab_ib_lock;
struct list_head ab_list_head;
struct list_head ib_list_head;
unsigned long cur_ab;
@@ -608,7 +608,6 @@
static int geni_se_rmv_ab_ib(struct geni_se_device *geni_se_dev,
struct se_geni_rsc *rsc)
{
- unsigned long flags;
struct se_geni_rsc *tmp;
bool bus_bw_update = false;
int ret = 0;
@@ -616,7 +615,7 @@
if (unlikely(list_empty(&rsc->ab_list) || list_empty(&rsc->ib_list)))
return -EINVAL;
- spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+ mutex_lock(&geni_se_dev->ab_ib_lock);
list_del_init(&rsc->ab_list);
geni_se_dev->cur_ab -= rsc->ab;
@@ -629,8 +628,6 @@
geni_se_dev->cur_ib = 0;
bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
- spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
if (bus_bw_update)
ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
geni_se_dev->cur_ab,
@@ -639,6 +636,7 @@
"%s: %lu:%lu (%lu:%lu) %d\n", __func__,
geni_se_dev->cur_ab, geni_se_dev->cur_ib,
rsc->ab, rsc->ib, bus_bw_update);
+ mutex_unlock(&geni_se_dev->ab_ib_lock);
return ret;
}
@@ -701,13 +699,12 @@
static int geni_se_add_ab_ib(struct geni_se_device *geni_se_dev,
struct se_geni_rsc *rsc)
{
- unsigned long flags;
struct se_geni_rsc *tmp = NULL;
struct list_head *ins_list_head;
bool bus_bw_update = false;
int ret = 0;
- spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+ mutex_lock(&geni_se_dev->ab_ib_lock);
list_add(&rsc->ab_list, &geni_se_dev->ab_list_head);
geni_se_dev->cur_ab += rsc->ab;
@@ -723,8 +720,6 @@
geni_se_dev->cur_ib = rsc->ib;
bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
- spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
if (bus_bw_update)
ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
geni_se_dev->cur_ab,
@@ -733,6 +728,7 @@
"%s: %lu:%lu (%lu:%lu) %d\n", __func__,
geni_se_dev->cur_ab, geni_se_dev->cur_ib,
rsc->ab, rsc->ib, bus_bw_update);
+ mutex_unlock(&geni_se_dev->ab_ib_lock);
return ret;
}
@@ -1330,7 +1326,7 @@
mutex_init(&geni_se_dev->iommu_lock);
INIT_LIST_HEAD(&geni_se_dev->ab_list_head);
INIT_LIST_HEAD(&geni_se_dev->ib_list_head);
- spin_lock_init(&geni_se_dev->ab_ib_lock);
+ mutex_init(&geni_se_dev->ab_ib_lock);
geni_se_dev->log_ctx = ipc_log_context_create(NUM_LOG_PAGES,
dev_name(geni_se_dev->dev), 0);
if (!geni_se_dev->log_ctx)
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index a23f069..47208f7 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -31,6 +31,7 @@
#define EL2_SCM_ID 0x02001902
#define KP_EL2_REPORT_REVISION 0x01000101
+#define INVALID_PID -1
static struct seemp_logk_dev *slogk_dev;
@@ -65,6 +66,7 @@
static long seemp_logk_set_mask(unsigned long arg);
static long seemp_logk_set_mapping(unsigned long arg);
static long seemp_logk_check_filter(unsigned long arg);
+static pid_t seemp_logk_get_pid(struct task_struct *t);
static int seemp_logk_rtic_thread(void *data);
void* (*seemp_logk_kernel_begin)(char **buf);
@@ -601,6 +603,26 @@
.mmap = seemp_logk_mmap,
};
+static pid_t seemp_logk_get_pid(struct task_struct *t)
+{
+ struct task_struct *task;
+ pid_t pid;
+
+ if (t == NULL)
+ return INVALID_PID;
+
+ rcu_read_lock();
+ for_each_process(task) {
+ if (task == t) {
+ pid = task->pid;
+ rcu_read_unlock();
+ return pid;
+ }
+ }
+ rcu_read_unlock();
+ return INVALID_PID;
+}
+
static int seemp_logk_rtic_thread(void *data)
{
struct el2_report_header_t *header;
@@ -632,8 +654,9 @@
|| report->sequence_number >
last_sequence_number)) {
seemp_logk_rtic(report->report_type,
- ((struct task_struct *) report->actor)
- ->pid,
+ seemp_logk_get_pid(
+ (struct task_struct *)
+ report->actor),
/* leave this empty until
* asset id is provided
*/
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 08e1505..431cd24 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -311,6 +311,9 @@
POWER_SUPPLY_ATTR(hw_current_max),
POWER_SUPPLY_ATTR(real_type),
POWER_SUPPLY_ATTR(pr_swap),
+ POWER_SUPPLY_ATTR(cc_step),
+ POWER_SUPPLY_ATTR(cc_step_sel),
+ POWER_SUPPLY_ATTR(sw_jeita_enabled),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index dd5f78f..c793ee5 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -49,7 +49,7 @@
#define SRAM_READ "fg_sram_read"
#define SRAM_WRITE "fg_sram_write"
#define PROFILE_LOAD "fg_profile_load"
-#define DELTA_SOC "fg_delta_soc"
+#define TTF_PRIMING "fg_ttf_priming"
/* Delta BSOC irq votable reasons */
#define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq"
@@ -82,6 +82,8 @@
#define BATT_THERM_NUM_COEFFS 3
+#define MAX_CC_STEPS 20
+
/* Debug flag definitions */
enum fg_debug_flag {
FG_IRQ = BIT(0), /* Show interrupts */
@@ -241,6 +243,11 @@
NUM_ESR_TIMERS,
};
+enum ttf_mode {
+ TTF_MODE_NORMAL = 0,
+ TTF_MODE_QNOVO,
+};
+
/* DT parameters for FG device */
struct fg_dt_props {
bool force_load_profile;
@@ -323,16 +330,31 @@
};
struct fg_circ_buf {
- int arr[20];
+ int arr[10];
int size;
int head;
};
+struct fg_cc_step_data {
+ int arr[MAX_CC_STEPS];
+ int sel;
+};
+
struct fg_pt {
s32 x;
s32 y;
};
+struct ttf {
+ struct fg_circ_buf ibatt;
+ struct fg_circ_buf vbatt;
+ struct fg_cc_step_data cc_step;
+ struct mutex lock;
+ int mode;
+ int last_ttf;
+ s64 last_ms;
+};
+
static const struct fg_pt fg_ln_table[] = {
{ 1000, 0 },
{ 2000, 693 },
@@ -372,6 +394,7 @@
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct power_supply *parallel_psy;
+ struct power_supply *pc_port_psy;
struct iio_channel *batt_id_chan;
struct iio_channel *die_temp_chan;
struct fg_irq_info *irqs;
@@ -388,9 +411,9 @@
struct fg_cyc_ctr_data cyc_ctr;
struct notifier_block nb;
struct fg_cap_learning cl;
+ struct ttf ttf;
struct mutex bus_lock;
struct mutex sram_rw_lock;
- struct mutex batt_avg_lock;
struct mutex charge_full_lock;
u32 batt_soc_base;
u32 batt_info_base;
@@ -403,12 +426,14 @@
int prev_charge_status;
int charge_done;
int charge_type;
+ int online_status;
int last_soc;
int last_batt_temp;
int health;
int maint_soc;
int delta_soc;
int last_msoc;
+ int last_recharge_volt_mv;
int esr_timer_charging_default[NUM_ESR_TIMERS];
enum slope_limit_status slope_limit_sts;
bool profile_available;
@@ -429,11 +454,8 @@
struct completion mem_grant;
struct delayed_work profile_load_work;
struct work_struct status_change_work;
- struct work_struct cycle_count_work;
- struct delayed_work batt_avg_work;
+ struct delayed_work ttf_work;
struct delayed_work sram_dump_work;
- struct fg_circ_buf ibatt_circ_buf;
- struct fg_circ_buf vbatt_circ_buf;
};
/* Debugfs data structures are below */
@@ -496,6 +518,7 @@
extern void fg_circ_buf_add(struct fg_circ_buf *buf, int val);
extern void fg_circ_buf_clr(struct fg_circ_buf *buf);
extern int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg);
+extern int fg_circ_buf_median(struct fg_circ_buf *buf, int *median);
extern int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input,
s32 *output);
#endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index d9ca47c..aed2062 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/sort.h>
#include "fg-core.h"
void fg_circ_buf_add(struct fg_circ_buf *buf, int val)
@@ -21,7 +22,9 @@
void fg_circ_buf_clr(struct fg_circ_buf *buf)
{
- memset(buf, 0, sizeof(*buf));
+ buf->size = 0;
+ buf->head = 0;
+ memset(buf->arr, 0, sizeof(buf->arr));
}
int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg)
@@ -39,6 +42,39 @@
return 0;
}
+static int cmp_int(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+int fg_circ_buf_median(struct fg_circ_buf *buf, int *median)
+{
+ int *temp;
+
+ if (buf->size == 0)
+ return -ENODATA;
+
+ if (buf->size == 1) {
+ *median = buf->arr[0];
+ return 0;
+ }
+
+ temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ memcpy(temp, buf->arr, buf->size * sizeof(*temp));
+ sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
+
+ if (buf->size % 2)
+ *median = temp[buf->size / 2];
+ else
+ *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
+
+ kfree(temp);
+ return 0;
+}
+
int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output)
{
int i;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 7c94744..6f615e4 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -1173,6 +1173,42 @@
return true;
}
+static bool usb_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->usb_psy)
+ return true;
+
+ chip->usb_psy = power_supply_get_by_name("usb");
+ if (!chip->usb_psy)
+ return false;
+
+ return true;
+}
+
+static bool pc_port_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->pc_port_psy)
+ return true;
+
+ chip->pc_port_psy = power_supply_get_by_name("pc_port");
+ if (!chip->pc_port_psy)
+ return false;
+
+ return true;
+}
+
+static bool dc_psy_initialized(struct fg_chip *chip)
+{
+ if (chip->dc_psy)
+ return true;
+
+ chip->dc_psy = power_supply_get_by_name("dc");
+ if (!chip->dc_psy)
+ return false;
+
+ return true;
+}
+
static bool is_parallel_charger_available(struct fg_chip *chip)
{
if (!chip->parallel_psy)
@@ -1279,11 +1315,20 @@
return true;
}
+#define QNOVO_CL_SKEW_DECIPCT -30
static void fg_cap_learning_post_process(struct fg_chip *chip)
{
int64_t max_inc_val, min_dec_val, old_cap;
int rc;
+ if (is_qnovo_en(chip)) {
+ fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n",
+ QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
+ chip->cl.final_cc_uah = chip->cl.final_cc_uah *
+ (1000 + QNOVO_CL_SKEW_DECIPCT);
+ do_div(chip->cl.final_cc_uah, 1000);
+ }
+
max_inc_val = chip->cl.learned_cc_uah
* (1000 + chip->dt.cl_max_cap_inc);
do_div(max_inc_val, 1000);
@@ -1592,6 +1637,9 @@
if (chip->wa_flags & PMI8998_V1_REV_WA)
return 0;
+ if (voltage_mv == chip->last_recharge_volt_mv)
+ return 0;
+
fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
voltage_mv);
fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
@@ -1606,6 +1654,7 @@
return rc;
}
+ chip->last_recharge_volt_mv = voltage_mv;
return 0;
}
@@ -1916,6 +1965,33 @@
return 0;
}
+static int fg_adjust_recharge_voltage(struct fg_chip *chip)
+{
+ int rc, recharge_volt_mv;
+
+ if (chip->dt.auto_recharge_soc)
+ return 0;
+
+ fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n",
+ chip->health, chip->charge_status, chip->charge_done);
+
+ recharge_volt_mv = chip->dt.recharge_volt_thr_mv;
+
+ /* Lower the recharge voltage in soft JEITA */
+ if (chip->health == POWER_SUPPLY_HEALTH_WARM ||
+ chip->health == POWER_SUPPLY_HEALTH_COOL)
+ recharge_volt_mv -= 200;
+
+ rc = fg_set_recharge_voltage(chip, recharge_volt_mv);
+ if (rc < 0) {
+ pr_err("Error in setting recharge_voltage, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
{
enum slope_limit_status status;
@@ -2133,102 +2209,67 @@
return 0;
}
-static void fg_batt_avg_update(struct fg_chip *chip)
+static void fg_ttf_update(struct fg_chip *chip)
{
- if (chip->charge_status == chip->prev_charge_status)
+ int rc;
+ int delay_ms;
+ union power_supply_propval prop = {0, };
+ int online = 0;
+
+ if (usb_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+ if (pc_port_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->pc_port_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+ if (dc_psy_initialized(chip)) {
+ rc = power_supply_get_property(chip->dc_psy,
+ POWER_SUPPLY_PROP_ONLINE, &prop);
+ if (rc < 0) {
+ pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
+ return;
+ }
+
+ online = online || prop.intval;
+ }
+
+
+ if (chip->online_status == online)
return;
- cancel_delayed_work_sync(&chip->batt_avg_work);
- fg_circ_buf_clr(&chip->ibatt_circ_buf);
- fg_circ_buf_clr(&chip->vbatt_circ_buf);
+ chip->online_status = online;
+ if (online)
+ /* wait 35 seconds for the input to settle */
+ delay_ms = 35000;
+ else
+ /* wait 5 seconds for current to settle during discharge */
+ delay_ms = 5000;
- if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
- chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
- schedule_delayed_work(&chip->batt_avg_work,
- msecs_to_jiffies(2000));
-}
-
-static void status_change_work(struct work_struct *work)
-{
- struct fg_chip *chip = container_of(work,
- struct fg_chip, status_change_work);
- union power_supply_propval prop = {0, };
- int rc, batt_temp;
-
- if (!batt_psy_initialized(chip)) {
- fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
- goto out;
- }
-
- rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
- &prop);
- if (rc < 0) {
- pr_err("Error in getting charging status, rc=%d\n", rc);
- goto out;
- }
-
- chip->prev_charge_status = chip->charge_status;
- chip->charge_status = prop.intval;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
- if (rc < 0) {
- pr_err("Error in getting charge type, rc=%d\n", rc);
- goto out;
- }
-
- chip->charge_type = prop.intval;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
- if (rc < 0) {
- pr_err("Error in getting charge_done, rc=%d\n", rc);
- goto out;
- }
-
- chip->charge_done = prop.intval;
- if (chip->cyc_ctr.en)
- schedule_work(&chip->cycle_count_work);
-
- fg_cap_learning_update(chip);
-
- rc = fg_charge_full_update(chip);
- if (rc < 0)
- pr_err("Error in charge_full_update, rc=%d\n", rc);
-
- rc = fg_adjust_recharge_soc(chip);
- if (rc < 0)
- pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
-
- rc = fg_adjust_ki_coeff_dischg(chip);
- if (rc < 0)
- pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
-
- rc = fg_esr_fcc_config(chip);
- if (rc < 0)
- pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
-
- rc = fg_esr_timer_config(chip, false);
- if (rc < 0)
- pr_err("Error in configuring ESR timer, rc=%d\n", rc);
-
- rc = fg_get_battery_temp(chip, &batt_temp);
- if (!rc) {
- rc = fg_slope_limit_config(chip, batt_temp);
- if (rc < 0)
- pr_err("Error in configuring slope limiter rc:%d\n",
- rc);
-
- rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
- if (rc < 0)
- pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
- rc);
- }
-
- fg_batt_avg_update(chip);
-
-out:
- fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
- chip->charge_status, chip->charge_type, chip->charge_done);
- pm_relax(chip->dev);
+ vote(chip->awake_votable, TTF_PRIMING, true, 0);
+ cancel_delayed_work_sync(&chip->ttf_work);
+ mutex_lock(&chip->ttf.lock);
+ fg_circ_buf_clr(&chip->ttf.ibatt);
+ fg_circ_buf_clr(&chip->ttf.vbatt);
+ chip->ttf.last_ttf = 0;
+ chip->ttf.last_ms = 0;
+ mutex_unlock(&chip->ttf.lock);
+ schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
}
static void restore_cycle_counter(struct fg_chip *chip)
@@ -2236,6 +2277,9 @@
int rc = 0, i;
u8 data[2];
+ if (!chip->cyc_ctr.en)
+ return;
+
mutex_lock(&chip->cyc_ctr.lock);
for (i = 0; i < BUCKET_COUNT; i++) {
rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
@@ -2289,20 +2333,25 @@
rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
FG_IMA_DEFAULT);
- if (rc < 0)
+ if (rc < 0) {
pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
bucket, rc);
- else
- chip->cyc_ctr.count[bucket] = cyc_count;
+ return rc;
+ }
+
+ chip->cyc_ctr.count[bucket] = cyc_count;
+ fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
+ bucket);
+
return rc;
}
-static void cycle_count_work(struct work_struct *work)
+static void fg_cycle_counter_update(struct fg_chip *chip)
{
int rc = 0, bucket, i, batt_soc;
- struct fg_chip *chip = container_of(work,
- struct fg_chip,
- cycle_count_work);
+
+ if (!chip->cyc_ctr.en)
+ return;
mutex_lock(&chip->cyc_ctr.lock);
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
@@ -2314,45 +2363,30 @@
/* We need only the most significant byte here */
batt_soc = (u32)batt_soc >> 24;
- if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
- /* Find out which bucket the SOC falls in */
- bucket = batt_soc / BUCKET_SOC_PCT;
- pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
+ /* Find out which bucket the SOC falls in */
+ bucket = batt_soc / BUCKET_SOC_PCT;
- /*
- * If we've started counting for the previous bucket,
- * then store the counter for that bucket if the
- * counter for current bucket is getting started.
- */
- if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
- !chip->cyc_ctr.started[bucket]) {
- rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
- if (rc < 0) {
- pr_err("Error in storing cycle_ctr rc: %d\n",
- rc);
- goto out;
- } else {
- chip->cyc_ctr.started[bucket - 1] = false;
- chip->cyc_ctr.last_soc[bucket - 1] = 0;
- }
- }
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
if (!chip->cyc_ctr.started[bucket]) {
chip->cyc_ctr.started[bucket] = true;
chip->cyc_ctr.last_soc[bucket] = batt_soc;
}
- } else {
+ } else if (chip->charge_done || !is_input_present(chip)) {
for (i = 0; i < BUCKET_COUNT; i++) {
if (chip->cyc_ctr.started[i] &&
- batt_soc > chip->cyc_ctr.last_soc[i]) {
+ batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
rc = fg_inc_store_cycle_ctr(chip, i);
if (rc < 0)
pr_err("Error in storing cycle_ctr rc: %d\n",
rc);
chip->cyc_ctr.last_soc[i] = 0;
+ chip->cyc_ctr.started[i] = false;
}
- chip->cyc_ctr.started[i] = false;
}
}
+
+ fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
+ batt_soc, bucket, chip->charge_status);
out:
mutex_unlock(&chip->cyc_ctr.lock);
}
@@ -2373,6 +2407,87 @@
return count;
}
+static void status_change_work(struct work_struct *work)
+{
+ struct fg_chip *chip = container_of(work,
+ struct fg_chip, status_change_work);
+ union power_supply_propval prop = {0, };
+ int rc, batt_temp;
+
+ if (!batt_psy_initialized(chip)) {
+ fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
+ goto out;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
+ &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charging status, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->prev_charge_status = chip->charge_status;
+ chip->charge_status = prop.intval;
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charge type, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->charge_type = prop.intval;
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
+ if (rc < 0) {
+ pr_err("Error in getting charge_done, rc=%d\n", rc);
+ goto out;
+ }
+
+ chip->charge_done = prop.intval;
+ fg_cycle_counter_update(chip);
+ fg_cap_learning_update(chip);
+
+ rc = fg_charge_full_update(chip);
+ if (rc < 0)
+ pr_err("Error in charge_full_update, rc=%d\n", rc);
+
+ rc = fg_adjust_recharge_soc(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
+
+ rc = fg_adjust_recharge_voltage(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc);
+
+ rc = fg_adjust_ki_coeff_dischg(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
+
+ rc = fg_esr_fcc_config(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
+
+ rc = fg_get_battery_temp(chip, &batt_temp);
+ if (!rc) {
+ rc = fg_slope_limit_config(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring slope limiter rc:%d\n",
+ rc);
+
+ rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
+ rc);
+ }
+
+ fg_ttf_update(chip);
+
+out:
+ fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
+ chip->charge_status, chip->charge_type, chip->charge_done);
+ pm_relax(chip->dev);
+}
+
static int fg_bp_params_config(struct fg_chip *chip)
{
int rc = 0;
@@ -2733,45 +2848,19 @@
module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
-#define BATT_AVG_POLL_PERIOD_MS 10000
-static void batt_avg_work(struct work_struct *work)
-{
- struct fg_chip *chip = container_of(work, struct fg_chip,
- batt_avg_work.work);
- int rc, ibatt_now, vbatt_now;
-
- mutex_lock(&chip->batt_avg_lock);
- rc = fg_get_battery_current(chip, &ibatt_now);
- if (rc < 0) {
- pr_err("failed to get battery current, rc=%d\n", rc);
- goto reschedule;
- }
-
- rc = fg_get_battery_voltage(chip, &vbatt_now);
- if (rc < 0) {
- pr_err("failed to get battery voltage, rc=%d\n", rc);
- goto reschedule;
- }
-
- fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
- fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
-
-reschedule:
- mutex_unlock(&chip->batt_avg_lock);
- schedule_delayed_work(&chip->batt_avg_work,
- msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
-}
-
#define HOURS_TO_SECONDS 3600
#define OCV_SLOPE_UV 10869
#define MILLI_UNIT 1000
#define MICRO_UNIT 1000000
-static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+#define NANO_UNIT 1000000000
+static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
{
- int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
- act_cap_uah;
- s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
- s64 t_predicted_cc = 0, t_predicted_cv = 0;
+ int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
+ i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
+ i, soc_per_step, msoc_this_step, msoc_next_step,
+ ibatt_this_step, t_predicted_this_step, ttf_slope,
+ t_predicted_cv, t_predicted = 0;
+ s64 delta_ms;
if (chip->bp.float_volt_uv <= 0) {
pr_err("battery profile is not loaded\n");
@@ -2790,48 +2879,53 @@
}
fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
+ /* the battery is considered full if the SOC is 100% */
if (msoc >= 100) {
*val = 0;
return 0;
}
- mutex_lock(&chip->batt_avg_lock);
- rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
- if (rc < 0) {
- /* try to get instantaneous current */
- rc = fg_get_battery_current(chip, &ibatt_avg);
- if (rc < 0) {
- mutex_unlock(&chip->batt_avg_lock);
- pr_err("failed to get battery current, rc=%d\n", rc);
- return rc;
- }
+ if (is_qnovo_en(chip))
+ ttf_mode = TTF_MODE_QNOVO;
+ else
+ ttf_mode = TTF_MODE_NORMAL;
+
+ /* when switching TTF algorithms the TTF needs to be reset */
+ if (chip->ttf.mode != ttf_mode) {
+ fg_circ_buf_clr(&chip->ttf.ibatt);
+ fg_circ_buf_clr(&chip->ttf.vbatt);
+ chip->ttf.last_ttf = 0;
+ chip->ttf.last_ms = 0;
+ chip->ttf.mode = ttf_mode;
}
- rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
- if (rc < 0) {
- /* try to get instantaneous voltage */
- rc = fg_get_battery_voltage(chip, &vbatt_avg);
- if (rc < 0) {
- mutex_unlock(&chip->batt_avg_lock);
- pr_err("failed to get battery voltage, rc=%d\n", rc);
- return rc;
- }
+ /* at least 10 samples are required to produce a stable IBATT */
+ if (chip->ttf.ibatt.size < 10) {
+ *val = -1;
+ return 0;
}
- mutex_unlock(&chip->batt_avg_lock);
- fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
+ rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
+ if (rc < 0) {
+ pr_err("failed to get IBATT AVG rc=%d\n", rc);
+ return rc;
+ }
- /* clamp ibatt_avg to -150mA */
- if (ibatt_avg > -150000)
- ibatt_avg = -150000;
+ rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
+ if (rc < 0) {
+ pr_err("failed to get VBATT AVG rc=%d\n", rc);
+ return rc;
+ }
+
+ ibatt_avg = -ibatt_avg / MILLI_UNIT;
+ vbatt_avg /= MILLI_UNIT;
+
+ /* clamp ibatt_avg to iterm */
+ if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
+ ibatt_avg = abs(chip->dt.sys_term_curr_ma);
+
fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
-
- /* reverse polarity to be consistent with unsigned current settings */
- ibatt_avg = abs(ibatt_avg);
-
- /* estimated battery current at the CC to CV transition */
- i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
- fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
+ fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
rc = fg_get_battery_resistance(chip, &rbatt);
if (rc < 0) {
@@ -2839,19 +2933,14 @@
return rc;
}
- /* clamp rbatt to 50mOhms */
- if (rbatt < 50000)
- rbatt = 50000;
-
+ rbatt /= MILLI_UNIT;
fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
- rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
+ rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
if (rc < 0) {
pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
return rc;
}
- act_cap_uah *= MILLI_UNIT;
- fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
if (rc < 0) {
@@ -2860,69 +2949,148 @@
}
full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
FULL_SOC_RAW);
- fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
+ act_cap_mah = full_soc * act_cap_mah / 100;
+ fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
+
+ /* estimated battery current at the CC to CV transition */
+ switch (chip->ttf.mode) {
+ case TTF_MODE_NORMAL:
+ i_cc2cv = ibatt_avg * vbatt_avg /
+ max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
+ break;
+ case TTF_MODE_QNOVO:
+ i_cc2cv = min(
+ chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
+ ibatt_avg * vbatt_avg /
+ max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
+ break;
+ default:
+ pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+ break;
+ }
+ fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
/* if we are already in CV state then we can skip estimating CC */
if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
- goto skip_cc_estimate;
+ goto cv_estimate;
- /* if the charger is current limited then use power approximation */
- if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
- ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
- else
- ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
- ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
- fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
-
- soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
/* estimated SOC at the CC to CV transition */
+ soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
soc_cc2cv = 100 - soc_cc2cv;
fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
- /* the esimated SOC may be lower than the current SOC */
- if (soc_cc2cv - msoc <= 0)
- goto skip_cc_estimate;
+ switch (chip->ttf.mode) {
+ case TTF_MODE_NORMAL:
+ if (soc_cc2cv - msoc <= 0)
+ goto cv_estimate;
- t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
- t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
- t_predicted_cc *= HOURS_TO_SECONDS;
- t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
+ divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
+ t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
+ HOURS_TO_SECONDS, divisor);
+ break;
+ case TTF_MODE_QNOVO:
+ soc_per_step = 100 / MAX_CC_STEPS;
+ for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
+ msoc_next_step = (i + 1) * soc_per_step;
+ if (i == msoc / soc_per_step)
+ msoc_this_step = msoc;
+ else
+ msoc_this_step = i * soc_per_step;
-skip_cc_estimate:
- fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
+ /* scale ibatt by 85% to account for discharge pulses */
+ ibatt_this_step = min(
+ chip->ttf.cc_step.arr[i] / MILLI_UNIT,
+ ibatt_avg) * 85 / 100;
+ divisor = max(100, ibatt_this_step * 100);
+ t_predicted_this_step = div_s64((s64)act_cap_mah *
+ (msoc_next_step - msoc_this_step) *
+ HOURS_TO_SECONDS, divisor);
+ t_predicted += t_predicted_this_step;
+ fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
+ msoc_this_step, msoc_next_step,
+ ibatt_this_step, t_predicted_this_step);
+ }
+ break;
+ default:
+ pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+ break;
+ }
- /* CV estimate starts here */
- if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
- ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
+cv_estimate:
+ fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
+
+ iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
+ fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
+
+ if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
+ tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
else
- ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
+ tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
- if (msoc < 95)
- centi_tau_scale = 100;
- else
- centi_tau_scale = 20 * (100 - msoc);
+ rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
+ if (rc < 0) {
+ pr_err("failed to interpolate tau rc=%d\n", rc);
+ return rc;
+ }
- fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
- rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
- fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
- t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
- t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
- t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
- t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
- fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
- *val = t_predicted_cc + t_predicted_cv;
+ /* tau is scaled linearly from 95% to 100% SOC */
+ if (msoc >= 95)
+ tau = tau * 2 * (100 - msoc) / 10;
+
+ fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
+ t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
+ HOURS_TO_SECONDS, NANO_UNIT);
+ fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
+ t_predicted += t_predicted_cv;
+
+ fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
+ if (chip->ttf.last_ms != 0) {
+ delta_ms = ktime_ms_delta(ktime_get_boottime(),
+ ms_to_ktime(chip->ttf.last_ms));
+ if (delta_ms > 10000) {
+ ttf_slope = div64_s64(
+ (s64)(t_predicted - chip->ttf.last_ttf) *
+ MICRO_UNIT, delta_ms);
+ if (ttf_slope > -100)
+ ttf_slope = -100;
+ else if (ttf_slope < -2000)
+ ttf_slope = -2000;
+
+ t_predicted = div_s64(
+ (s64)ttf_slope * delta_ms, MICRO_UNIT) +
+ chip->ttf.last_ttf;
+ fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
+ } else {
+ t_predicted = chip->ttf.last_ttf;
+ }
+ }
+
+ /* clamp the ttf to 0 */
+ if (t_predicted < 0)
+ t_predicted = 0;
+
+ fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
+ *val = t_predicted;
return 0;
}
+static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+{
+ int rc;
+
+ mutex_lock(&chip->ttf.lock);
+ rc = fg_get_time_to_full_locked(chip, val);
+ mutex_unlock(&chip->ttf.lock);
+ return rc;
+}
+
#define CENTI_ICORRECT_C0 105
#define CENTI_ICORRECT_C1 20
static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
{
- int rc, ibatt_avg, msoc, act_cap_uah;
- s32 divisor;
- s64 t_predicted;
+ int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
- rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
+ rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
if (rc < 0) {
/* try to get instantaneous current */
rc = fg_get_battery_current(chip, &ibatt_avg);
@@ -2932,16 +3100,10 @@
}
}
- /* clamp ibatt_avg to 150mA */
- if (ibatt_avg < 150000)
- ibatt_avg = 150000;
-
- rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
- if (rc < 0) {
- pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
- return rc;
- }
- act_cap_uah *= MILLI_UNIT;
+ ibatt_avg /= MILLI_UNIT;
+ /* clamp ibatt_avg to 100mA */
+ if (ibatt_avg < 100)
+ ibatt_avg = 100;
rc = fg_get_prop_capacity(chip, &msoc);
if (rc < 0) {
@@ -2949,14 +3111,25 @@
return rc;
}
- t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
- t_predicted *= HOURS_TO_SECONDS;
- divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
- divisor = div_s64((s64)divisor * ibatt_avg, 10000);
- if (divisor > 0)
- t_predicted = div_s64(t_predicted, divisor);
+ rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
+ if (rc < 0) {
+ pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
+ return rc;
+ }
- *val = t_predicted;
+ rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
+ if (rc < 0) {
+ pr_err("failed to get full soc rc=%d\n", rc);
+ return rc;
+ }
+ full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
+ FULL_SOC_RAW);
+ act_cap_mah = full_soc * act_cap_mah / 100;
+
+ divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
+ divisor = ibatt_avg * divisor / 100;
+ divisor = max(100, divisor);
+ *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
return 0;
}
@@ -3118,6 +3291,67 @@
fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
return 0;
}
+
+static void ttf_work(struct work_struct *work)
+{
+ struct fg_chip *chip = container_of(work, struct fg_chip,
+ ttf_work.work);
+ int rc, ibatt_now, vbatt_now, ttf;
+ ktime_t ktime_now;
+
+ mutex_lock(&chip->ttf.lock);
+ if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
+ chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
+ goto end_work;
+
+ rc = fg_get_battery_current(chip, &ibatt_now);
+ if (rc < 0) {
+ pr_err("failed to get battery current, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ rc = fg_get_battery_voltage(chip, &vbatt_now);
+ if (rc < 0) {
+ pr_err("failed to get battery voltage, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
+ fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
+
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+ rc = fg_get_time_to_full_locked(chip, &ttf);
+ if (rc < 0) {
+ pr_err("failed to get ttf, rc=%d\n", rc);
+ goto end_work;
+ }
+
+ /* keep the wake lock and prime the IBATT and VBATT buffers */
+ if (ttf < 0) {
+ /* delay for one FG cycle */
+ schedule_delayed_work(&chip->ttf_work,
+ msecs_to_jiffies(1500));
+ mutex_unlock(&chip->ttf.lock);
+ return;
+ }
+
+ /* update the TTF reference point every minute */
+ ktime_now = ktime_get_boottime();
+ if (ktime_ms_delta(ktime_now,
+ ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
+ chip->ttf.last_ms == 0) {
+ chip->ttf.last_ttf = ttf;
+ chip->ttf.last_ms = ktime_to_ms(ktime_now);
+ }
+ }
+
+ /* recurse every 10 seconds */
+ schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
+end_work:
+ vote(chip->awake_votable, TTF_PRIMING, false, 0);
+ mutex_unlock(&chip->ttf.lock);
+}
+
/* PSY CALLBACKS STAY HERE */
static int fg_psy_get_property(struct power_supply *psy,
@@ -3194,6 +3428,20 @@
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_CC_STEP:
+ if ((chip->ttf.cc_step.sel >= 0) &&
+ (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+ pval->intval =
+ chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ chip->ttf.cc_step.sel);
+ return -EINVAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ pval->intval = chip->ttf.cc_step.sel;
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -3232,6 +3480,26 @@
case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
rc = fg_prepare_for_qnovo(chip, pval->intval);
break;
+ case POWER_SUPPLY_PROP_CC_STEP:
+ if ((chip->ttf.cc_step.sel >= 0) &&
+ (chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+ chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
+ pval->intval;
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ chip->ttf.cc_step.sel);
+ return -EINVAL;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
+ chip->ttf.cc_step.sel = pval->intval;
+ } else {
+ pr_err("cc_step_sel is out of bounds [0, %d]\n",
+ pval->intval);
+ return -EINVAL;
+ }
+ break;
default:
break;
}
@@ -3245,6 +3513,8 @@
switch (psp) {
case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ case POWER_SUPPLY_PROP_CC_STEP:
+ case POWER_SUPPLY_PROP_CC_STEP_SEL:
return 1;
default:
break;
@@ -3305,6 +3575,8 @@
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
POWER_SUPPLY_PROP_DEBUG_BATTERY,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CC_STEP,
+ POWER_SUPPLY_PROP_CC_STEP_SEL,
};
static const struct power_supply_desc fg_psy_desc = {
@@ -3515,8 +3787,7 @@
return rc;
}
- if (chip->cyc_ctr.en)
- restore_cycle_counter(chip);
+ restore_cycle_counter(chip);
if (chip->dt.jeita_hyst_temp >= 0) {
val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
@@ -3766,6 +4037,11 @@
if (rc < 0)
pr_err("Error in adjusting timebase, rc=%d\n", rc);
+ rc = fg_adjust_recharge_voltage(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting recharge_voltage, rc=%d\n",
+ rc);
+
chip->last_batt_temp = batt_temp;
power_supply_changed(chip->batt_psy);
}
@@ -3813,8 +4089,7 @@
int rc;
fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
- if (chip->cyc_ctr.en)
- schedule_work(&chip->cycle_count_work);
+ fg_cycle_counter_update(chip);
if (chip->cl.active)
fg_cap_learning_update(chip);
@@ -4519,6 +4794,7 @@
chip->charge_status = -EINVAL;
chip->prev_charge_status = -EINVAL;
chip->ki_coeff_full_soc = -EINVAL;
+ chip->online_status = -EINVAL;
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
dev_err(chip->dev, "Parent regmap is unavailable\n");
@@ -4587,15 +4863,14 @@
mutex_init(&chip->sram_rw_lock);
mutex_init(&chip->cyc_ctr.lock);
mutex_init(&chip->cl.lock);
- mutex_init(&chip->batt_avg_lock);
+ mutex_init(&chip->ttf.lock);
mutex_init(&chip->charge_full_lock);
init_completion(&chip->soc_update);
init_completion(&chip->soc_ready);
init_completion(&chip->mem_grant);
INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
INIT_WORK(&chip->status_change_work, status_change_work);
- INIT_WORK(&chip->cycle_count_work, cycle_count_work);
- INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
+ INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
rc = fg_memif_init(chip);
@@ -4692,7 +4967,7 @@
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
- cancel_delayed_work_sync(&chip->batt_avg_work);
+ cancel_delayed_work_sync(&chip->ttf_work);
if (fg_sram_dump)
cancel_delayed_work_sync(&chip->sram_dump_work);
return 0;
@@ -4707,9 +4982,7 @@
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
- fg_circ_buf_clr(&chip->ibatt_circ_buf);
- fg_circ_buf_clr(&chip->vbatt_circ_buf);
- schedule_delayed_work(&chip->batt_avg_work, 0);
+ schedule_delayed_work(&chip->ttf_work, 0);
if (fg_sram_dump)
schedule_delayed_work(&chip->sram_dump_work,
msecs_to_jiffies(fg_sram_dump_period_ms));
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index cf90f90..b208079 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -1396,6 +1396,17 @@
union power_supply_propval pval = {0};
/*
+ * In some cases (esp shutting down) the userspace would disable by
+ * setting qnovo_enable=0. Also charger could be removed or there is
+ * an error (i.e. its not okay to run qnovo)-
+ * skip taking ESR measurement in such situations
+ */
+
+ if (get_client_vote(chip->disable_votable, USER_VOTER)
+ || get_effective_result(chip->not_ok_to_qnovo_votable) > 0)
+ return IRQ_HANDLED;
+
+ /*
* hw resets pt_en bit once ptrain_done triggers.
* vote on behalf of QNI to disable it such that
* once QNI enables it, the votable state changes
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index faca084..60f5d23 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -900,6 +900,7 @@
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
+ POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
POWER_SUPPLY_PROP_CHARGE_DONE,
POWER_SUPPLY_PROP_PARALLEL_DISABLE,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
@@ -962,6 +963,9 @@
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
val->intval = chg->step_chg_enabled;
break;
+ case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+ val->intval = chg->sw_jeita_enabled;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
rc = smblib_get_prop_batt_voltage_now(chg, val);
break;
@@ -1081,6 +1085,13 @@
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
chg->step_chg_enabled = !!val->intval;
break;
+ case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+ if (chg->sw_jeita_enabled != (!!val->intval)) {
+ rc = smblib_disable_hw_jeita(chg, !!val->intval);
+ if (rc == 0)
+ chg->sw_jeita_enabled = !!val->intval;
+ }
+ break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
chg->batt_profile_fcc_ua = val->intval;
vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
@@ -1123,6 +1134,7 @@
case POWER_SUPPLY_PROP_RERUN_AICL:
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+ case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
return 1;
default:
break;
@@ -1715,6 +1727,14 @@
}
}
+ if (chg->sw_jeita_enabled) {
+ rc = smblib_disable_hw_jeita(chg, true);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
+ return rc;
+ }
+ }
+
return rc;
}
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 601f3e1..cc3bd93 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -2079,6 +2079,29 @@
return rc;
}
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
+{
+ int rc;
+ u8 mask;
+
+ /*
+ * Disable h/w base JEITA compensation if s/w JEITA is enabled
+ */
+ mask = JEITA_EN_COLD_SL_FCV_BIT
+ | JEITA_EN_HOT_SL_FCV_BIT
+ | JEITA_EN_HOT_SL_CCC_BIT
+ | JEITA_EN_COLD_SL_CCC_BIT,
+ rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
+ disable ? 0 : mask);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't configure s/w jeita rc=%d\n",
+ rc);
+ return rc;
+ }
+ return 0;
+}
+
/*******************
* DC PSY GETTERS *
*******************/
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 2746555..bfc5cae 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -508,6 +508,7 @@
union power_supply_propval *val);
int smblib_icl_override(struct smb_charger *chg, bool override);
int smblib_dp_dm(struct smb_charger *chg, int val);
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
int smblib_rerun_aicl(struct smb_charger *chg);
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
index 053aac3..06ecc7e 100644
--- a/drivers/power/supply/qcom/step-chg-jeita.c
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -271,6 +271,13 @@
int rc = 0, fcc_ua = 0, fv_uv = 0;
u64 elapsed_us;
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_SW_JEITA_ENABLED, &pval);
+ if (rc < 0)
+ chip->sw_jeita_enable = 0;
+ else
+ chip->sw_jeita_enable = pval.intval;
+
if (!chip->sw_jeita_enable) {
if (chip->fcc_votable)
vote(chip->fcc_votable, JEITA_VOTER, false, 0);
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index aef28db..0be35b3 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -24,6 +24,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/qpnp/qpnp-revid.h>
#define QPNP_LCDB_REGULATOR_DRIVER_NAME "qcom,qpnp-lcdb-regulator"
@@ -146,6 +147,8 @@
#define MIN_SOFT_START_US 0
#define MAX_SOFT_START_US 2000
+#define BST_HEADROOM_DEFAULT_MV 200
+
struct ldo_regulator {
struct regulator_desc rdesc;
struct regulator_dev *rdev;
@@ -186,12 +189,14 @@
int soft_start_us;
int vreg_ok_dbc_us;
int voltage_mv;
+ u16 headroom_mv;
};
struct qpnp_lcdb {
struct device *dev;
struct platform_device *pdev;
struct regmap *regmap;
+ struct pmic_revid_data *pmic_rev_id;
u32 base;
int sc_irq;
@@ -199,9 +204,6 @@
bool ttw_enable;
bool ttw_mode_sw;
- /* top level DT params */
- bool force_module_reenable;
-
/* status parameters */
bool lcdb_enabled;
bool settings_saved;
@@ -579,6 +581,65 @@
return 0;
}
+static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb)
+{
+ int rc;
+ u8 val = 0;
+
+ /* required only for PM660L */
+ if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
+ return 0;
+
+ val = MODULE_EN_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to enable lcdb rc= %d\n", rc);
+ return rc;
+ }
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to disable lcdb rc= %d\n", rc);
+ return rc;
+ }
+
+ /* execute the below for rev1.1 */
+ if (lcdb->pmic_rev_id->rev3 == PM660L_V1P1_REV3 &&
+ lcdb->pmic_rev_id->rev4 == PM660L_V1P1_REV4) {
+ /*
+ * delay to make sure that the MID pin – ie the
+ * output of the LCDB boost – returns to 0V
+ * after the module is disabled
+ */
+ usleep_range(10000, 10100);
+
+ rc = qpnp_lcdb_masked_write(lcdb,
+ lcdb->base + LCDB_MISC_CTL_REG,
+ DIS_SCP_BIT, DIS_SCP_BIT);
+ if (rc < 0) {
+ pr_err("Failed to disable SC rc=%d\n", rc);
+ return rc;
+ }
+ /* delay for SC-disable to take effect */
+ usleep_range(1000, 1100);
+
+ rc = qpnp_lcdb_masked_write(lcdb,
+ lcdb->base + LCDB_MISC_CTL_REG,
+ DIS_SCP_BIT, 0);
+ if (rc < 0) {
+ pr_err("Failed to enable SC rc=%d\n", rc);
+ return rc;
+ }
+ /* delay for SC-enable to take effect */
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
{
int rc = 0, timeout, delay;
@@ -598,31 +659,20 @@
}
}
+ rc = qpnp_lcdb_enable_wa(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to execute enable_wa rc=%d\n", rc);
+ return rc;
+ }
+
val = MODULE_EN_BIT;
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
&val, 1);
if (rc < 0) {
- pr_err("Failed to enable lcdb rc= %d\n", rc);
+ pr_err("Failed to disable lcdb rc= %d\n", rc);
goto fail_enable;
}
- if (lcdb->force_module_reenable) {
- val = 0;
- rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
- &val, 1);
- if (rc < 0) {
- pr_err("Failed to enable lcdb rc= %d\n", rc);
- goto fail_enable;
- }
- val = MODULE_EN_BIT;
- rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
- &val, 1);
- if (rc < 0) {
- pr_err("Failed to disable lcdb rc= %d\n", rc);
- goto fail_enable;
- }
- }
-
/* poll for vreg_ok */
timeout = 10;
delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
@@ -806,28 +856,40 @@
#define VOLTAGE_STEP_50_MV 50
#define VOLTAGE_STEP_50MV_OFFSET 0xA
static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
- int voltage_mv)
+ int voltage_mv, u8 type)
{
int rc = 0;
u8 val = 0;
+ int bst_voltage_mv;
+ struct ldo_regulator *ldo = &lcdb->ldo;
+ struct ncp_regulator *ncp = &lcdb->ncp;
+ struct bst_params *bst = &lcdb->bst;
- if (voltage_mv < MIN_BST_VOLTAGE_MV)
- voltage_mv = MIN_BST_VOLTAGE_MV;
- else if (voltage_mv > MAX_BST_VOLTAGE_MV)
- voltage_mv = MAX_BST_VOLTAGE_MV;
+ /* Vout_Boost = headroom_mv + max( Vout_LDO, abs (Vout_NCP)) */
+ bst_voltage_mv = max(voltage_mv, max(ldo->voltage_mv, ncp->voltage_mv));
+ bst_voltage_mv += bst->headroom_mv;
- val = DIV_ROUND_UP(voltage_mv - MIN_BST_VOLTAGE_MV,
- VOLTAGE_STEP_50_MV);
+ if (bst_voltage_mv < MIN_BST_VOLTAGE_MV)
+ bst_voltage_mv = MIN_BST_VOLTAGE_MV;
+ else if (bst_voltage_mv > MAX_BST_VOLTAGE_MV)
+ bst_voltage_mv = MAX_BST_VOLTAGE_MV;
- rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
- LCDB_BST_OUTPUT_VOLTAGE_REG,
- SET_OUTPUT_VOLTAGE_MASK, val);
- if (rc < 0)
- pr_err("Failed to set boost voltage %d mv rc=%d\n",
- voltage_mv, rc);
- else
- pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n",
- voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val);
+ if (bst_voltage_mv != bst->voltage_mv) {
+ val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
+ VOLTAGE_STEP_50_MV);
+
+ rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
+ LCDB_BST_OUTPUT_VOLTAGE_REG,
+ SET_OUTPUT_VOLTAGE_MASK, val);
+ if (rc < 0) {
+ pr_err("Failed to set boost voltage %d mv rc=%d\n",
+ bst_voltage_mv, rc);
+ } else {
+ pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n",
+ bst_voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val);
+ bst->voltage_mv = bst_voltage_mv;
+ }
+ }
return rc;
}
@@ -858,25 +920,16 @@
u16 offset = LCDB_LDO_OUTPUT_VOLTAGE_REG;
u8 val = 0;
- if (type == BST)
- return qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv);
-
- if (type == NCP)
- offset = LCDB_NCP_OUTPUT_VOLTAGE_REG;
-
if (!is_between(voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV)) {
pr_err("Invalid voltage %dmv (min=%d max=%d)\n",
voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV);
return -EINVAL;
}
- /* Change the BST voltage to LDO + 100mV */
- if (type == LDO) {
- rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv + 100);
- if (rc < 0) {
- pr_err("Failed to set boost voltage rc=%d\n", rc);
- return rc;
- }
+ rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv, type);
+ if (rc < 0) {
+ pr_err("Failed to set boost voltage rc=%d\n", rc);
+ return rc;
}
/* Below logic is only valid for LDO and NCP type */
@@ -889,6 +942,9 @@
val += VOLTAGE_STEP_50MV_OFFSET;
}
+ if (type == NCP)
+ offset = LCDB_NCP_OUTPUT_VOLTAGE_REG;
+
rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + offset,
SET_OUTPUT_VOLTAGE_MASK, val);
if (rc < 0)
@@ -1011,6 +1067,8 @@
rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, LDO);
if (rc < 0)
pr_err("Failed to set LDO voltage rc=%c\n", rc);
+ else
+ lcdb->ldo.voltage_mv = min_uV / 1000;
return rc;
}
@@ -1082,6 +1140,8 @@
rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, NCP);
if (rc < 0)
pr_err("Failed to set LDO voltage rc=%c\n", rc);
+ else
+ lcdb->ncp.voltage_mv = min_uV / 1000;
return rc;
}
@@ -1342,6 +1402,12 @@
return -EINVAL;
}
+ /* Boost head room configuration */
+ of_property_read_u16(node, "qcom,bst-headroom-mv",
+ &lcdb->bst.headroom_mv);
+ if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV)
+ lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+
return 0;
}
@@ -1648,6 +1714,9 @@
}
lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200;
+ if (!lcdb->bst.headroom_mv)
+ lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+
return 0;
}
@@ -1674,7 +1743,8 @@
return rc;
}
- if (lcdb->sc_irq >= 0) {
+ if (lcdb->sc_irq >= 0 &&
+ lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) {
lcdb->sc_count = 0;
rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
@@ -1714,8 +1784,26 @@
{
int rc = 0;
const char *label;
- struct device_node *temp, *node = lcdb->dev->of_node;
+ struct device_node *revid_dev_node, *temp, *node = lcdb->dev->of_node;
+ revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property - fail driver\n");
+ return -EINVAL;
+ }
+
+ lcdb->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR(lcdb->pmic_rev_id)) {
+ pr_debug("Unable to get revid data\n");
+ /*
+ * revid should to be defined, return -EPROBE_DEFER
+ * until the revid module registers.
+ */
+ of_node_put(revid_dev_node);
+ return -EPROBE_DEFER;
+ }
+
+ of_node_put(revid_dev_node);
for_each_available_child_of_node(node, temp) {
rc = of_property_read_string(temp, "label", &label);
if (rc < 0) {
@@ -1742,9 +1830,6 @@
}
}
- lcdb->force_module_reenable = of_property_read_bool(node,
- "qcom,force-module-reenable");
-
if (of_property_read_bool(node, "qcom,ttw-enable")) {
rc = qpnp_lcdb_parse_ttw(lcdb);
if (rc < 0) {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 38eff96..d1f717b 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -753,6 +753,15 @@
source "drivers/soc/qcom/memshare/Kconfig"
+config MSM_REMOTEQDSS
+ bool "Allow debug tools to enable events on other processors"
+ depends on QCOM_SCM && DEBUG_FS
+ help
+ Other onchip processors/execution environments may support debug
+ events. Provide a sysfs interface for debug tools to dynamically
+ enable/disable these events. Interface located in
+ /sys/class/remoteqdss.
+
config QSEE_IPC_IRQ_BRIDGE
tristate "QSEE IPC Interrupt Bridge"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 2d7d62a..567493d 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -79,4 +79,5 @@
obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
+obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a2ab266..dc891eb 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -292,6 +292,7 @@
ICNSS_WLFW_EXISTS,
ICNSS_SHUTDOWN_DONE,
ICNSS_HOST_TRIGGERED_PDR,
+ ICNSS_FW_DOWN,
};
struct ce_irq_list {
@@ -1946,6 +1947,12 @@
icnss_pr_dbg("Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
+ if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+ icnss_pr_dbg("FW down, ignoring 0x%x, state: 0x%lx\n",
+ msg_id, penv->state);
+ return;
+ }
+
switch (msg_id) {
case QMI_WLFW_FW_READY_IND_V01:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND,
@@ -1992,6 +1999,7 @@
return -ENODEV;
set_bit(ICNSS_WLFW_EXISTS, &penv->state);
+ clear_bit(ICNSS_FW_DOWN, &penv->state);
penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv);
if (!penv->wlfw_clnt) {
@@ -2492,6 +2500,8 @@
icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
+ set_bit(ICNSS_FW_DOWN, &priv->state);
+
if (notif->crashed)
priv->stats.recovery.root_pd_crash++;
else
@@ -2619,6 +2629,7 @@
icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
*state, priv->state, icnss_pdr_cause[cause]);
event_post:
+ set_bit(ICNSS_FW_DOWN, &priv->state);
icnss_ignore_qmi_timeout(true);
clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
@@ -2627,6 +2638,8 @@
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
done:
+ if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
+ clear_bit(ICNSS_FW_DOWN, &priv->state);
return NOTIFY_OK;
}
@@ -3834,6 +3847,9 @@
case ICNSS_HOST_TRIGGERED_PDR:
seq_puts(s, "HOST TRIGGERED PDR");
continue;
+ case ICNSS_FW_DOWN:
+ seq_puts(s, "FW DOWN");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
index aa6c5d7..bcaeca5 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
@@ -1794,7 +1794,7 @@
int ret = 0;
char *test_cl = "test-client";
bool log_transaction = false;
- u64 slp_ib, slp_ab;
+ u64 dual_ib, dual_ab, act_ib, act_ab;
rt_mutex_lock(&msm_bus_adhoc_lock);
@@ -1815,15 +1815,20 @@
}
if (cl->active_only) {
- slp_ib = 0;
- slp_ab = 0;
+ act_ib = ib;
+ act_ab = ab;
+ dual_ib = 0;
+ dual_ab = 0;
} else {
- slp_ib = ib;
- slp_ab = ab;
+ dual_ib = ib;
+ dual_ab = ab;
+ act_ib = 0;
+ act_ab = 0;
}
- ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab,
- cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only);
+ ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, dual_ib,
+ dual_ab, cl->cur_act_ib, cl->cur_act_ab, cl->first_hop,
+ cl->active_only);
if (ret) {
MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
@@ -1832,10 +1837,10 @@
}
commit_data();
- cl->cur_act_ib = ib;
- cl->cur_act_ab = ab;
- cl->cur_slp_ib = slp_ib;
- cl->cur_slp_ab = slp_ab;
+ cl->cur_act_ib = act_ib;
+ cl->cur_act_ab = act_ab;
+ cl->cur_dual_ib = dual_ib;
+ cl->cur_dual_ab = dual_ab;
if (log_transaction)
getpath_debug(cl->mas, cl->first_hop, cl->active_only);
@@ -1847,7 +1852,7 @@
}
static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
- u64 act_ib, u64 slp_ib, u64 slp_ab)
+ u64 act_ib, u64 dual_ib, u64 dual_ab)
{
int ret = 0;
@@ -1860,18 +1865,18 @@
if ((cl->cur_act_ib == act_ib) &&
(cl->cur_act_ab == act_ab) &&
- (cl->cur_slp_ib == slp_ib) &&
- (cl->cur_slp_ab == slp_ab)) {
+ (cl->cur_dual_ib == dual_ib) &&
+ (cl->cur_dual_ab == dual_ab)) {
MSM_BUS_ERR("No change in vote");
goto exit_change_context;
}
- if (!slp_ab && !slp_ib)
+ if (!dual_ab && !dual_ib)
cl->active_only = true;
- msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib);
- ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab,
- cl->cur_act_ab, cl->cur_act_ab, cl->first_hop,
- cl->active_only);
+ msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_dual_ib);
+ ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, dual_ib,
+ dual_ab, cl->cur_act_ab, cl->cur_act_ab,
+ cl->first_hop, cl->active_only);
if (ret) {
MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
__func__, ret, cl->active_only);
@@ -1880,8 +1885,8 @@
commit_data();
cl->cur_act_ib = act_ib;
cl->cur_act_ab = act_ab;
- cl->cur_slp_ib = slp_ib;
- cl->cur_slp_ab = slp_ab;
+ cl->cur_dual_ib = dual_ib;
+ cl->cur_dual_ab = dual_ab;
// trace_bus_update_request_end(cl->name);
exit_change_context:
rt_mutex_unlock(&msm_bus_adhoc_lock);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_client_api.c b/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
index b6595a2..14583cb 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -142,17 +142,17 @@
* act_ab: The average bandwidth(AB) in Bytes/s to be used in active context.
* act_ib: The instantaneous bandwidth(IB) in Bytes/s to be used in active
* context.
- * slp_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
- * slp_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
+ * dual_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
+ * dual_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
* context.
*/
int
msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
- u64 act_ib, u64 slp_ib, u64 slp_ab)
+ u64 act_ib, u64 dual_ib, u64 dual_ab)
{
if (arb_ops.update_context)
return arb_ops.update_bw_context(cl, act_ab, act_ib,
- slp_ab, slp_ib);
+ dual_ab, dual_ib);
return -EPROBE_DEFER;
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_core.h b/drivers/soc/qcom/msm_bus/msm_bus_core.h
index 4911cf2..ee67ac0 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_core.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_core.h
@@ -68,7 +68,7 @@
int (*update_bw)(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
void (*unregister)(struct msm_bus_client_handle *cl);
int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab,
- u64 act_ib, u64 slp_ib, u64 slp_ab);
+ u64 act_ib, u64 dual_ib, u64 dual_ab);
int (*query_usecase)(struct msm_bus_tcs_usecase *tcs_usecase,
uint32_t cl, unsigned int index);
int (*query_usecase_all)(struct msm_bus_tcs_handle *tcs_handle,
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index e45f61e..de89b8f 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -821,6 +821,7 @@
uint16_t clnt;
int i, j;
+ memset(&data, 0, sizeof(data));
data.opcode = RESET_EVENTS;
data.reset_event = code;
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 92a97fae..9f12564a 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -239,7 +239,7 @@
int num_of_intents, uint32_t size)
{
int i;
- int rc;
+ int rc = 0;
if (!apr_ch || !num_of_intents || !size) {
pr_err("%s: Invalid parameter\n", __func__);
diff --git a/drivers/soc/qcom/remoteqdss.c b/drivers/soc/qcom/remoteqdss.c
new file mode 100644
index 0000000..9a668c0
--- /dev/null
+++ b/drivers/soc/qcom/remoteqdss.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <soc/qcom/scm.h>
+#include <linux/debugfs.h>
+#include <linux/ratelimit.h>
+#include <linux/dma-mapping.h>
+
+#define REMOTEQDSS_FLAG_QUIET (BIT(0))
+
+static unsigned long remoteqdss_dbg_flags;
+module_param_named(dbg_flags, remoteqdss_dbg_flags, ulong, 0644);
+
+static struct dentry *remoteqdss_dir;
+
+#define REMOTEQDSS_ERR(fmt, ...) \
+ pr_debug("%s: " fmt, __func__, ## __VA_ARGS__)
+
+#define REMOTEQDSS_ERR_CALLER(fmt, caller, ...) \
+ pr_debug("%pf: " fmt, caller, ## __VA_ARGS__)
+
+struct qdss_msg_translation {
+ u64 val;
+ char *msg;
+};
+
+/*
+ * id Unique identifier
+ * sw_entity_group Array index
+ * sw_event_group Array index
+ * dir Parent debugfs directory
+ */
+struct remoteqdss_data {
+ uint32_t id;
+ uint32_t sw_entity_group;
+ uint32_t sw_event_group;
+ struct dentry *dir;
+};
+
+static struct device dma_dev;
+
+/* Allowed message formats */
+
+enum remoteqdss_cmd_id {
+ CMD_ID_QUERY_SWEVENT_TAG,
+ CMD_ID_FILTER_SWTRACE_STATE,
+ CMD_ID_QUERY_SWTRACE_STATE,
+ CMD_ID_FILTER_SWEVENT,
+ CMD_ID_QUERY_SWEVENT,
+ CMD_ID_FILTER_SWENTITY,
+ CMD_ID_QUERY_SWENTITY,
+};
+
+struct remoteqdss_header_fmt {
+ uint32_t subsys_id;
+ uint32_t cmd_id;
+};
+
+struct remoteqdss_filter_swtrace_state_fmt {
+ struct remoteqdss_header_fmt h;
+ uint32_t state;
+};
+
+struct remoteqdss_filter_swevent_fmt {
+ struct remoteqdss_header_fmt h;
+ uint32_t event_group;
+ uint32_t event_mask;
+};
+
+struct remoteqdss_query_swevent_fmt {
+ struct remoteqdss_header_fmt h;
+ uint32_t event_group;
+};
+
+struct remoteqdss_filter_swentity_fmt {
+ struct remoteqdss_header_fmt h;
+ uint32_t entity_group;
+ uint32_t entity_mask;
+};
+
+struct remoteqdss_query_swentity_fmt {
+ struct remoteqdss_header_fmt h;
+ uint32_t entity_group;
+};
+
+/* msgs is a null terminated array */
+static void remoteqdss_err_translation(struct qdss_msg_translation *msgs,
+ u64 err, const void *caller)
+{
+ static DEFINE_RATELIMIT_STATE(rl, 5 * HZ, 2);
+ struct qdss_msg_translation *msg;
+
+ if (!err)
+ return;
+
+ if (remoteqdss_dbg_flags & REMOTEQDSS_FLAG_QUIET)
+ return;
+
+ for (msg = msgs; msg->msg; msg++) {
+ if (err == msg->val && __ratelimit(&rl)) {
+ REMOTEQDSS_ERR_CALLER("0x%llx: %s\n", caller, err,
+ msg->msg);
+ return;
+ }
+ }
+
+ REMOTEQDSS_ERR_CALLER("Error 0x%llx\n", caller, err);
+}
+
+/* Shared across all remoteqdss scm functions */
+#define SCM_CMD_ID (0x1)
+
+/* Response Values */
+#define SCM_CMD_FAIL (0x80)
+#define SCM_QDSS_UNAVAILABLE (0x81)
+#define SCM_UNINITIALIZED (0x82)
+#define SCM_BAD_ARG (0x83)
+#define SCM_BAD_SUBSYS (0x85)
+
+static struct qdss_msg_translation remoteqdss_scm_msgs[] = {
+ {SCM_CMD_FAIL,
+ "Command failed"},
+ {SCM_QDSS_UNAVAILABLE,
+ "QDSS not available or cannot turn QDSS (clock) on"},
+ {SCM_UNINITIALIZED,
+ "Tracer not initialized or unable to initialize"},
+ {SCM_BAD_ARG,
+ "Invalid parameter value"},
+ {SCM_BAD_SUBSYS,
+ "Incorrect subsys ID"},
+ {}
+};
+
+static struct remoteqdss_data *create_remoteqdss_data(u32 id)
+{
+ struct remoteqdss_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ data->id = id;
+ return data;
+}
+
+static void free_remoteqdss_data(struct remoteqdss_data *data)
+{
+ kfree(data);
+}
+
+static int remoteqdss_do_scm_call(struct scm_desc *desc,
+ dma_addr_t addr, size_t size, const void *caller)
+{
+ int ret;
+
+ memset(desc, 0, sizeof(*desc));
+ desc->args[0] = dma_to_phys(&dma_dev, addr);
+ desc->args[1] = size;
+ desc->arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
+
+ ret = scm_call2(
+ SCM_SIP_FNID(SCM_SVC_QDSS, SCM_CMD_ID),
+ desc);
+ if (ret)
+ return ret;
+
+ remoteqdss_err_translation(remoteqdss_scm_msgs, desc->ret[0], caller);
+ ret = desc->ret[0] ? -EINVAL : 0;
+ return ret;
+}
+
+static int remoteqdss_scm_query_swtrace(void *priv, u64 *val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_header_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->subsys_id = data->id;
+ fmt->cmd_id = CMD_ID_QUERY_SWTRACE_STATE;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+ *val = desc.ret[1];
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+static int remoteqdss_scm_filter_swtrace(void *priv, u64 val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_filter_swtrace_state_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->h.subsys_id = data->id;
+ fmt->h.cmd_id = CMD_ID_FILTER_SWTRACE_STATE;
+ fmt->state = (uint32_t)val;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_sw_trace_output,
+ remoteqdss_scm_query_swtrace,
+ remoteqdss_scm_filter_swtrace,
+ "0x%llx\n");
+
+static int remoteqdss_scm_query_tag(void *priv, u64 *val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_header_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->subsys_id = data->id;
+ fmt->cmd_id = CMD_ID_QUERY_SWEVENT_TAG;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+ *val = desc.ret[1];
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_tag,
+ remoteqdss_scm_query_tag,
+ NULL,
+ "0x%llx\n");
+
+static int remoteqdss_scm_query_swevent(void *priv, u64 *val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_query_swevent_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->h.subsys_id = data->id;
+ fmt->h.cmd_id = CMD_ID_QUERY_SWEVENT;
+ fmt->event_group = data->sw_event_group;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+ *val = desc.ret[1];
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+static int remoteqdss_scm_filter_swevent(void *priv, u64 val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_filter_swevent_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->h.subsys_id = data->id;
+ fmt->h.cmd_id = CMD_ID_FILTER_SWEVENT;
+ fmt->event_group = data->sw_event_group;
+ fmt->event_mask = (uint32_t)val;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_swevent,
+ remoteqdss_scm_query_swevent,
+ remoteqdss_scm_filter_swevent,
+ "0x%llx\n");
+
+static int remoteqdss_scm_query_swentity(void *priv, u64 *val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_query_swentity_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->h.subsys_id = data->id;
+ fmt->h.cmd_id = CMD_ID_QUERY_SWENTITY;
+ fmt->entity_group = data->sw_entity_group;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+ *val = desc.ret[1];
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+static int remoteqdss_scm_filter_swentity(void *priv, u64 val)
+{
+ struct remoteqdss_data *data = priv;
+ int ret;
+ struct scm_desc desc;
+ struct remoteqdss_filter_swentity_fmt *fmt;
+ dma_addr_t addr;
+
+ fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+ if (!fmt)
+ return -ENOMEM;
+ fmt->h.subsys_id = data->id;
+ fmt->h.cmd_id = CMD_ID_FILTER_SWENTITY;
+ fmt->entity_group = data->sw_entity_group;
+ fmt->entity_mask = (uint32_t)val;
+
+ ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+ __builtin_return_address(0));
+
+ dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_swentity,
+ remoteqdss_scm_query_swentity,
+ remoteqdss_scm_filter_swentity,
+ "0x%llx\n");
+
+static void __init enumerate_scm_devices(struct dentry *parent)
+{
+ u64 unused;
+ int ret;
+ struct remoteqdss_data *data;
+ struct dentry *dentry;
+
+ if (!is_scm_armv8())
+ return;
+
+ data = create_remoteqdss_data(0);
+ if (!data)
+ return;
+
+ /* Assume failure means device not present */
+ ret = remoteqdss_scm_query_swtrace(data, &unused);
+ if (ret)
+ goto out;
+
+ data->dir = debugfs_create_dir("tz", parent);
+ if (IS_ERR_OR_NULL(data->dir))
+ goto out;
+
+ dentry = debugfs_create_file("sw_trace_output", 0644,
+ data->dir, data, &fops_sw_trace_output);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ dentry = debugfs_create_u32("sw_entity_group", 0644,
+ data->dir, &data->sw_entity_group);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ dentry = debugfs_create_u32("sw_event_group", 0644,
+ data->dir, &data->sw_event_group);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ dentry = debugfs_create_file("tag", 0444,
+ data->dir, data, &fops_tag);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ dentry = debugfs_create_file("swevent", 0644,
+ data->dir, data, &fops_swevent);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ dentry = debugfs_create_file("swentity", 0644,
+ data->dir, data, &fops_swentity);
+ if (IS_ERR_OR_NULL(dentry))
+ goto out;
+
+ return;
+
+out:
+ debugfs_remove_recursive(data->dir);
+ free_remoteqdss_data(data);
+}
+
+static int __init remoteqdss_init(void)
+{
+ unsigned long old_flags = remoteqdss_dbg_flags;
+ int ret;
+
+ /* Set up DMA */
+ arch_setup_dma_ops(&dma_dev, 0, U64_MAX, NULL, false);
+ ret = dma_coerce_mask_and_coherent(&dma_dev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
+ /*
+ * disable normal error messages while checking
+ * if support is present.
+ */
+ remoteqdss_dbg_flags |= REMOTEQDSS_FLAG_QUIET;
+
+ remoteqdss_dir = debugfs_create_dir("remoteqdss", NULL);
+ if (!remoteqdss_dir)
+ return 0;
+
+ enumerate_scm_devices(remoteqdss_dir);
+
+ remoteqdss_dbg_flags = old_flags;
+ return 0;
+}
+late_initcall(remoteqdss_init);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 8580484..8a7043a6 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -845,6 +845,28 @@
}
EXPORT_SYMBOL(rpmh_read);
+/**
+ * rpmh_ctrlr_idle: Check if the controller is idle
+ *
+ * @rc: The RPMH handle got from rpmh_get_dev_channel
+ *
+ * Returns if the controller is idle or not.
+ */
+int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{
+ if (IS_ERR_OR_NULL(rc))
+ return -EINVAL;
+
+ if (rpmh_standalone)
+ return 0;
+
+ if (!mbox_controller_is_idle(rc->chan))
+ return -EBUSY;
+
+ return 0;
+}
+EXPORT_SYMBOL(rpmh_ctrlr_idle);
+
static inline int is_req_valid(struct rpmh_req *req)
{
return (req->sleep_val != UINT_MAX && req->wake_val != UINT_MAX
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index f4f4c36..2ecbf15 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <soc/qcom/rpmh.h>
+#include <soc/qcom/system_pm.h>
#define ARCH_TIMER_HZ (19200000UL)
#define PDC_TIME_VALID_SHIFT 31
@@ -34,6 +35,15 @@
}
/**
+ * system_sleep_allowed() - Returns if its okay to enter system low power modes
+ */
+bool system_sleep_allowed(void)
+{
+ return (rpmh_ctrlr_idle(rpmh_client) == 0);
+}
+EXPORT_SYMBOL(system_sleep_allowed);
+
+/**
* system_sleep_enter() - Activties done when entering system low power modes
*
* @sleep_val: The sleep duration in us.
diff --git a/drivers/soundwire/soundwire.c b/drivers/soundwire/soundwire.c
index f0c7aa9..16b16e5e 100644
--- a/drivers/soundwire/soundwire.c
+++ b/drivers/soundwire/soundwire.c
@@ -79,11 +79,16 @@
{
struct swr_device *swr_dev_loop, *safe;
+ /*
+ * master still has reference to all nodes and deletes
+ * at platform_unregister, so need to init the deleted
+ * entry
+ */
list_for_each_entry_safe(swr_dev_loop, safe,
&swr_dev->master->devices,
dev_list) {
if (swr_dev == swr_dev_loop)
- list_del(&swr_dev_loop->dev_list);
+ list_del_init(&swr_dev_loop->dev_list);
}
}
EXPORT_SYMBOL(swr_remove_device);
@@ -789,9 +794,7 @@
static void swr_master_release(struct device *dev)
{
- struct swr_master *master = to_swr_master(dev);
-
- kfree(master);
+ /* kfree of master done at swrm_remove of device */
}
#define swr_master_attr_gr NULL
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 55b1a0e..453a63f 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -409,6 +409,8 @@
# define DP_TEST_LINK_EDID_READ (1 << 2)
# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */
# define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */
+# define DP_TEST_LINK_AUDIO_PATTERN (1 << 5)
+# define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6)
#define DP_TEST_LINK_RATE 0x219
# define DP_LINK_RATE_162 (0x6)
@@ -417,6 +419,63 @@
#define DP_TEST_LANE_COUNT 0x220
#define DP_TEST_PATTERN 0x221
+# define DP_NO_TEST_PATTERN 0x0
+# define DP_COLOR_RAMP 0x1
+# define DP_BLACK_AND_WHITE_VERTICAL_LINES 0x2
+# define DP_COLOR_SQUARE 0x3
+
+#define DP_TEST_H_TOTAL_HI 0x222
+#define DP_TEST_H_TOTAL_LO 0x223
+
+#define DP_TEST_V_TOTAL_HI 0x224
+#define DP_TEST_V_TOTAL_LO 0x225
+
+#define DP_TEST_H_START_HI 0x226
+#define DP_TEST_H_START_LO 0x227
+
+#define DP_TEST_V_START_HI 0x228
+#define DP_TEST_V_START_LO 0x229
+
+#define DP_TEST_HSYNC_HI 0x22A
+# define DP_TEST_HSYNC_POLARITY (1 << 7)
+# define DP_TEST_HSYNC_WIDTH_HI_MASK (127 << 0)
+#define DP_TEST_HSYNC_WIDTH_LO 0x22B
+
+#define DP_TEST_VSYNC_HI 0x22C
+# define DP_TEST_VSYNC_POLARITY (1 << 7)
+# define DP_TEST_VSYNC_WIDTH_HI_MASK (127 << 0)
+#define DP_TEST_VSYNC_WIDTH_LO 0x22D
+
+#define DP_TEST_H_WIDTH_HI 0x22E
+#define DP_TEST_H_WIDTH_LO 0x22F
+
+#define DP_TEST_V_HEIGHT_HI 0x230
+#define DP_TEST_V_HEIGHT_LO 0x231
+
+#define DP_TEST_MISC0 0x232
+# define DP_TEST_SYNC_CLOCK (1 << 0)
+# define DP_TEST_COLOR_FORMAT_MASK (3 << 1)
+# define DP_TEST_COLOR_FORMAT_SHIFT 1
+# define DP_COLOR_FORMAT_RGB (0 << 1)
+# define DP_COLOR_FORMAT_YCbCr422 (1 << 1)
+# define DP_COLOR_FORMAT_YCbCr444 (2 << 1)
+# define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3)
+# define DP_TEST_YCBCR_COEFFICIENTS (1 << 4)
+# define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4)
+# define DP_YCBCR_COEFFICIENTS_ITU709 (1 << 4)
+# define DP_TEST_BIT_DEPTH_MASK (7 << 5)
+# define DP_TEST_BIT_DEPTH_SHIFT 5
+# define DP_TEST_BIT_DEPTH_6 (0 << 5)
+# define DP_TEST_BIT_DEPTH_8 (1 << 5)
+# define DP_TEST_BIT_DEPTH_10 (2 << 5)
+# define DP_TEST_BIT_DEPTH_12 (3 << 5)
+# define DP_TEST_BIT_DEPTH_16 (4 << 5)
+
+#define DP_TEST_MISC1 0x233
+# define DP_TEST_REFRESH_DENOMINATOR (1 << 0)
+# define DP_TEST_INTERLACED (1 << 1)
+
+#define DP_TEST_REFRESH_RATE_NUMERATOR 0x234
#define DP_TEST_CRC_R_CR 0x240
#define DP_TEST_CRC_G_Y 0x242
@@ -426,6 +485,14 @@
# define DP_TEST_CRC_SUPPORTED (1 << 5)
# define DP_TEST_COUNT_MASK 0xf
+#define DP_TEST_PHY_PATTERN 0x248
+# define DP_TEST_PHY_PATTERN_NONE 0x0
+# define DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING 0x1
+# define DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT 0x2
+# define DP_TEST_PHY_PATTERN_PRBS7 0x3
+# define DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN 0x4
+# define DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN 0x5
+
#define DP_TEST_RESPONSE 0x260
# define DP_TEST_ACK (1 << 0)
# define DP_TEST_NAK (1 << 1)
@@ -436,6 +503,19 @@
#define DP_TEST_SINK 0x270
# define DP_TEST_SINK_START (1 << 0)
+#define DP_TEST_AUDIO_MODE 0x271
+
+#define DP_TEST_AUDIO_PATTERN_TYPE 0x272
+
+#define DP_TEST_AUDIO_PERIOD_CH1 0x273
+#define DP_TEST_AUDIO_PERIOD_CH2 0x274
+#define DP_TEST_AUDIO_PERIOD_CH3 0x275
+#define DP_TEST_AUDIO_PERIOD_CH4 0x276
+#define DP_TEST_AUDIO_PERIOD_CH5 0x277
+#define DP_TEST_AUDIO_PERIOD_CH6 0x278
+#define DP_TEST_AUDIO_PERIOD_CH7 0x279
+#define DP_TEST_AUDIO_PERIOD_CH8 0x27A
+
#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */
# define DP_PAYLOAD_TABLE_UPDATED (1 << 0)
# define DP_PAYLOAD_ACT_HANDLED (1 << 1)
diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h
index 26e948f..c298666 100644
--- a/include/linux/msm-bus.h
+++ b/include/linux/msm-bus.h
@@ -87,8 +87,8 @@
struct device *mas_dev;
u64 cur_act_ib;
u64 cur_act_ab;
- u64 cur_slp_ib;
- u64 cur_slp_ab;
+ u64 cur_dual_ib;
+ u64 cur_dual_ab;
bool active_only;
};
@@ -125,7 +125,7 @@
void msm_bus_scale_unregister(struct msm_bus_client_handle *cl);
int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
int msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl,
- u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab);
+ u64 act_ab, u64 act_ib, u64 dual_ib, u64 dual_ab);
int msm_bus_scale_query_tcs_cmd(struct msm_bus_tcs_usecase *tcs_usecase,
uint32_t cl, unsigned int index);
int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle,
@@ -192,7 +192,7 @@
static inline int
msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
- u64 act_ib, u64 slp_ib, u64 slp_ab)
+ u64 act_ib, u64 dual_ib, u64 dual_ab)
{
return 0;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8e7a431..ec3be7b 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -249,6 +249,9 @@
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
POWER_SUPPLY_PROP_REAL_TYPE,
POWER_SUPPLY_PROP_PR_SWAP,
+ POWER_SUPPLY_PROP_CC_STEP,
+ POWER_SUPPLY_PROP_CC_STEP_SEL,
+ POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/net/cnss_nl.h b/include/net/cnss_nl.h
new file mode 100644
index 0000000..86c2fcc
--- /dev/null
+++ b/include/net/cnss_nl.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS_GENETLINK_H_
+#define _NET_CNSS_GENETLINK_H_
+
+#define CLD80211_MAX_COMMANDS 40
+#define CLD80211_MAX_NL_DATA 4096
+
+/**
+ * enum cld80211_attr - Driver/Application embeds the data in nlmsg with the
+ * help of below attributes
+ *
+ * @CLD80211_ATTR_VENDOR_DATA: Embed all other attributes in this nested
+ * attribute.
+ * @CLD80211_ATTR_DATA: Embed complete data in this attribute
+ *
+ * Any new message in future can be added as another attribute
+ */
+enum cld80211_attr {
+ CLD80211_ATTR_VENDOR_DATA = 1,
+ CLD80211_ATTR_DATA,
+ /* add new attributes above here */
+
+ __CLD80211_ATTR_AFTER_LAST,
+ CLD80211_ATTR_MAX = __CLD80211_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum cld80211_multicast_groups - List of multicast groups supported
+ *
+ * @CLD80211_MCGRP_SVC_MSGS: WLAN service message will be sent to this group.
+ * Ex: Status ind messages
+ * @CLD80211_MCGRP_HOST_LOGS: All logging related messages from driver will be
+ * sent to this multicast group
+ * @CLD80211_MCGRP_FW_LOGS: Firmware logging messages will be sent to this group
+ * @CLD80211_MCGRP_PER_PKT_STATS: Messages related packet stats debugging infra
+ * will be sent to this group
+ * @CLD80211_MCGRP_DIAG_EVENTS: Driver/Firmware status logging diag events will
+ * be sent to this group
+ * @CLD80211_MCGRP_FATAL_EVENTS: Any fatal message generated in driver/firmware
+ * will be sent to this group
+ * @CLD80211_MCGRP_OEM_MSGS: All OEM message will be sent to this group
+ * Ex: LOWI messages
+ */
+enum cld80211_multicast_groups {
+ CLD80211_MCGRP_SVC_MSGS,
+ CLD80211_MCGRP_HOST_LOGS,
+ CLD80211_MCGRP_FW_LOGS,
+ CLD80211_MCGRP_PER_PKT_STATS,
+ CLD80211_MCGRP_DIAG_EVENTS,
+ CLD80211_MCGRP_FATAL_EVENTS,
+ CLD80211_MCGRP_OEM_MSGS,
+};
+
+/**
+ * typedef cld80211_cb - Callback to be called when an nlmsg is received with
+ * the registered cmd_id command from userspace
+ * @data: Payload of the message to be sent to driver
+ * @data_len: Length of the payload
+ * @cb_ctx: callback context to be returned to driver when the callback
+ * is called
+ * @pid: process id of the sender
+ */
+typedef void (*cld80211_cb)(const void *data, int data_len,
+ void *cb_ctx, int pid);
+
+/**
+ * register_cld_cmd_cb() - Allows cld driver to register for commands with
+ * callback
+ * @cmd_id: Command to be registered. Valid range [1, CLD80211_MAX_COMMANDS]
+ * @cb: Callback to be called when an nlmsg is received with cmd_id command
+ * from userspace
+ * @cb_ctx: context provided by driver; Send this as cb_ctx of func()
+ * to driver
+ */
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb cb, void *cb_ctx);
+
+/**
+ * deregister_cld_cmd_cb() - Allows cld driver to de-register the command it
+ * has already registered
+ * @cmd_id: Command to be deregistered.
+ */
+int deregister_cld_cmd_cb(u8 cmd_id);
+
+/**
+ * cld80211_get_genl_family() - Returns current netlink family context
+ */
+struct genl_family *cld80211_get_genl_family(void);
+
+#endif /* _NET_CNSS_GENETLINK_H_ */
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index 75e6ccd..f0b3d02 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -40,6 +40,8 @@
int rpmh_invalidate(struct rpmh_client *rc);
+int rpmh_ctrlr_idle(struct rpmh_client *rc);
+
int rpmh_flush(struct rpmh_client *rc);
int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp);
@@ -82,6 +84,9 @@
static inline int rpmh_invalidate(struct rpmh_client *rc)
{ return -ENODEV; }
+static inline int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{ return -ENODEV; }
+
static inline int rpmh_flush(struct rpmh_client *rc)
{ return -ENODEV; }
diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h
index 0be089b..6d0993a 100644
--- a/include/soc/qcom/system_pm.h
+++ b/include/soc/qcom/system_pm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -17,12 +17,18 @@
int system_sleep_enter(uint64_t sleep_val);
void system_sleep_exit(void);
+
+bool system_sleep_allowed(void);
#else
static inline int system_sleep_enter(uint64_t sleep_val)
{ return -ENODEV; }
static inline void system_sleep_exit(void)
{ }
+
+static inline bool system_sleep_allowed(void)
+{ return false; }
+
#endif /* CONFIG_QTI_SYSTEM_PM */
#endif /* __SOC_QCOM_SYS_PM_H__ */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 5fdbdd8..51c0165 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -132,6 +132,8 @@
#define IPA_FLT_MAC_DST_ADDR_802_3 (1ul << 20)
#define IPA_FLT_MAC_ETHER_TYPE (1ul << 21)
#define IPA_FLT_MAC_DST_ADDR_L2TP (1ul << 22)
+#define IPA_FLT_TCP_SYN (1ul << 23)
+#define IPA_FLT_TCP_SYN_L2TP (1ul << 24)
/**
* maximal number of NAT PDNs in the PDN config table
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 24e93a6..26506d5 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1123,6 +1123,9 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 113)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 114)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 957d642..67cb46c 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -1374,6 +1374,10 @@
{
struct spi_device *spi = to_spi_device(dev);
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+ struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
+
+ debugfs_remove_recursive(dbg_data->dir);
+ dbg_data->dir = NULL;
wcd_spi->m_dev = NULL;
wcd_spi->m_ops = NULL;
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index fe1ce45..2fc26dc 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -128,6 +128,8 @@
#define WCD934X_DIG_CORE_REG_MIN WCD934X_CDC_ANC0_CLK_RESET_CTL
#define WCD934X_DIG_CORE_REG_MAX 0xFFF
+#define WCD934X_CHILD_DEVICES_MAX 6
+
#define WCD934X_MAX_MICBIAS 4
#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone"
@@ -626,6 +628,11 @@
int power_active_ref;
int sidetone_coeff_array[IIR_MAX][BAND_MAX]
[WCD934X_CDC_SIDETONE_IIR_COEFF_MAX];
+
+ struct spi_device *spi;
+ struct platform_device *pdev_child_devices
+ [WCD934X_CHILD_DEVICES_MAX];
+ int child_count;
};
static const struct tavil_reg_mask_val tavil_spkr_default[] = {
@@ -5105,6 +5112,13 @@
int band_idx = 0, coeff_idx = 0;
struct snd_soc_codec *codec = tavil->codec;
+ /*
+ * snd_soc_write call crashes at rmmod if there is no machine
+ * driver and hence no codec pointer available
+ */
+ if (!codec)
+ return;
+
for (band_idx = 0; band_idx < BAND_MAX; band_idx++) {
snd_soc_write(codec,
(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
@@ -9397,6 +9411,9 @@
control = dev_get_drvdata(codec->dev->parent);
devm_kfree(codec->dev, control->rx_chs);
+ /* slimslave deinit in wcd core looks for this value */
+ control->num_rx_port = 0;
+ control->num_tx_port = 0;
control->rx_chs = NULL;
control->tx_chs = NULL;
tavil_cleanup_irqs(tavil);
@@ -9736,6 +9753,7 @@
goto err_dt_parse;
}
+ tavil->spi = spi;
/* Put the reference to SPI master */
put_device(&master->dev);
@@ -9782,6 +9800,7 @@
}
platdata = &tavil->swr.plat_data;
+ tavil->child_count = 0;
for_each_child_of_node(wcd9xxx->dev->of_node, node) {
@@ -9849,6 +9868,10 @@
__func__);
tavil->swr.ctrl_data = swr_ctrl_data;
}
+ if (tavil->child_count < WCD934X_CHILD_DEVICES_MAX)
+ tavil->pdev_child_devices[tavil->child_count++] = pdev;
+ else
+ goto err_mem;
}
return;
@@ -10076,11 +10099,24 @@
static int tavil_remove(struct platform_device *pdev)
{
struct tavil_priv *tavil;
+ int count = 0;
tavil = platform_get_drvdata(pdev);
if (!tavil)
return -EINVAL;
+ /* do dsd deinit before codec->component->regmap becomes freed */
+ if (tavil->dsd_config) {
+ tavil_dsd_deinit(tavil->dsd_config);
+ tavil->dsd_config = NULL;
+ }
+
+ if (tavil->spi)
+ spi_unregister_device(tavil->spi);
+ for (count = 0; count < tavil->child_count &&
+ count < WCD934X_CHILD_DEVICES_MAX; count++)
+ platform_device_unregister(tavil->pdev_child_devices[count]);
+
mutex_destroy(&tavil->micb_lock);
mutex_destroy(&tavil->svs_mutex);
mutex_destroy(&tavil->codec_mutex);
@@ -10091,10 +10127,6 @@
snd_soc_unregister_codec(&pdev->dev);
clk_put(tavil->wcd_ext_clk);
wcd_resmgr_remove(tavil->resmgr);
- if (tavil->dsd_config) {
- tavil_dsd_deinit(tavil->dsd_config);
- tavil->dsd_config = NULL;
- }
devm_kfree(&pdev->dev, tavil);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index c8b01c6..543bc31 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -3632,7 +3632,6 @@
clear_bit(STATUS_PORT_STARTED,
mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
}
- kfree(mi2s_dai_data);
return 0;
}
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 7a5ccd8..2792616 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -7149,6 +7149,7 @@
msm_release_pinctrl(pdev);
snd_soc_unregister_card(card);
+ audio_notifier_deregister("sdm845");
return 0;
}